Enhancement - #307 show command

- introduced new show command to display configuration settings
- config command is used to just set config values
- modified documentation
- modified some unit tests calling 'task config' to 'task show'
This commit is contained in:
Federico Hernandez 2010-06-07 23:35:58 +02:00
parent f1368d6ac6
commit 51e5a18384
12 changed files with 156 additions and 125 deletions

View file

@ -129,12 +129,16 @@ Shows the task version number
.B help .B help
Shows the long usage text. Shows the long usage text.
.TP show
Shows the current settings in the task configuration file. If a section-name is
specified just the settings for the particular section will be displayed.
Section-names are: alias, calendar, color, general, holiday, report.
.TP .TP
.B config [name [value | '']] .B config [name [value | '']]
Shows the current settings in the task configuration file. Also supports Add, modify and remove settings directly in the task configuration.
directly modifying the .taskrc file. This command either modifies This command either modifies the 'name' setting with a new value of 'value',
the 'name' setting with a new value of 'value', or adds a new entry that or adds a new entry that is equivalent to 'name=value':
is equivalent to 'name=value':
task config name value task config name value

View file

@ -59,6 +59,7 @@
228 version 228 version
229 shell 229 shell
230 config 230 config
231 show
# 3xx Attributes - must be sequential # 3xx Attributes - must be sequential
300 project 300 project

View file

@ -126,6 +126,7 @@ void Cmd::load ()
commands.push_back (context.stringtable.get (CMD_CALENDAR, "calendar")); commands.push_back (context.stringtable.get (CMD_CALENDAR, "calendar"));
commands.push_back (context.stringtable.get (CMD_COLORS, "colors")); commands.push_back (context.stringtable.get (CMD_COLORS, "colors"));
commands.push_back (context.stringtable.get (CMD_CONFIG, "config")); commands.push_back (context.stringtable.get (CMD_CONFIG, "config"));
commands.push_back (context.stringtable.get (CMD_SHOW, "show"));
commands.push_back (context.stringtable.get (CMD_DELETE, "delete")); commands.push_back (context.stringtable.get (CMD_DELETE, "delete"));
commands.push_back (context.stringtable.get (CMD_DONE, "done")); commands.push_back (context.stringtable.get (CMD_DONE, "done"));
commands.push_back (context.stringtable.get (CMD_DUPLICATE, "duplicate")); commands.push_back (context.stringtable.get (CMD_DUPLICATE, "duplicate"));
@ -211,6 +212,7 @@ bool Cmd::isReadOnlyCommand ()
command == context.stringtable.get (CMD_CALENDAR, "calendar") || command == context.stringtable.get (CMD_CALENDAR, "calendar") ||
command == context.stringtable.get (CMD_COLORS, "colors") || command == context.stringtable.get (CMD_COLORS, "colors") ||
command == context.stringtable.get (CMD_CONFIG, "config") || command == context.stringtable.get (CMD_CONFIG, "config") ||
command == context.stringtable.get (CMD_SHOW, "show") ||
command == context.stringtable.get (CMD_HELP, "help") || command == context.stringtable.get (CMD_HELP, "help") ||
command == context.stringtable.get (CMD_INFO, "info") || command == context.stringtable.get (CMD_INFO, "info") ||
command == context.stringtable.get (CMD_PROJECTS, "projects") || command == context.stringtable.get (CMD_PROJECTS, "projects") ||

View file

@ -210,6 +210,7 @@ int Context::dispatch (std::string &out)
else if (cmd.command == "colors") { rc = handleColor (out); } else if (cmd.command == "colors") { rc = handleColor (out); }
else if (cmd.command == "version") { rc = handleVersion (out); } else if (cmd.command == "version") { rc = handleVersion (out); }
else if (cmd.command == "config") { rc = handleConfig (out); } else if (cmd.command == "config") { rc = handleConfig (out); }
else if (cmd.command == "show") { rc = handleShow (out); }
else if (cmd.command == "help") { rc = longUsage (out); } else if (cmd.command == "help") { rc = longUsage (out); }
else if (cmd.command == "stats") { rc = handleReportStats (out); } else if (cmd.command == "stats") { rc = handleReportStats (out); }
else if (cmd.command == "info") { rc = handleInfo (out); } else if (cmd.command == "info") { rc = handleInfo (out); }

