diff --git a/src/Makefile.am b/src/Makefile.am index fbd5fb679..d8035df18 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -11,7 +11,8 @@ task_SOURCES = API.cpp API.h Att.cpp Att.h Cmd.cpp Cmd.h Color.cpp Color.h \ StringTable.h Subst.cpp Subst.h TDB.cpp TDB.h Table.cpp Table.h \ Task.cpp Task.h Taskmod.cpp Taskmod.h Thread.cpp Thread.h \ Timer.cpp Timer.h Transport.cpp Transport.h TransportSSH.cpp \ - TransportSSH.h Tree.cpp Tree.h command.cpp custom.cpp \ + TransportSSH.h TransportRSYNC.cpp TransportRSYNC.h \ + Tree.cpp Tree.h command.cpp custom.cpp \ dependency.cpp edit.cpp export.cpp i18n.h import.cpp \ interactive.cpp main.cpp main.h recur.cpp report.cpp rules.cpp \ rx.cpp rx.h text.cpp text.h util.cpp util.h diff --git a/src/Transport.cpp b/src/Transport.cpp index 15f28508c..394de1a00 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -31,6 +31,7 @@ #include #include "Transport.h" #include "TransportSSH.h" +#include "TransportRSYNC.h" //////////////////////////////////////////////////////////////////////////////// Transport::Transport (const std::string& host, const std::string& path, const std::string& user="", const std::string& port="") @@ -60,6 +61,7 @@ void Transport::parseUri(std::string uri) { std::string::size_type pos; std::string uripart; + std::string pathDelimiter = "/"; user = ""; port = ""; @@ -67,11 +69,20 @@ void Transport::parseUri(std::string uri) // skip ^.*:// if ((pos = uri.find ("://")) != std::string::npos) { + protocol = uri.substr(0, pos); uri = uri.substr (pos+3); + // standard syntax: protocol://[user@]host.xz[:port]/path/to/undo.data + pathDelimiter = "/"; + } + else + { + protocol = "ssh"; + // scp-like syntax: [user@]host.xz:path/to/undo.data + pathDelimiter = ":"; } // get host part - if ((pos = uri.find ("/")) != std::string::npos) + if ((pos = uri.find (pathDelimiter)) != std::string::npos) { host = uri.substr (0, pos); path = uri.substr (pos+1); @@ -88,6 +99,8 @@ void Transport::parseUri(std::string uri) host = host.substr (pos+1); } + // remark: this find() will never be != npos for scp-like syntax + // because we found pathDelimiter, which is ":", before if ((pos = host.find (":")) != std::string::npos) { port = host.substr (pos+1); @@ -99,7 +112,15 @@ void Transport::parseUri(std::string uri) Transport* Transport::getTransport(const std::string& uri) { if (uri.find("ssh://") == 0) { - return new TransportSSH(uri); + return new TransportSSH(uri); + } + else if (uri.find("rsync://") == 0) { + return new TransportRSYNC(uri); + } + else if ( (uri.find(":") != std::string::npos) + && (uri.find("://") == std::string::npos) ) + { + return new TransportSSH(uri); } return NULL; diff --git a/src/Transport.h b/src/Transport.h index 30a458cdc..fe25eb927 100644 --- a/src/Transport.h +++ b/src/Transport.h @@ -44,6 +44,7 @@ public: protected: std::string executable; + std::string protocol; std::vector arguments; std::string host; diff --git a/src/TransportRSYNC.cpp b/src/TransportRSYNC.cpp new file mode 100644 index 000000000..56b0b988f --- /dev/null +++ b/src/TransportRSYNC.cpp @@ -0,0 +1,130 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2010, Johannes Schlatow. +// All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free Software +// Foundation; either version 2 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the +// +// Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, +// Boston, MA +// 02110-1301 +// USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include "TransportRSYNC.h" + +//////////////////////////////////////////////////////////////////////////////// +TransportRSYNC::TransportRSYNC(const std::string& uri) : Transport(uri) +{ + executable = "rsync"; +} + +//////////////////////////////////////////////////////////////////////////////// +TransportRSYNC::TransportRSYNC( + const std::string& host, + const std::string& path, + const std::string& user, + const std::string& port) : Transport (host,path,user,port) +{ + executable = "rsync"; +} + +//////////////////////////////////////////////////////////////////////////////// +void TransportRSYNC::send(const std::string& source) +{ + if (host == "") { + throw std::string ("Hostname is empty"); + } + + // Is there more than one file to transfer? + // Then path has to end with a '/' + if ( (source.find ("*") != std::string::npos) + || (source.find ("?") != std::string::npos) + || (source.find (" ") != std::string::npos) ) + { + std::string::size_type pos; + + pos = path.find_last_of ("/"); + if (pos != path.length()-1) + { + path = path.substr (0, pos+1); + } + } + + // cmd line is: rsync [--port=PORT] source [user@]host::path + if (port != "") + { + arguments.push_back ("--port=" + port); + } + + arguments.push_back (source); + + if (user != "") + { + arguments.push_back (user + "@" + host + "::" + path); + } + else + { + arguments.push_back (host + "::" + path); + } + + if (execute()) + throw std::string ("Failed to run rsync!"); +} + +//////////////////////////////////////////////////////////////////////////////// +void TransportRSYNC::recv(std::string target) +{ + if (host == "") { + throw std::string ("Hostname is empty"); + } + + // Is there more than one file to transfer? + // Then target has to end with a '/' + if ( (path.find ("*") != std::string::npos) + || (path.find ("?") != std::string::npos) ) + { + std::string::size_type pos; + pos = target.find_last_of ("/"); + if (pos != target.length()-1) + { + target = target.substr( 0, pos+1); + } + } + + // cmd line is: rsync [--port=PORT] [user@]host::path target + if (port != "") + { + arguments.push_back ("--port=" + port); + } + + if (user != "") + { + arguments.push_back (user + "@" + host + "::" + path); + } + else + { + arguments.push_back (host + "::" + path); + } + + arguments.push_back (target); + + if (execute()) + throw std::string ("Failed to run rsync!"); +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/TransportRSYNC.h b/src/TransportRSYNC.h new file mode 100644 index 000000000..9f15678dc --- /dev/null +++ b/src/TransportRSYNC.h @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2010, Johannes Schlatow. +// All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free Software +// Foundation; either version 2 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the +// +// Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, +// Boston, MA +// 02110-1301 +// USA +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_TRANSPORTRSYNC +#define INCLUDED_TRANSPORTRSYNC + +#include +#include + +class TransportRSYNC : public Transport { +public: + TransportRSYNC (const std::string&); + TransportRSYNC (const std::string&, const std::string&, const std::string&, const std::string&); + + virtual void send (const std::string&); + virtual void recv (std::string); + +}; + +#endif + diff --git a/src/tests/Makefile b/src/tests/Makefile index 571bbb7fa..9289ccd55 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -14,7 +14,7 @@ OBJECTS = ../t-TDB.o ../t-Task.o ../t-text.o ../t-Date.o ../t-Table.o \ ../t-Permission.o ../t-Path.o ../t-File.o ../t-Directory.o \ ../t-Hooks.o ../t-API.o ../t-rx.o ../t-Taskmod.o ../t-dependency.o \ ../t-Transport.o ../t-TransportSSH.o ../t-Sensor.o ../t-Thread.o \ - ../t-Lisp.o ../t-Rectangle.o ../t-Tree.o + ../t-Lisp.o ../t-Rectangle.o ../t-Tree.o ../t-TransportRSYNC.o all: $(PROJECT) diff --git a/src/tests/transport.t.cpp b/src/tests/transport.t.cpp index 8f24e95b3..3a7853f88 100644 --- a/src/tests/transport.t.cpp +++ b/src/tests/transport.t.cpp @@ -42,6 +42,7 @@ class TransportTest : public Transport std::string getPath() { return path; }; std::string getUser() { return user; }; std::string getPort() { return port; }; + std::string getProt() { return protocol; }; virtual void recv(std::string) {}; virtual void send(const std::string&) {}; @@ -50,31 +51,35 @@ class TransportTest : public Transport //////////////////////////////////////////////////////////////////////////////// int main (int argc, char** argv) { - UnitTest t (16); + UnitTest t (20); TransportTest tport1 ("asfd://user@host/folder/"); t.is (tport1.getUser (), "user", "Transport::parseUri() : asfd://user@host/folder/"); t.is (tport1.getHost (), "host", "Transport::parseUri() : asfd://user@host/folder/"); t.is (tport1.getPort (), "", "Transport::parseUri() : asfd://user@host/folder/"); t.is (tport1.getPath (), "folder/", "Transport::parseUri() : asfd://user@host/folder/"); + t.is (tport1.getProt (), "asfd", "Transport::parseUri() : asfd://user@host/folder/"); - TransportTest tport2 ("user@host:22/folder/file.test"); + TransportTest tport2 ("user@host:folder/file.test"); t.is (tport2.getUser (), "user", "Transport::parseUri() : user@host:22/folder/file.test"); t.is (tport2.getHost (), "host", "Transport::parseUri() : user@host:22/folder/file.test"); - t.is (tport2.getPort (), "22", "Transport::parseUri() : user@host:22/folder/file.test"); + t.is (tport2.getPort (), "", "Transport::parseUri() : user@host:22/folder/file.test"); t.is (tport2.getPath (), "folder/file.test", "Transport::parseUri() : user@host:22/folder/file.test"); + t.is (tport2.getProt (), "ssh", "Transport::parseUri() : user@host:22/folder/file.test"); - TransportTest tport3 ("hostname.abc.de/file.test"); + TransportTest tport3 ("rsync://hostname.abc.de:1234/file.test"); t.is (tport3.getUser (), "", "Transport::parseUri() : hostname.abc.de/file.test"); t.is (tport3.getHost (), "hostname.abc.de", "Transport::parseUri() : hostname.abc.de/file.test"); - t.is (tport3.getPort (), "", "Transport::parseUri() : hostname.abc.de/file.test"); + t.is (tport3.getPort (), "1234", "Transport::parseUri() : hostname.abc.de/file.test"); t.is (tport3.getPath (), "file.test", "Transport::parseUri() : hostname.abc.de/file.test"); + t.is (tport3.getProt (), "rsync", "Transport::parseUri() : hostname.abc.de/file.test"); - TransportTest tport4 ("hostname/"); + TransportTest tport4 ("hostname:"); t.is (tport4.getUser (), "", "Transport::parseUri() : hostname/"); t.is (tport4.getHost (), "hostname", "Transport::parseUri() : hostname/"); t.is (tport4.getPort (), "", "Transport::parseUri() : hostname/"); t.is (tport4.getPath (), "", "Transport::parseUri() : hostname/"); + t.is (tport4.getProt (), "ssh", "Transport::parseUri() : hostname/"); return 0; }