From 042d7b40de8f5bf7b107751cdc273de8a54e31d8 Mon Sep 17 00:00:00 2001 From: Johannes Schlatow Date: Wed, 6 Oct 2010 16:11:32 +0200 Subject: [PATCH] Feature #462: url support - added uri class for proper uri and path handling --- src/Makefile.am | 2 +- src/Transport.cpp | 86 ++------------ src/Transport.h | 13 +-- src/TransportCurl.cpp | 38 ++---- src/TransportCurl.h | 3 +- src/TransportRSYNC.cpp | 46 +++----- src/TransportRSYNC.h | 3 +- src/TransportSSH.cpp | 46 +++----- src/TransportSSH.h | 3 +- src/Uri.cpp | 235 ++++++++++++++++++++++++++++++++++++++ src/Uri.h | 68 +++++++++++ src/command.cpp | 99 +++++----------- src/import.cpp | 5 +- src/tests/Makefile | 10 +- src/tests/merge.t | 10 +- src/tests/transport.t.cpp | 87 -------------- src/tests/uri.t.cpp | 94 +++++++++++++++ 17 files changed, 505 insertions(+), 343 deletions(-) create mode 100644 src/Uri.cpp create mode 100644 src/Uri.h delete mode 100644 src/tests/transport.t.cpp create mode 100644 src/tests/uri.t.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 5de0dce94..6cf22affe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,7 @@ task_SOURCES = API.cpp API.h Att.cpp Att.h Cmd.cpp Cmd.h Color.cpp Color.h \ TransportCurl.cpp TransportCurl.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 + rx.cpp rx.h text.cpp text.h util.cpp util.h Uri.cpp Uri.h task_CPPFLAGS=$(LUA_CFLAGS) task_LDFLAGS=$(LUA_LFLAGS) diff --git a/src/Transport.cpp b/src/Transport.cpp index 46b4dd09f..803a04eb6 100644 --- a/src/Transport.cpp +++ b/src/Transport.cpp @@ -35,21 +35,10 @@ #include "TransportCurl.h" //////////////////////////////////////////////////////////////////////////////// -Transport::Transport (const std::string& host, const std::string& path, const std::string& user="", const std::string& port="") +Transport::Transport (const Uri& uri) { executable = ""; - this->host = host; - this->path = path; - this->user = user; - this->port = port; -} - -//////////////////////////////////////////////////////////////////////////////// -Transport::Transport (const std::string& uri) -{ - executable = ""; - - parseUri(uri); + this->uri = uri; } //////////////////////////////////////////////////////////////////////////////// @@ -58,79 +47,22 @@ Transport::~Transport () } //////////////////////////////////////////////////////////////////////////////// -void Transport::parseUri(std::string uri) +Transport* Transport::getTransport(const Uri& uri) { - std::string::size_type pos; - std::string uripart; - std::string pathDelimiter = "/"; - - user = ""; - port = ""; - - // 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 (pathDelimiter)) != std::string::npos) - { - host = uri.substr (0, pos); - path = uri.substr (pos+1); - } - else - { - throw std::string ("Could not parse \""+uri+"\""); - } - - // parse host - if ((pos = host.find ("@")) != std::string::npos) - { - user = host.substr (0, pos); - 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); - host = host.substr (0,pos); - } -} - -//////////////////////////////////////////////////////////////////////////////// -Transport* Transport::getTransport(const std::string& uri) -{ - if (uri.find("ssh://") == 0) + if (uri.protocol == "ssh") { return new TransportSSH(uri); } - else if (uri.find("rsync://") == 0) + else if (uri.protocol == "rsync") { return new TransportRSYNC(uri); } - else if ( (uri.find("http://") == 0) - || (uri.find("https://") == 0) - || (uri.find("ftp://") == 0) ) + else if ( (uri.protocol == "http") + || (uri.protocol == "https") + || (uri.protocol == "ftp") ) { return new TransportCurl(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 a52b202fd..117b30ff7 100644 --- a/src/Transport.h +++ b/src/Transport.h @@ -29,28 +29,23 @@ #include #include +#include "Uri.h" class Transport { public: - Transport (const std::string&, const std::string&, const std::string&, const std::string&); - Transport (const std::string&); + Transport (const Uri&); ~Transport (); - static Transport* getTransport(const std::string&); + static Transport* getTransport(const Uri&); - void parseUri (std::string); virtual void send (const std::string&) = 0; virtual void recv (std::string) = 0; protected: std::string executable; - std::string protocol; std::vector arguments; - std::string host; - std::string path; - std::string port; - std::string user; + Uri uri; int execute(); }; diff --git a/src/TransportCurl.cpp b/src/TransportCurl.cpp index a17e6a4c9..110418dd0 100644 --- a/src/TransportCurl.cpp +++ b/src/TransportCurl.cpp @@ -28,31 +28,15 @@ #include "TransportCurl.h" //////////////////////////////////////////////////////////////////////////////// -TransportCurl::TransportCurl(const std::string& uri) : Transport(uri) +TransportCurl::TransportCurl(const Uri& uri) : Transport(uri) { executable = "curl"; - - if (protocol == "") - protocol = "http"; -} - -//////////////////////////////////////////////////////////////////////////////// -TransportCurl::TransportCurl( - const std::string& host, - const std::string& path, - const std::string& user, - const std::string& port) : Transport (host,path,user,port) -{ - executable = "curl"; - - if (protocol == "") - protocol = "http"; } //////////////////////////////////////////////////////////////////////////////// void TransportCurl::send(const std::string& source) { - if (host == "") { + if (uri.host == "") { throw std::string ("Hostname is empty"); } @@ -67,13 +51,13 @@ void TransportCurl::send(const std::string& source) arguments.push_back ("-T"); arguments.push_back (source); - if (port != "") + if (uri.port != "") { - arguments.push_back (protocol + "://" + host + ":" + port + "/" + path); + arguments.push_back (uri.protocol + "://" + uri.host + ":" + uri.port + "/" + uri.path); } else { - arguments.push_back (protocol + "://" + host + "/" + path); + arguments.push_back (uri.protocol + "://" + uri.host + "/" + uri.path); } if (execute()) @@ -83,25 +67,25 @@ void TransportCurl::send(const std::string& source) //////////////////////////////////////////////////////////////////////////////// void TransportCurl::recv(std::string target) { - if (host == "") { + if (uri.host == "") { throw std::string ("Hostname is empty"); } // Wildcards arent supported - if ( (path.find ("*") != std::string::npos) - || (path.find ("?") != std::string::npos) ) + if ( (uri.path.find ("*") != std::string::npos) + || (uri.path.find ("?") != std::string::npos) ) { throw std::string ("Failed to use curl with wildcards!"); } // cmd line is: curl protocol://host:port/path/to/source/file -o path/to/target/file - if (port != "") + if (uri.port != "") { - arguments.push_back (protocol + "://" + host + ":" + port + "/" + path); + arguments.push_back (uri.protocol + "://" + uri.host + ":" + uri.port + "/" + uri.path); } else { - arguments.push_back (protocol + "://" + host + "/" + path); + arguments.push_back (uri.protocol + "://" + uri.host + "/" + uri.path); } arguments.push_back ("-o"); diff --git a/src/TransportCurl.h b/src/TransportCurl.h index 2bb38f0e1..79bada02c 100644 --- a/src/TransportCurl.h +++ b/src/TransportCurl.h @@ -32,8 +32,7 @@ class TransportCurl : public Transport { public: - TransportCurl (const std::string&); - TransportCurl (const std::string&, const std::string&, const std::string&, const std::string&); + TransportCurl (const Uri&); virtual void send (const std::string&); virtual void recv (std::string); diff --git a/src/TransportRSYNC.cpp b/src/TransportRSYNC.cpp index 56b0b988f..1ffa19c9e 100644 --- a/src/TransportRSYNC.cpp +++ b/src/TransportRSYNC.cpp @@ -28,17 +28,7 @@ #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) +TransportRSYNC::TransportRSYNC(const Uri& uri) : Transport(uri) { executable = "rsync"; } @@ -46,7 +36,7 @@ TransportRSYNC::TransportRSYNC( //////////////////////////////////////////////////////////////////////////////// void TransportRSYNC::send(const std::string& source) { - if (host == "") { + if (uri.host == "") { throw std::string ("Hostname is empty"); } @@ -58,28 +48,28 @@ void TransportRSYNC::send(const std::string& source) { std::string::size_type pos; - pos = path.find_last_of ("/"); - if (pos != path.length()-1) + pos = uri.path.find_last_of ("/"); + if (pos != uri.path.length()-1) { - path = path.substr (0, pos+1); + uri.path = uri.path.substr (0, pos+1); } } // cmd line is: rsync [--port=PORT] source [user@]host::path - if (port != "") + if (uri.port != "") { - arguments.push_back ("--port=" + port); + arguments.push_back ("--port=" + uri.port); } arguments.push_back (source); - if (user != "") + if (uri.user != "") { - arguments.push_back (user + "@" + host + "::" + path); + arguments.push_back (uri.user + "@" + uri.host + "::" + uri.path); } else { - arguments.push_back (host + "::" + path); + arguments.push_back (uri.host + "::" + uri.path); } if (execute()) @@ -89,14 +79,14 @@ void TransportRSYNC::send(const std::string& source) //////////////////////////////////////////////////////////////////////////////// void TransportRSYNC::recv(std::string target) { - if (host == "") { + if (uri.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) ) + if ( (uri.path.find ("*") != std::string::npos) + || (uri.path.find ("?") != std::string::npos) ) { std::string::size_type pos; pos = target.find_last_of ("/"); @@ -107,18 +97,18 @@ void TransportRSYNC::recv(std::string target) } // cmd line is: rsync [--port=PORT] [user@]host::path target - if (port != "") + if (uri.port != "") { - arguments.push_back ("--port=" + port); + arguments.push_back ("--port=" + uri.port); } - if (user != "") + if (uri.user != "") { - arguments.push_back (user + "@" + host + "::" + path); + arguments.push_back (uri.user + "@" + uri.host + "::" + uri.path); } else { - arguments.push_back (host + "::" + path); + arguments.push_back (uri.host + "::" + uri.path); } arguments.push_back (target); diff --git a/src/TransportRSYNC.h b/src/TransportRSYNC.h index 9f15678dc..5cd66dc0b 100644 --- a/src/TransportRSYNC.h +++ b/src/TransportRSYNC.h @@ -32,8 +32,7 @@ class TransportRSYNC : public Transport { public: - TransportRSYNC (const std::string&); - TransportRSYNC (const std::string&, const std::string&, const std::string&, const std::string&); + TransportRSYNC (const Uri&); virtual void send (const std::string&); virtual void recv (std::string); diff --git a/src/TransportSSH.cpp b/src/TransportSSH.cpp index b863d3a3a..8b0e0dfe6 100644 --- a/src/TransportSSH.cpp +++ b/src/TransportSSH.cpp @@ -28,17 +28,7 @@ #include "TransportSSH.h" //////////////////////////////////////////////////////////////////////////////// -TransportSSH::TransportSSH(const std::string& uri) : Transport(uri) -{ - executable = "scp"; -} - -//////////////////////////////////////////////////////////////////////////////// -TransportSSH::TransportSSH( - const std::string& host, - const std::string& path, - const std::string& user, - const std::string& port) : Transport (host,path,user,port) +TransportSSH::TransportSSH(const Uri& uri) : Transport(uri) { executable = "scp"; } @@ -46,7 +36,7 @@ TransportSSH::TransportSSH( //////////////////////////////////////////////////////////////////////////////// void TransportSSH::send(const std::string& source) { - if (host == "") { + if (uri.host == "") { throw std::string ("Hostname is empty"); } @@ -58,29 +48,29 @@ void TransportSSH::send(const std::string& source) { std::string::size_type pos; - pos = path.find_last_of ("/"); - if (pos != path.length()-1) + pos = uri.path.find_last_of ("/"); + if (pos != uri.path.length()-1) { - path = path.substr (0, pos+1); + uri.path = uri.path.substr (0, pos+1); } } // cmd line is: scp [-p port] [user@]host:path - if (port != "") + if (uri.port != "") { arguments.push_back ("-P"); - arguments.push_back (port); + arguments.push_back (uri.port); } arguments.push_back (source); - if (user != "") + if (uri.user != "") { - arguments.push_back (user + "@" + host + ":" + path); + arguments.push_back (uri.user + "@" + uri.host + ":" + uri.path); } else { - arguments.push_back (host + ":" + path); + arguments.push_back (uri.host + ":" + uri.path); } if (execute()) @@ -90,14 +80,14 @@ void TransportSSH::send(const std::string& source) //////////////////////////////////////////////////////////////////////////////// void TransportSSH::recv(std::string target) { - if (host == "") { + if (uri.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) ) + if ( (uri.path.find ("*") != std::string::npos) + || (uri.path.find ("?") != std::string::npos) ) { std::string::size_type pos; pos = target.find_last_of ("/"); @@ -108,19 +98,19 @@ void TransportSSH::recv(std::string target) } // cmd line is: scp [-p port] [user@]host:path - if (port != "") + if (uri.port != "") { arguments.push_back ("-P"); - arguments.push_back (port); + arguments.push_back (uri.port); } - if (user != "") + if (uri.user != "") { - arguments.push_back (user + "@" + host + ":" + path); + arguments.push_back (uri.user + "@" + uri.host + ":" + uri.path); } else { - arguments.push_back (host + ":" + path); + arguments.push_back (uri.host + ":" + uri.path); } arguments.push_back (target); diff --git a/src/TransportSSH.h b/src/TransportSSH.h index 11b6f17dc..34655b881 100644 --- a/src/TransportSSH.h +++ b/src/TransportSSH.h @@ -32,8 +32,7 @@ class TransportSSH : public Transport { public: - TransportSSH (const std::string&); - TransportSSH (const std::string&, const std::string&, const std::string&, const std::string&); + TransportSSH (const Uri&); virtual void send (const std::string&); virtual void recv (std::string); diff --git a/src/Uri.cpp b/src/Uri.cpp new file mode 100644 index 000000000..544b80522 --- /dev/null +++ b/src/Uri.cpp @@ -0,0 +1,235 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "Context.h" +#include "Uri.h" + +extern Context context; + +//////////////////////////////////////////////////////////////////////////////// +Uri::Uri () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Uri::Uri (const Uri& other) +{ + if (this != &other) + { + data = other.data; + host = other.host; + path = other.path; + user = other.user; + port = other.port; + protocol = other.protocol; + } +} + +//////////////////////////////////////////////////////////////////////////////// +Uri::Uri (const std::string& in, const std::string& configPrefix) +{ + data = in; + if (configPrefix != "") + expand(configPrefix); +} + +//////////////////////////////////////////////////////////////////////////////// +Uri::~Uri () +{ +} + +//////////////////////////////////////////////////////////////////////////////// +Uri& Uri::operator= (const Uri& other) +{ + if (this != &other) + { + this->data = other.data; + this->host = other.host; + this->path = other.path; + this->user = other.user; + this->port = other.port; + this->protocol = other.protocol; + } + + return *this; +} + +//////////////////////////////////////////////////////////////////////////////// +Uri::operator std::string () const +{ + return data; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string Uri::name () const +{ + if (path.length ()) + { + std::string::size_type slash = path.rfind ('/'); + if (slash != std::string::npos) + return path.substr (slash + 1, std::string::npos); + } + + return path; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string Uri::parent () const +{ + if (path.length ()) + { + std::string::size_type slash = path.rfind ('/'); + if (slash != std::string::npos) + return path.substr (0, slash); + } + + return ""; +} + +//////////////////////////////////////////////////////////////////////////////// +std::string Uri::extension () const +{ + if (path.length ()) + { + std::string::size_type dot = path.rfind ('.'); + if (dot != std::string::npos) + return path.substr (dot + 1, std::string::npos); + } + + return ""; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Uri::is_directory () const +{ + return (path == ".") + || (path == "") + || (path[path.length()-1] == '/'); +} + +//////////////////////////////////////////////////////////////////////////////// +bool Uri::is_local () const +{ + return ( (data.find("://") == std::string::npos) + && (data.find(":") == std::string::npos) ); +} + +//////////////////////////////////////////////////////////////////////////////// +bool Uri::append (const std::string& path) +{ + if (is_directory ()) + { + this->path += path; + return true; + } + else + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +bool Uri::expand (const std::string& configPrefix ) +{ + std::string tmp; + if (data.length ()) + { + // try to replace argument with uri from config + tmp = context.config.get (configPrefix + "." + data + ".uri"); + } + else + { + // get default target from config + tmp = context.config.get (configPrefix + ".default.uri"); + } + + if (tmp != "") + { + data = tmp; + return true; + } + + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +void Uri::parse () +{ + if (is_local ()) + { + path = data; + return; + } + + std::string::size_type pos; + std::string uripart; + std::string pathDelimiter = "/"; + + user = ""; + port = ""; + + // skip ^.*:// + if ((pos = data.find ("://")) != std::string::npos) + { + protocol = data.substr(0, pos); + data = data.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 = data.find (pathDelimiter)) != std::string::npos) + { + host = data.substr (0, pos); + path = data.substr (pos+1); + } + else + { + throw std::string ("Could not parse \""+data+"\""); + } + + // parse host + if ((pos = host.find ("@")) != std::string::npos) + { + user = host.substr (0, pos); + 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); + host = host.substr (0,pos); + } +} + +//////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/src/Uri.h b/src/Uri.h new file mode 100644 index 000000000..aa8357330 --- /dev/null +++ b/src/Uri.h @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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_URI +#define INCLUDED_URI + +#include +#include + +// supports the following syntaxes: +// protocol://[user@]host.tld[:port]/path +// [user@]host:path +// path/to/local/file.ext +// alias (e.g. merge.alias.uri) +class Uri +{ +public: + Uri (); + Uri (const Uri&); + Uri (const std::string&, const std::string& configPrefix=""); + virtual ~Uri (); + + Uri& operator= (const Uri&); + operator std::string () const; + + std::string name () const; + std::string parent () const; + std::string extension () const; + bool is_directory () const; + bool is_local () const; + bool append (const std::string&); + bool expand (const std::string&); + void parse (); + +public: + std::string data; + std::string path; + std::string host; + std::string port; + std::string user; + std::string protocol; +}; + +#endif +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/command.cpp b/src/command.cpp index 390fe3978..ab8bf27cc 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -588,42 +588,26 @@ void handleMerge (std::string& outs) std::string sAutopush = context.config.get ("merge.autopush"); bool bAutopush = context.config.getBoolean("merge.autopush"); - - if (file.length () == 0) + + Uri uri (file, "merge"); + uri.parse(); + + if (sAutopush == "ask") { - // get default target from config - file = context.config.get ("merge.default.uri"); - - if (sAutopush == "ask") - pushfile = context.config.get ("push.default.uri"); - } - else - { - // replace argument with uri from config - std::string tmp = context.config.get ("merge." + file + ".uri"); - - if (sAutopush == "ask") - pushfile = context.config.get ("push." + file + ".uri"); - - if (tmp != "") - file = tmp; + // expand uri + Uri push (file, "push"); + pushfile = push.data; } - if (file.length () > 0) + if (uri.data.length ()) { Directory location (context.config.get ("data.location")); - - // add undo.data to path if necessary - if (file.find ("undo.data") == std::string::npos) - { - if (file[file.length()-1] != '/') - file += "/"; - - file += "undo.data"; - } + + // be sure that uri points to a file + uri.append("undo.data"); Transport* transport; - if ((transport = Transport::getTransport (file)) != NULL ) + if ((transport = Transport::getTransport (uri)) != NULL ) { tmpfile = location.data + "/undo_remote.data"; transport->recv (tmpfile); @@ -631,6 +615,8 @@ void handleMerge (std::string& outs) file = tmpfile; } + else + file = uri.path; context.tdb.lock (context.config.getBoolean ("locking")); context.tdb.merge (file); @@ -641,7 +627,7 @@ void handleMerge (std::string& outs) if (tmpfile != "") { remove (tmpfile.c_str()); - } + } if ( ((sAutopush == "ask") && (confirm ("Do you want to push the changes to \'" + pushfile + "\'?")) ) || (bAutopush) ) @@ -662,28 +648,18 @@ void handlePush (std::string& outs) if (context.hooks.trigger ("pre-push-command")) { std::string file = trim (context.task.get ("description")); + + Uri uri (file, "push"); + uri.parse (); - if (file.length () == 0) - { - // get default target from config - file = context.config.get ("push.default.uri"); - } - else - { - // try to replace argument with uri from config - std::string tmp = context.config.get ("push." + file + ".uri"); - - if (tmp != "") - file = tmp; - } - - if (file.length () > 0) + if (uri.data.length ()) { Directory location (context.config.get ("data.location")); Transport* transport; - if ((transport = Transport::getTransport (file)) != NULL ) + if ((transport = Transport::getTransport (uri)) != NULL ) { + // TODO specify data files transport->send (location.data + "/*.data"); delete transport; } @@ -709,42 +685,25 @@ void handlePull (std::string& outs) if (context.hooks.trigger ("pre-pull-command")) { std::string file = trim (context.task.get ("description")); + + Uri uri (file, "pull"); + uri.parse (); - if (file.length () == 0) - { - // get default target from config - file = context.config.get ("pull.default.uri"); - } - else - { - // replace argument with uri from config - std::string tmp = context.config.get ("pull." + file + ".uri"); - - if (tmp != "") - file = tmp; - } - - if (file.length () > 0) + if (uri.data.length ()) { Directory location (context.config.get ("data.location")); - // add *.data to path if necessary - if (file.find ("*.data") == std::string::npos) - { - if (file[file.length()-1] != '/') - file += "/"; - - file += "*.data"; - } + uri.append ("*.data"); Transport* transport; - if ((transport = Transport::getTransport (file)) != NULL ) + if ((transport = Transport::getTransport (uri)) != NULL ) { transport->recv (location.data + "/"); delete transport; } else { + // TODO copy files throw std::string ("Pull failed"); } diff --git a/src/import.cpp b/src/import.cpp index aa9d0df41..113f6d1a0 100644 --- a/src/import.cpp +++ b/src/import.cpp @@ -1267,8 +1267,11 @@ int handleImport (std::string &outs) #if FEATURE_URL > 0 std::string tmpfile = ""; + Uri uri (file); + uri.parse (); + Transport* transport; - if ((transport = Transport::getTransport (file)) != NULL ) + if ((transport = Transport::getTransport (uri)) != NULL ) { std::string location (context.config.get ("data.location")); tmpfile = location + "/import.data"; diff --git a/src/tests/Makefile b/src/tests/Makefile index d3970c63c..a9804c1c7 100644 --- a/src/tests/Makefile +++ b/src/tests/Makefile @@ -1,7 +1,7 @@ PROJECT = t.t tdb.t date.t duration.t t.benchmark.t text.t autocomplete.t \ config.t seq.t att.t stringtable.t record.t nibbler.t subst.t filt.t \ cmd.t util.t color.t list.t path.t file.t directory.t grid.t rx.t \ - taskmod.t sensor.t rectangle.t tree.t tree2.t lisp.t transport.t + taskmod.t sensor.t rectangle.t tree.t tree2.t lisp.t uri.t CFLAGS = -I. -I.. -I../.. -Wall -pedantic -ggdb3 -fno-rtti LFLAGS = -L/usr/local/lib -lpthread -lncurses -llua OBJECTS = ../t-TDB.o ../t-Task.o ../t-text.o ../t-Date.o ../t-Table.o \ @@ -15,7 +15,7 @@ OBJECTS = ../t-TDB.o ../t-Task.o ../t-text.o ../t-Date.o ../t-Table.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-TransportRSYNC.o \ - ../t-TransportCurl.o + ../t-TransportCurl.o ../t-Uri.o all: $(PROJECT) @@ -106,9 +106,6 @@ rx.t: rx.t.o $(OBJECTS) test.o taskmod.t: taskmod.t.o $(OBJECTS) test.o g++ taskmod.t.o $(OBJECTS) test.o $(LFLAGS) -o taskmod.t -transport.t: transport.t.o $(OBJECTS) test.o - g++ transport.t.o $(OBJECTS) test.o $(LFLAGS) -o transport.t - lisp.t: lisp.t.o $(OBJECTS) test.o g++ lisp.t.o $(OBJECTS) test.o $(LFLAGS) -o lisp.t @@ -124,3 +121,6 @@ tree.t: tree.t.o $(OBJECTS) test.o tree2.t: tree2.t.o $(OBJECTS) test.o g++ tree2.t.o $(OBJECTS) test.o $(LFLAGS) -o tree2.t +uri.t: uri.t.o $(OBJECTS) test.o + g++ uri.t.o $(OBJECTS) test.o $(LFLAGS) -o uri.t + diff --git a/src/tests/merge.t b/src/tests/merge.t index 3150c69fe..ea0dad0a3 100755 --- a/src/tests/merge.t +++ b/src/tests/merge.t @@ -28,7 +28,7 @@ use strict; use warnings; -use Test::More tests => 42; +use Test::More tests => 43; use File::Copy; use constant false => 0; @@ -137,8 +137,7 @@ qx{../task rc:remote.rc 4 +gym}; # right_newer # merge remote into local copy("local/undo.data", "local/undo.save") or fail("copy local/undo.data to local/undo.save"); -my $output_l = qx{../task rc:local.rc merge remote/undo.data}; -rename("local/undo.save", "local/undo.data") or fail("rename local/undo.save in local/undo.data"); +my $output_l = qx{../task rc:local.rc merge remote/}; #check output like ($output_l, qr/Running redo/, "local-merge finished"); @@ -146,7 +145,7 @@ unlike ($output_l, qr/Missing/, "local-merge: no missing entry"); unlike ($output_l, qr/Not adding duplicate/, "local-merge: no duplicates"); # merge local into remote -my $output_r = qx{../task rc:remote.rc merge local/undo.data}; +my $output_r = qx{../task rc:remote.rc merge local/undo.save}; # check output like ($output_r, qr/Running redo/, "remote-merge finished"); @@ -240,6 +239,9 @@ ok (!-r 'local/completed.data', 'Removed local/completed.data'); unlink 'local/undo.data'; ok (!-r 'local/undo.data', 'Removed local/undo.data'); +unlink 'local/undo.save'; +ok (!-r 'local/undo.save', 'Removed local/undo.save'); + unlink 'local.rc'; ok (!-r 'local.rc', 'Removed local.rc'); diff --git a/src/tests/transport.t.cpp b/src/tests/transport.t.cpp deleted file mode 100644 index 3a7853f88..000000000 --- a/src/tests/transport.t.cpp +++ /dev/null @@ -1,87 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// taskwarrior - a command line task list manager. -// -// Copyright 2006 - 2010, Paul Beckingham. -// 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 -#include -#include -//#include -#include -#include - -Context context; - -class TransportTest : public Transport -{ - public: - TransportTest (const std::string& uri) : Transport (uri) {}; - - std::string getHost() { return host; }; - 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&) {}; -}; - -//////////////////////////////////////////////////////////////////////////////// -int main (int argc, char** argv) -{ - 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: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 (), "", "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 ("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 (), "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:"); - 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; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/tests/uri.t.cpp b/src/tests/uri.t.cpp new file mode 100644 index 000000000..1d8913a1a --- /dev/null +++ b/src/tests/uri.t.cpp @@ -0,0 +1,94 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +#include +#include +#include +#include + +Context context; + +//////////////////////////////////////////////////////////////////////////////// +int main (int argc, char** argv) +{ + UnitTest t (30); + + Uri uri1 ("asfd://user@host/folder/"); + uri1.parse (); + t.is (uri1.user, "user", "Uri::parse() : asdf://user@host/folder/"); + t.is (uri1.host, "host", "Uri::parse() : asdf://user@host/folder/"); + t.is (uri1.port, "", "Uri::parse() : asdf://user@host/folder/"); + t.is (uri1.path, "folder/", "Uri::parse() : asdf://user@host/folder/"); + t.is (uri1.protocol, "asfd", "Uri::parse() : asdf://user@host/folder/"); + t.ok (uri1.append ("file.test"), "Uri::append() to path"); + t.is (uri1.path, "folder/file.test", "Uri::append() ok"); + + Uri uri2 ("user@host:folder/file.test"); + uri2.parse (); + t.is (uri2.user, "user", "Uri::parse() : user@host:folder/file.test"); + t.is (uri2.host, "host", "Uri::parse() : user@host:folder/file.test"); + t.is (uri2.port, "", "Uri::parse() : user@host/folder/file.test"); + t.is (uri2.path, "folder/file.test", "Uri::parse() : user@host/folder/file.test"); + t.is (uri2.protocol, "ssh", "Uri::parse() : user@host/folder/file.test"); + t.notok (uri2.append ("test.dat"), "Uri::append() to file"); + + Uri uri3 ("rsync://hostname.abc.de:1234//abs/path"); + uri3.parse (); + t.is (uri3.user, "", "Uri::parse() : rsync://hostname.abc.de:1234//abs/path"); + t.is (uri3.host, "hostname.abc.de", "Uri::parse() : rsync://hostname.abc.de:1234//abs/path"); + t.is (uri3.port, "1234", "Uri::parse() : rsync://hostname.abc.de:1234//abs/path"); + t.is (uri3.path, "/abs/path", "Uri::parse() : rsync://hostname.abc.de:1234//abs/path"); + t.is (uri3.protocol, "rsync", "Uri::parse() : rsync://hostname.abc.de:1234//abs/path"); + + Uri uri4 ("hostname:"); + uri4.parse (); + t.is (uri4.user, "", "Uri::parse() : hostname:"); + t.is (uri4.host, "hostname", "Uri::parse() : hostname:"); + t.is (uri4.port, "", "Uri::parse() : hostname:"); + t.is (uri4.path, "", "Uri::parse() : hostname:"); + t.is (uri4.protocol, "ssh", "Uri::parse() : hostname:"); + t.notok (uri4.is_local (), "Uri::is_local() : hostname:"); + t.ok (uri4.append ("file.test"), "Uri::append() : hostname:"); + t.is (uri4.path, "file.test","Uri::append() : ok"); + + context.config.set ("merge.default.uri", "../folder/"); + context.config.set ("push.test.uri", "/home/user/.task/"); + + Uri uri5 ("", "merge"); + t.ok (uri5.is_local (), "Uri::is_local() : ../server/"); + uri5.parse (); + t.is (uri5.path, "../folder/", "Uri::expand() default"); + + Uri uri6 ("test", "push"); + t.ok (uri6.is_local(), "Uri::is_local() : /home/user/.task/"); + uri6.parse (); + t.is (uri6.path, "/home/user/.task/", "Uri::expand() test"); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////////