mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Merge branch '1.9.4' of tasktools.org:task into 1.9.4
Conflicts: ChangeLog
This commit is contained in:
commit
18c770141d
6 changed files with 213 additions and 48 deletions
|
@ -35,12 +35,17 @@
|
||||||
+ Fixed bug #538, where some color legend items were not readable.
|
+ Fixed bug #538, where some color legend items were not readable.
|
||||||
+ Fixed bug #539, where the man page task-color(5) contained a line that
|
+ Fixed bug #539, where the man page task-color(5) contained a line that
|
||||||
began with a ' and was not displayed.
|
began with a ' and was not displayed.
|
||||||
|
+ Fixed bug #540, where user names containing @s could not be parsed
|
||||||
+ Fixed bug #542, which sorted the countdown columns incorrectly (thanks to
|
+ Fixed bug #542, which sorted the countdown columns incorrectly (thanks to
|
||||||
Michelle Crane).
|
Michelle Crane).
|
||||||
+ Fixed bug #555, which caused a segfault when logging a task with a project
|
+ Fixed bug #555, which caused a segfault when logging a task with a project
|
||||||
(thanks to Itay Perl).
|
(thanks to Itay Perl).
|
||||||
|
+ Fixed bug #570, which used unsupported brace expansion with dash (default
|
||||||
|
/bin/sh in Ubuntu)
|
||||||
+ Fixed bug #579, which displayed incorrect counts when using the 'limit:N'
|
+ Fixed bug #579, which displayed incorrect counts when using the 'limit:N'
|
||||||
filter (thanks to Thomas Sattler).
|
filter (thanks to Thomas Sattler).
|
||||||
|
+ Fixed bug #580, where reusing the merge uri for autopush failed when the
|
||||||
|
uri was taken from taskrc.
|
||||||
+ Applied patch to fix bug #581, in which backslashes in annotations and
|
+ Applied patch to fix bug #581, in which backslashes in annotations and
|
||||||
descriptions caused problems (thanks to Itay Perl).
|
descriptions caused problems (thanks to Itay Perl).
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,21 @@ https://host[:port]/path/to/undo.data
|
||||||
ftp://[user@]host[:port]/path/to/undo.data
|
ftp://[user@]host[:port]/path/to/undo.data
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
|
You can use single quotes to encapsulate user names that contain delimiting
|
||||||
|
characters like '@', '/' or ':', e.g.:
|
||||||
|
|
||||||
|
.br
|
||||||
|
.RS
|
||||||
|
ssh://'user@name'@host/
|
||||||
|
.RE
|
||||||
|
|
||||||
|
Remember to escape the quotes on your shell:
|
||||||
|
|
||||||
|
.br
|
||||||
|
.RS
|
||||||
|
$ task push ftp://\'user@name\':host/
|
||||||
|
.RE
|
||||||
|
|
||||||
.SH CONFLICTS
|
.SH CONFLICTS
|
||||||
When modifications on the local and remote machine conflict, for example if
|
When modifications on the local and remote machine conflict, for example if
|
||||||
both machines change the project name of the same task to different values,
|
both machines change the project name of the same task to different values,
|
||||||
|
|
98
src/Uri.cpp
98
src/Uri.cpp
|
@ -198,54 +198,74 @@ void Uri::parse ()
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string::size_type pos;
|
std::string::size_type pos;
|
||||||
std::string uripart;
|
std::string uripart;
|
||||||
std::string pathDelimiter = "/";
|
std::string pathDelimiter = "/";
|
||||||
|
|
||||||
user = "";
|
user = "";
|
||||||
port = "";
|
port = "";
|
||||||
|
|
||||||
// skip ^.*://
|
// skip ^.*://
|
||||||
if ((pos = data.find ("://")) != std::string::npos)
|
if ((pos = data.find ("://")) != std::string::npos)
|
||||||
{
|
{
|
||||||
protocol = data.substr(0, pos);
|
protocol = data.substr(0, pos);
|
||||||
data = data.substr (pos+3);
|
data = data.substr (pos+3);
|
||||||
// standard syntax: protocol://[user@]host.xz[:port]/path/to/undo.data
|
// standard syntax: protocol://[user@]host.xz[:port]/path/to/undo.data
|
||||||
pathDelimiter = "/";
|
pathDelimiter = "/";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
protocol = "ssh";
|
protocol = "ssh";
|
||||||
// scp-like syntax: [user@]host.xz:path/to/undo.data
|
// scp-like syntax: [user@]host.xz:path/to/undo.data
|
||||||
pathDelimiter = ":";
|
pathDelimiter = ":";
|
||||||
}
|
}
|
||||||
|
|
||||||
// get host part
|
// user delimited by single quotes?
|
||||||
if ((pos = data.find (pathDelimiter)) != std::string::npos)
|
if ( data[0] == '\''
|
||||||
{
|
&& (pos = data.find("'", 1)) != std::string::npos )
|
||||||
host = data.substr (0, pos);
|
{
|
||||||
path = data.substr (pos+1);
|
if (data[pos+1] == '@')
|
||||||
}
|
{
|
||||||
else
|
// end of user name
|
||||||
{
|
user = data.substr (1, pos-1);
|
||||||
|
data = data.substr (pos+2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::string ("Could not parse uri '") + data + "', wrong usage of single quotes.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// find user name
|
||||||
|
if ((pos = data.find ("@")) != std::string::npos)
|
||||||
|
{
|
||||||
|
user = data.substr (0, pos);
|
||||||
|
data = data.substr (pos+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get host, port and path
|
||||||
|
if ((pos = data.find (pathDelimiter)) != std::string::npos)
|
||||||
|
{
|
||||||
|
host = data.substr (0, pos);
|
||||||
|
path = data.substr (pos+1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
throw std::string ("The uri '") + data + "' is not in the expected format.";
|
throw std::string ("The uri '") + data + "' is not in the expected format.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse host
|
// port specified?
|
||||||
if ((pos = host.find ("@")) != std::string::npos)
|
// remark: this find() will never be != npos for scp-like syntax
|
||||||
{
|
// because we found pathDelimiter, which is ":", before
|
||||||
user = host.substr (0, pos);
|
if ((pos = host.find (":")) != std::string::npos)
|
||||||
host = host.substr (pos+1);
|
{
|
||||||
}
|
port = host.substr (pos+1);
|
||||||
|
host = host.substr (0,pos);
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed = true;
|
parsed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// vim: et ts=2 sw=2
|
||||||
|
|
|
@ -590,13 +590,6 @@ void handleMerge (std::string& outs)
|
||||||
Uri uri (file, "merge");
|
Uri uri (file, "merge");
|
||||||
uri.parse();
|
uri.parse();
|
||||||
|
|
||||||
if (sAutopush == "ask")
|
|
||||||
{
|
|
||||||
// expand uri
|
|
||||||
Uri push (file, "push");
|
|
||||||
pushfile = push.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uri.data.length ())
|
if (uri.data.length ())
|
||||||
{
|
{
|
||||||
Directory location (context.config.get ("data.location"));
|
Directory location (context.config.get ("data.location"));
|
||||||
|
@ -627,10 +620,11 @@ void handleMerge (std::string& outs)
|
||||||
if (tmpfile != "")
|
if (tmpfile != "")
|
||||||
remove (tmpfile.c_str ());
|
remove (tmpfile.c_str ());
|
||||||
|
|
||||||
if ( ((sAutopush == "ask") && (confirm ("Would you like to push the merged changes to \'" + pushfile + "\'?")) )
|
if ( ((sAutopush == "ask") && (confirm ("Would you like to push the merged changes to \'" + uri.data + "\'?")) )
|
||||||
|| (bAutopush) )
|
|| (bAutopush) )
|
||||||
{
|
{
|
||||||
std::string out;
|
std::string out;
|
||||||
|
context.task.set ("description", uri.data);
|
||||||
handlePush (out);
|
handlePush (out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
108
src/tests/bug.580.t
Executable file
108
src/tests/bug.580.t
Executable file
|
@ -0,0 +1,108 @@
|
||||||
|
#! /usr/bin/perl
|
||||||
|
################################################################################
|
||||||
|
## taskwarrior - a command line task list manager.
|
||||||
|
##
|
||||||
|
## Copyright 2006 - 2010, Paul Beckingham, Federico Hernandez.
|
||||||
|
## 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
|
||||||
|
##
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Test::More tests => 16;
|
||||||
|
use File::Copy;
|
||||||
|
|
||||||
|
use constant false => 0;
|
||||||
|
use constant true => 1;
|
||||||
|
|
||||||
|
# Create data locations
|
||||||
|
mkdir("local", 0755);
|
||||||
|
ok(-e 'local', "Created directory local");
|
||||||
|
mkdir("remote", 0755);
|
||||||
|
ok(-e 'remote', "Created directory remote");
|
||||||
|
|
||||||
|
# Create the rc files.
|
||||||
|
if (open my $fh, '>', 'local.rc')
|
||||||
|
{
|
||||||
|
print $fh "data.location=./local\n",
|
||||||
|
"confirmation=no\n",
|
||||||
|
"merge.default.uri=remote/\n",
|
||||||
|
"merge.autopush=yes\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'local.rc', 'Created local.rc');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (open my $fh, '>', 'remote.rc')
|
||||||
|
{
|
||||||
|
print $fh "data.location=./remote\n",
|
||||||
|
"confirmation=no\n",
|
||||||
|
"merge.autopush=no\n";
|
||||||
|
close $fh;
|
||||||
|
ok (-r 'remote.rc', 'Created remote.rc');
|
||||||
|
}
|
||||||
|
|
||||||
|
# add a remote task
|
||||||
|
qx{../task rc:remote.rc add remote task};
|
||||||
|
|
||||||
|
# add a local task
|
||||||
|
qx(../task rc:local.rc add local task);
|
||||||
|
|
||||||
|
# merge and autopush
|
||||||
|
qx{../task rc:local.rc merge};
|
||||||
|
|
||||||
|
my $output = qx{../task rc:remote.rc ls};
|
||||||
|
like ($output, qr/local task/, "autopush failed");
|
||||||
|
|
||||||
|
# Cleanup.
|
||||||
|
unlink 'local/pending.data';
|
||||||
|
ok (!-r 'local/pending.data', 'Removed local/pending.data');
|
||||||
|
|
||||||
|
unlink 'local/completed.data';
|
||||||
|
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');
|
||||||
|
|
||||||
|
unlink 'remote/pending.data';
|
||||||
|
ok (!-r 'remote/pending.data', 'Removed remote/pending.data');
|
||||||
|
|
||||||
|
unlink 'remote/completed.data';
|
||||||
|
ok (!-r 'remote/completed.data', 'Removed remote/completed.data');
|
||||||
|
|
||||||
|
unlink 'remote/undo.data';
|
||||||
|
ok (!-r 'remote/undo.data', 'Removed remote/undo.data');
|
||||||
|
|
||||||
|
unlink 'remote.rc';
|
||||||
|
ok (!-r 'remote.rc', 'Removed remote.rc');
|
||||||
|
|
||||||
|
rmdir("remote");
|
||||||
|
ok (!-e "remote", "Removed dir remote");
|
||||||
|
rmdir("local");
|
||||||
|
ok (!-e "local", "Removed dir local");
|
||||||
|
|
||||||
|
exit 0;
|
|
@ -35,7 +35,7 @@ Context context;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int main (int argc, char** argv)
|
int main (int argc, char** argv)
|
||||||
{
|
{
|
||||||
UnitTest t (30);
|
UnitTest t (44);
|
||||||
|
|
||||||
Uri uri1 ("asfd://user@host/folder/");
|
Uri uri1 ("asfd://user@host/folder/");
|
||||||
uri1.parse ();
|
uri1.parse ();
|
||||||
|
@ -88,6 +88,29 @@ int main (int argc, char** argv)
|
||||||
uri6.parse ();
|
uri6.parse ();
|
||||||
t.is (uri6.path, "/home/user/.task/", "Uri::expand() test");
|
t.is (uri6.path, "/home/user/.task/", "Uri::expand() test");
|
||||||
|
|
||||||
|
Uri uri7 ("ftp://'user@name'@host:321/path/to/x");
|
||||||
|
uri7.parse ();
|
||||||
|
t.is (uri7.user, "user@name", "Uri::parse() : ftp://'user@name'@host:321/path/to/x");
|
||||||
|
t.is (uri7.host, "host", "Uri::parse() : ftp://'user@name'@host:321/path/to/x");
|
||||||
|
t.is (uri7.port, "321", "Uri::parse() : ftp://'user@name'@host:321/path/to/x");
|
||||||
|
t.is (uri7.path, "path/to/x", "Uri::parse() : ftp://'user@name'@host:321/path/to/x");
|
||||||
|
t.is (uri7.protocol, "ftp", "Uri::parse() : ftp://'user@name'@host:321/path/to/x");
|
||||||
|
|
||||||
|
Uri uri8 ("http://'us/er@n:ame'@host/path/to/x");
|
||||||
|
uri8.parse ();
|
||||||
|
t.is (uri8.user, "us/er@n:ame", "Uri::parse() : http://'us/er@n:ame'@host/path/to/x");
|
||||||
|
t.is (uri8.host, "host", "Uri::parse() : http://'us/er@n:ame'@host/path/to/x");
|
||||||
|
t.is (uri8.port, "", "Uri::parse() : http://'us/er@n:ame'@host/path/to/x");
|
||||||
|
t.is (uri8.path, "path/to/x", "Uri::parse() : http://'us/er@n:ame'@host/path/to/x");
|
||||||
|
t.is (uri8.protocol, "http", "Uri::parse() : http://'us/er@n:ame'@host/path/to/x");
|
||||||
|
|
||||||
|
Uri uri9 ("'user@name'@host:path/to/x");
|
||||||
|
uri9.parse ();
|
||||||
|
t.is (uri9.user, "user@name", "Uri::parse() : 'user@name'@host:path/to/x");
|
||||||
|
t.is (uri9.host, "host", "Uri::parse() : 'user@name'@host:path/to/x");
|
||||||
|
t.is (uri9.port, "", "Uri::parse() : 'user@name'@host:path/to/x");
|
||||||
|
t.is (uri9.path, "path/to/x", "Uri::parse() : 'user@name'@host:path/to/x");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue