- Implemented export.yaml, import (yaml).
- Updated man page.
- 'export' is now an alias to 'export.yaml'.
- Added missing 'tags' attribute as an internal Att.
- Improved recognition of YAML.
- Added unit tests for export.yaml, import (yaml).
- Added missing unlink from dependencies.t
This commit is contained in:
Paul Beckingham 2010-08-02 17:45:48 -04:00
parent f60205c704
commit e090f556da
10 changed files with 285 additions and 19 deletions

View file

@ -8,6 +8,8 @@
as relative to the current date/time.
+ Added feature #189, that records the start and stop times
as an annotation for a task.
+ Added features #244, #272, #274 and #275, which support import and
export of YAML 1.1. YAML is now the default export format for task.
+ Added feature #391, now the 'task color legend' command will show
samples of all the defined colors and color rules from your .taskrc
and theme.

3
NEWS
View file

@ -10,6 +10,7 @@ New Features in task 1.9.3
- Now supports 'now' as a date.
- Now defines an overdue task as being one second after the due date,
instead of the day after the due date.
- Import and export of YAML 1.1, including round-trip capability.
Please refer to the ChangeLog file for full details. There are too many to
list here.
@ -18,6 +19,8 @@ New commands in task 1.9.3
- New 'task color legend' command will show samples of all the defined colors
and color rules from your .taskrc and theme.
- New 'task export.yaml' command will export YAML 1.1, which can then be
imported via 'task import <file>'.
New configuration options in task 1.9.3

View file

@ -124,7 +124,12 @@ Imports tasks from a variety of formats.
.TP
.B export
Exports all tasks in CSV format. This command is an alias to the export.csv command.
Exports all tasks in the default format. This is an alias to the command export.yaml.
Redirect the output to a file, if you wish to save it, or pipe it to another command.
.TP
.B export.csv
Exports all tasks in CSV format.
Redirect the output to a file, if you wish to save it, or pipe it to another command.
.TP
@ -132,6 +137,11 @@ Redirect the output to a file, if you wish to save it, or pipe it to another com
Exports all tasks in iCalendar format.
Redirect the output to a file, if you wish to save it, or pipe it to another command.
.TP
.B export.yaml
Exports all tasks in YAML 1.1 format.
Redirect the output to a file, if you wish to save it, or pipe it to another command.
.TP
.B color [sample | legend]
Displays all possible colors, a named sample, or a legend containing all

View file

@ -51,6 +51,7 @@ static const char* internalNames[] =
"limit",
"status",
"description",
"tags",
// Note that annotations are not listed.
};

View file

@ -232,7 +232,7 @@ std::string Config::defaults =
"alias.rm=delete # Alias for the delete command\n"
"alias.history=history.monthly # Prefer monthly over annual history reports\n"
"alias.ghistory=ghistory.monthly # Prefer monthly graphical over annual history reports\n"
"alias.export=export.csv # Prefer CSV over iCal export\n"
"alias.export=export.yaml # Prefer YAML over CSV or iCal export\n"
"alias.export.vcalendar=export.ical # They are the same\n"
"\n"
"# Fields: id, uuid, project, priority, priority_long, entry, start, end, due\n"

View file

@ -405,15 +405,18 @@ std::string Task::composeYAML () const
Att::allNames (names);
std::sort (names.begin (), names.end ());
// Only include non-trivial attributes.
std::string value;
foreach (name, names)
out << " " << *name << ": " << get (*name) << "\n";
if ((value = get (*name)) != "")
out << " " << *name << ": " << value << "\n";
// Now the annotations, which are not listed by the Att::allNames call.
std::vector <Att> annotations;
getAnnotations (annotations);
foreach (a, annotations)
out << " annotation:\n"
<< " entry: " << a->name().substr (12) << "\n"
<< " entry: " << a->name().substr (11) << "\n"
<< " description: " << a->value () << "\n";
return out.str ();

View file