View file

@ -601,7 +601,7 @@ int handleVersion (std::string &outs)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int handleConfig (std::string &outs) int handleShow (std::string &outs)
{ {
int rc = 0; int rc = 0;
@ -614,114 +614,6 @@ int handleConfig (std::string &outs)
std::vector <std::string> args; std::vector <std::string> args;
split (args, context.task.get ("description"), ' '); split (args, context.task.get ("description"), ' ');
// Support:
// task config name value # set name to value
// task config name "" # set name to blank
// task config name # remove name
if (args.size () > 0)
{
std::string name = args[0];
std::string value = "";
if (args.size () > 1)
{
for (unsigned int i = 1; i < args.size (); ++i)
{
if (i > 1)
value += " ";
value += args[i];
}
}
if (name != "")
{
bool change = false;
// Read .taskrc (or equivalent)
std::string contents;
File::read (context.config.original_file, contents);
// task config name value
// task config name ""
if (args.size () > 1 ||
context.args[context.args.size () - 1] == "")
{
// Find existing entry & overwrite
std::string::size_type pos = contents.find (name + "=");
if (pos != std::string::npos)
{
std::string::size_type eol = contents.find_first_of ("\r\f\n", pos);
if (eol == std::string::npos)
throw std::string ("Cannot find EOL after entry '") + name + "'";
if (confirm (std::string ("Are you sure you want to change the value of '")
+ name
+ "' from '"
+ context.config.get(name)
+ "' to '"
+ value + "'?"))
{
contents = contents.substr (0, pos)
+ name + "=" + value
+ contents.substr (eol);
change = true;
}
}
// Not found, so append instead.
else
{
if (confirm (std::string ("Are you sure you want to add '") + name + "' with a value of '" + value + "'?"))
{
contents = contents
+ "\n"
+ name + "=" + value
+ "\n";
change = true;
}
}
}
// task config name
else
{
// Remove name
std::string::size_type pos = contents.find (name + "=");
if (pos == std::string::npos)
throw std::string ("No entry named '") + name + "' found";
std::string::size_type eol = contents.find_first_of ("\r\f\n", pos);
if (eol == std::string::npos)
throw std::string ("Cannot find EOL after entry '") + name + "'";
if (confirm (std::string ("Are you sure you want to remove '") + name + "'?"))
{
contents = contents.substr (0, pos) + contents.substr (eol + 1);
change = true;
}
}
// Write .taskrc (or equivalent)
if (change)
{
File::write (context.config.original_file, contents);
out << "Config file "
<< context.config.original_file.data
<< " modified."
<< std::endl;
}
else
out << "No changes made." << std::endl;
}
else
throw std::string ("Specify the name of a config variable to modify.");
outs = out.str ();
return rc;
}
// No arguments - display config values instead.
int width = context.getWidth (); int width = context.getWidth ();
std::vector <std::string> all; std::vector <std::string> all;
@ -955,6 +847,131 @@ int handleConfig (std::string &outs)
return rc; return rc;
} }
////////////////////////////////////////////////////////////////////////////////
int handleConfig (std::string &outs)
{
int rc = 0;
if (context.hooks.trigger ("pre-config-command"))
{
std::stringstream out;
// Obtain the arguments from the description. That way, things like '--'
// have already been handled.
std::vector <std::string> args;
split (args, context.task.get ("description"), ' ');
// Support:
// task config name value # set name to value
// task config name "" # set name to blank
// task config name # remove name
if (args.size () > 0)
{
std::string name = args[0];
std::string value = "";
if (args.size () > 1)
{
for (unsigned int i = 1; i < args.size (); ++i)
{
if (i > 1)
value += " ";
value += args[i];
}
}
if (name != "")
{
bool change = false;
// Read .taskrc (or equivalent)
std::string contents;
File::read (context.config.original_file, contents);
// task config name value
// task config name ""
if (args.size () > 1 ||
context.args[context.args.size () - 1] == "")
{
// Find existing entry & overwrite
std::string::size_type pos = contents.find (name + "=");
if (pos != std::string::npos)
{
std::string::size_type eol = contents.find_first_of ("\r\f\n", pos);
if (eol == std::string::npos)
throw std::string ("Cannot find EOL after entry '") + name + "'";
if (confirm (std::string ("Are you sure you want to change the value of '")
+ name
+ "' from '"
+ context.config.get(name)
+ "' to '"
+ value + "'?"))
{
contents = contents.substr (0, pos)
+ name + "=" + value
+ contents.substr (eol);
change = true;
}
}
// Not found, so append instead.
else
{
if (confirm (std::string ("Are you sure you want to add '") + name + "' with a value of '" + value + "'?"))
{
contents = contents
+ "\n"
+ name + "=" + value
+ "\n";
change = true;
}
}
}
// task config name
else
{
// Remove name
std::string::size_type pos = contents.find (name + "=");
if (pos == std::string::npos)
throw std::string ("No entry named '") + name + "' found";
std::string::size_type eol = contents.find_first_of ("\r\f\n", pos);
if (eol == std::string::npos)
throw std::string ("Cannot find EOL after entry '") + name + "'";
if (confirm (std::string ("Are you sure you want to remove '") + name + "'?"))
{
contents = contents.substr (0, pos) + contents.substr (eol + 1);
change = true;
}
}
// Write .taskrc (or equivalent)
if (change)
{
File::write (context.config.original_file, contents);
out << "Config file "
<< context.config.original_file.data
<< " modified."
<< std::endl;
}
else
out << "No changes made." << std::endl;
}
else
throw std::string ("Specify the name of a config variable to modify.");
outs = out.str ();
context.hooks.trigger ("post-config-command");
}
else
throw std::string ("Specify the name of a config variable to modify.");
}
return rc;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int handleDelete (std::string &outs) int handleDelete (std::string &outs)
{ {

View file

@ -96,6 +96,7 @@
#define CMD_VERSION 228 #define CMD_VERSION 228
#define CMD_SHELL 229 #define CMD_SHELL 229
#define CMD_CONFIG 230 #define CMD_CONFIG 230
#define CMD_SHOW 231
// 3xx Attributes // 3xx Attributes
#define ATT_PROJECT 300 #define ATT_PROJECT 300

View file

@ -71,6 +71,7 @@ int handleCompletionConfig (std::string &);
int handleCompletionVersion (std::string &); int handleCompletionVersion (std::string &);
int handleVersion (std::string &); int handleVersion (std::string &);
int handleConfig (std::string &); int handleConfig (std::string &);
int handleShow (std::string &);
int handleDelete (std::string &); int handleDelete (std::string &);
int handleStart (std::string &); int handleStart (std::string &);
int handleStop (std::string &); int handleStop (std::string &);

View file

@ -206,9 +206,13 @@ int shortUsage (std::string &outs)
table.addCell (row, 1, "task version"); table.addCell (row, 1, "task version");
table.addCell (row, 2, "Shows the task version number."); table.addCell (row, 2, "Shows the task version number.");
row = table.addRow ();
table.addCell (row, 1, "task show [section-name]");
table.addCell (row, 2, "Shows the task entire configuration or a specific section.");
row = table.addRow (); row = table.addRow ();
table.addCell (row, 1, "task config [name [value | '']]"); table.addCell (row, 1, "task config [name [value | '']]");
table.addCell (row, 2, "Shows the task configuration, or can add, modify and remove settings."); table.addCell (row, 2, "Add, modify and remove settings in the task configuration.");
row = table.addRow (); row = table.addRow ();
table.addCell (row, 1, "task help"); table.addCell (row, 1, "task help");

View file

@ -41,7 +41,7 @@ if (open my $fh, '>', 'color.rc')
} }
# Test the add command. # Test the add command.
my $output = qx{../task rc:color.rc config}; my $output = qx{../task rc:color.rc show};
like ($output, qr/that use deprecated underscores/ms, 'Deprecated color detected'); like ($output, qr/that use deprecated underscores/ms, 'Deprecated color detected');
# Cleanup. # Cleanup.

View file

@ -40,7 +40,7 @@ if (open my $fh, '>', 'obsolete.rc')
} }
# Test the add command. # Test the add command.
my $output = qx{../task rc:obsolete.rc config}; my $output = qx{../task rc:obsolete.rc show};
like ($output, qr/Your .taskrc file contains these unrecognized variables:\n/, like ($output, qr/Your .taskrc file contains these unrecognized variables:\n/,
'unsupported configuration variable'); 'unsupported configuration variable');

View file

@ -39,10 +39,10 @@ if (open my $fh, '>', 'rc.rc')
ok (-r 'rc.rc', 'Created rc.rc'); ok (-r 'rc.rc', 'Created rc.rc');
} }
my $output = qx{../task rc:rc.rc config}; my $output = qx{../task rc:rc.rc show};
like ($output, qr/\sfoo\s+bar/, 'unmodified'); like ($output, qr/\sfoo\s+bar/, 'unmodified');
$output = qx{../task rc:rc.rc rc.foo:baz config}; $output = qx{../task rc:rc.rc rc.foo:baz show};
like ($output, qr/\sfoo\s+baz/, 'overridden'); like ($output, qr/\sfoo\s+baz/, 'overridden');
unlink 'rc.rc'; unlink 'rc.rc';

View file

@ -53,34 +53,34 @@ ok (-d 'foo', 'Created default data directory');
# Add a setting. # Add a setting.
qx{echo 'y'|../task rc:foo.rc config must_be_unique old}; qx{echo 'y'|../task rc:foo.rc config must_be_unique old};
my $output = qx{../task rc:foo.rc config}; my $output = qx{../task rc:foo.rc show};
like ($output, qr/^must_be_unique\s+old$/ms, 'config setting a new value'); like ($output, qr/^must_be_unique\s+old$/ms, 'config setting a new value');
qx{echo 'y'|../task rc:foo.rc config must_be_unique new}; qx{echo 'y'|../task rc:foo.rc config must_be_unique new};
$output = qx{../task rc:foo.rc config}; $output = qx{../task rc:foo.rc show};
like ($output, qr/^must_be_unique\s+new$/ms, 'config overwriting an existing value'); like ($output, qr/^must_be_unique\s+new$/ms, 'config overwriting an existing value');
qx{echo 'y'|../task rc:foo.rc config must_be_unique ''}; qx{echo 'y'|../task rc:foo.rc config must_be_unique ''};
$output = qx{../task rc:foo.rc config}; $output = qx{../task rc:foo.rc show};
like ($output, qr/^must_be_unique$/ms, 'config setting a blank value'); like ($output, qr/^must_be_unique$/ms, 'config setting a blank value');
qx{echo 'y'|../task rc:foo.rc config must_be_unique}; qx{echo 'y'|../task rc:foo.rc config must_be_unique};
$output = qx{../task rc:foo.rc config}; $output = qx{../task rc:foo.rc show};
unlike ($output, qr/^must_be_unique/ms, 'config removing a value'); unlike ($output, qr/^must_be_unique/ms, 'config removing a value');
# 'report.:b' is designed to get past the config command checks for recognized # 'report.:b' is designed to get past the config command checks for recognized
# names. # names.
qx{echo 'y'|../task rc:foo.rc config -- report.:b +c}; qx{echo 'y'|../task rc:foo.rc config -- report.:b +c};
$output = qx{../task rc:foo.rc config}; $output = qx{../task rc:foo.rc show};
like ($output, qr/^report\.:b\s+\+c/ms, 'the -- operator is working'); like ($output, qr/^report\.:b\s+\+c/ms, 'the -- operator is working');
# Make sure the value is accepted if it has multiple words. # Make sure the value is accepted if it has multiple words.
qx{echo 'y'|../task rc:foo.rc config must_be_unique 'one two three'}; qx{echo 'y'|../task rc:foo.rc config must_be_unique 'one two three'};
$output = qx{../task rc:foo.rc config}; $output = qx{../task rc:foo.rc show};
like ($output, qr/^must_be_unique\s+one two three$/ms, 'config allows multi-word quoted values'); like ($output, qr/^must_be_unique\s+one two three$/ms, 'config allows multi-word quoted values');
qx{echo 'y'|../task rc:foo.rc config must_be_unique one two three}; qx{echo 'y'|../task rc:foo.rc config must_be_unique one two three};
$output = qx{../task rc:foo.rc config}; $output = qx{../task rc:foo.rc show};
like ($output, qr/^must_be_unique\s+one two three$/ms, 'config allows multi-word unquoted values'); like ($output, qr/^must_be_unique\s+one two three$/ms, 'config allows multi-word unquoted values');
rmtree 'foo', 0, 0; rmtree 'foo', 0, 0;