@ -79,6 +79,13 @@ static fileType determineFileType (const std::vector <std::string>& lines)
return task_1_4_3;
}
if (lines.size () > 2 &&
lines[0] == "%YAML 1.1" &&
lines[1] == "---")
{
return yaml;
}
// A task command line might include a priority or project.
for (unsigned int i = 0; i < lines.size (); ++i)
{
@ -154,13 +161,6 @@ static fileType determineFileType (const std::vector <std::string>& lines)
if (commas_on_every_line)
return csv;
if (lines.size () > 2 &&
lines[0] == "% YAML 1.1\n" &&
lines[1] == "---\n")
{
return yaml;
}
// Looks like 'text' is the default case, if there is any data at all.
if (lines.size () > 1)
return text;
@ -1155,6 +1155,79 @@ static std::string importCSV (const std::vector <std::string>& lines)
return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
static std::string importYAML (const std::vector <std::string>& lines)
{
int count = 0;
context.tdb.lock (context.config.getBoolean ("locking"));
Task t;
std::string name;
std::string value;
bool inAnno = false;
std::string annoEntry;
std::vector <std::string>::const_iterator it;
for (it = lines.begin (); it != lines.end (); ++it)
{
name = "";
value = "";
Nibbler n (*it);
n.skipWS ();
n.getUntil (':', name);
n.skip (':');
n.skipWS ();
n.getUntilEOL (value);
if (name == "%YAML 1.1")
;
else if (name == "---")
;
else if (name == "task" || name == "...")
{
if (t.size ())
{
context.tdb.add (t);
t.clear ();
++count;
}
}
else if (name == "annotation")
inAnno = true;
else if (name == "entry" && inAnno)
annoEntry = value;
else if (name == "description" && inAnno)
{
t.set ("annotation_" + annoEntry, value);
annoEntry = "";
inAnno = false;
}
else if (name != "" && value != "")
t.set (name, value);
}
context.tdb.commit ();
context.tdb.unlock ();
std::stringstream out;
out << "Imported "
<< count
<< " tasks successfully."
<< std::endl;
return out.str ();
}
////////////////////////////////////////////////////////////////////////////////
int handleImport (std::string &outs)
{
@ -1177,12 +1250,6 @@ int handleImport (std::string &outs)
for (it = all.begin (); it != all.end (); ++it)
{
std::string line = *it;
// Strip comments
std::string::size_type pound = line.find ("#");
if (pound != std::string::npos)
line = line.substr (0, pound);
trim (line);
// Skip blank lines
@ -1222,7 +1289,7 @@ int handleImport (std::string &outs)
case task_cmd_line: out << importTaskCmdLine (lines); break;
case todo_sh_2_0: out << importTodoSh_2_0 (lines); break;
case csv: out << importCSV (lines); break;
case yaml: throw std::string ("import.yaml not implemented.");
case yaml: out << importYAML (lines); break;
case text: out << importText (lines); break;
case not_a_clue: /* to stop the compiler from complaining. */ break;
}

View file

@ -41,7 +41,7 @@ if (open my $fh, '>', 'export.rc')
# Add two tasks, export, examine result.
qx{../task rc:export.rc add priority:H project:A one};
qx{../task rc:export.rc add +tag1 +tag2 two};
qx{../task rc:export.rc export > ./export.txt};
qx{../task rc:export.rc export.csv > ./export.txt};
my @lines;
if (open my $fh, '<', './export.txt')

84
src/tests/export.yaml.t Executable file
View file

@ -0,0 +1,84 @@
#! /usr/bin/perl
################################################################################
## task - 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
##
################################################################################
use strict;
use warnings;
use Test::More tests => 21;
# Create the rc file.
if (open my $fh, '>', 'export.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'export.rc', 'Created export.rc');
}
# Add two tasks, export, examine result.
qx{../task rc:export.rc add priority:H project:A one};
qx{../task rc:export.rc add +tag1 +tag2 two};
qx{../task rc:export.rc export.yaml | tail +2 > ./export.txt};
my @lines;
if (open my $fh, '<', './export.txt')
{
@lines = <$fh>;
close $fh;
}
like ($lines[0], qr/^%YAML 1.1$/, 'export.yaml line 0');
like ($lines[1], qr/^---$/, 'export.yaml line 1');
like ($lines[2], qr/^ task:$/, 'export.yaml line 2');
like ($lines[3], qr/^ description: one$/, 'export.yaml line 3');
like ($lines[4], qr/^ entry: \d+$/, 'export.yaml line 4');
like ($lines[5], qr/^ priority: H$/, 'export.yaml line 5');
like ($lines[6], qr/^ project: A$/, 'export.yaml line 6');
like ($lines[7], qr/^ status: pending$/, 'export.yaml line 7');
like ($lines[8], qr/^ uuid: .+$/, 'export.yaml line 8');
like ($lines[9], qr/^ task:$/, 'export.yaml line 9');
like ($lines[10], qr/^ description: two$/, 'export.yaml line 10');
like ($lines[11], qr/^ entry: \d+$/, 'export.yaml line 11');
like ($lines[12], qr/^ status: pending$/, 'export.yaml line 12');
like ($lines[13], qr/^ tags: tag1,tag2$/, 'export.yaml line 13');
like ($lines[14], qr/^ uuid: .+$/, 'export.yaml line 14');
like ($lines[15], qr/^\.\.\.$/, 'export.yaml line 15');
# Cleanup.
unlink 'export.txt';
ok (!-r 'export.txt', 'Removed export.txt');
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'undo.data';
ok (!-r 'undo.data', 'Removed undo.data');
unlink 'export.rc';
ok (!-r 'export.rc', 'Removed export.rc');
exit 0;

96
src/tests/import.yaml.t Executable file
View file

@ -0,0 +1,96 @@
#! /usr/bin/perl
################################################################################
## task - 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
##
################################################################################
use strict;
use warnings;
use Test::More tests => 11;
# Create the rc file.
if (open my $fh, '>', 'import.rc')
{
print $fh "data.location=.\n";
close $fh;
ok (-r 'import.rc', 'Created import.rc');
}
# Create import file.
if (open my $fh, '>', 'import.txt')
{
print $fh <<EOF;
%YAML 1.1
---
task:
uuid: 00000000-0000-0000-0000-000000000000
description: zero
project: A
status: pending
task:
uuid: 11111111-1111-1111-1111-111111111111
description: one
project: B
status: pending
task:
uuid: 22222222-2222-2222-2222-222222222222
description: two
status: completed
end: 1234567890
...
EOF
close $fh;
ok (-r 'import.txt', 'Created sample import data');
}
my $output = qx{../task rc:import.rc import import.txt};
like ($output, qr/Imported 3 tasks successfully./, 'no errors');
$output = qx{../task rc:import.rc list};
like ($output, qr/1.+A.+zero/, 't1');
like ($output, qr/2.+B.+one/, 't2');
$output = qx{../task rc:import.rc completed};
like ($output, qr/2\/13\/2009.+two/, 't3');
# Cleanup.
unlink 'import.txt';
ok (!-r 'import.txt', 'Removed import.txt');
unlink 'pending.data';
ok (!-r 'pending.data', 'Removed pending.data');
unlink 'completed.data';
ok (!-r 'completed.data', 'Removed completed.data');
unlink 'undo.data';
ok (!-r 'undo.data', 'Removed undo.data');
unlink 'import.rc';
ok (!-r 'import.rc', 'Removed import.rc');
exit 0;