Feature - #352 rc file should support includes

- Added include file support to Config.cpp.
- Implemented isAbsolutePath helper.
- Added unit tests for isAbsolutePath.
- Fixed small bug in bug.bulk.t.
- Added TODO items to config.t.cpp.
This commit is contained in:
Paul Beckingham 2009-12-09 17:21:09 -05:00
parent 8d43a35ca4
commit 0780919c2e
8 changed files with 64 additions and 4 deletions

View file

@ -17,6 +17,7 @@
"description.contains:th".
+ The 'version' command now complains about use of deprecated color names and
duplicate entries.
+ Task now supports nested .taskrc files using the "include /path" directive.
+ Fixed bug that showed a calendar for the year 2037 when 'task calendar due'
was run, and there are no tasks with due dates.
+ Fixed bug #316 which caused the timesheet report to display an oddly sorted

View file

@ -58,8 +58,16 @@ Config::Config (const std::string& file)
// Read the Configuration file and populate the *this map. The file format is
// simply lines with name=value pairs. Whitespace between name, = and value is
// not tolerated, but blank lines and comments starting with # are allowed.
bool Config::load (const std::string& file)
//
// Nested files are now supported, with the following construct:
// include /absolute/path/to/file
//
bool Config::load (const std::string& file, int nest /* = 1 */)
{
if (nest > 10)
throw std::string ("Configuration file nested to more than 10 levels deep"
" - this has to be a mistake.");
std::ifstream in;
in.open (file.c_str (), std::ifstream::in);
if (in.good ())
@ -82,9 +90,29 @@ bool Config::load (const std::string& file)
{
std::string key = trim (line.substr (0, equal), " \t"); // no i18n
std::string value = trim (line.substr (equal+1, line.length () - equal), " \t"); // no i18n
(*this)[key] = value;
sequence.push_back (key);
}
else
{
std::string::size_type include = line.find ("include"); // no i18n.
if (include != std::string::npos)
{
std::string included = expandPath ( trim ( line.substr (include + 7, std::string::npos), " \t"));
if (isAbsolutePath (included))
{
if (!access (included.c_str (), F_OK | R_OK))
this->load (included, nest + 1);
else
throw std::string ("Could not read include file '") + included + "'";
}
else
throw std::string ("Can only include files with absolute paths, not '") + included + "'";
}
else
throw std::string ("Malformed entry in ") + file + ": '" + line + "'";
}
}
}

View file

@ -40,7 +40,7 @@ public:
Config (const Config&);
Config& operator= (const Config&);
bool load (const std::string&);
bool load (const std::string&, int nest = 1);
void createDefaultRC (const std::string&, const std::string&);
void createDefaultData (const std::string&);
void setDefaults ();

View file

@ -52,7 +52,7 @@ qx{../task rc:bulk.rc add t6 due:saturday};
my $output = qx{echo "quit"|../task rc:bulk.rc pro:p1 pri:M 4 5 6};
like ($output, qr/Modified 0 tasks/, '"quit" prevents any further modifications');
my $output = qx{echo "all"|../task rc:bulk.rc pro:p1 pri:M 4 5 6};
$output = qx{echo "All"|../task rc:bulk.rc pro:p1 pri:M 4 5 6};
unlike ($output, qr/Task 4 "t4"\n - No changes were made/, 'Task 4 modified');
unlike ($output, qr/Task 5 "t5"\n - No changes were made/, 'Task 5 modified');
unlike ($output, qr/Task 6 "t6"\n - No changes were made/, 'Task 6 modified');

View file

@ -105,6 +105,11 @@ int main (int argc, char** argv)
// 22 default report setting created in Config::Config.
t.ok (all.size () >= 8, "Config::all");
// TODO Test includes
// TODO Test included nesting limit
// TODO Test included absolute vs relative
// TODO Test included missing file
return 0;
}

View file

@ -34,7 +34,7 @@ Context context;
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
UnitTest t (67);
UnitTest t (74);
// TODO bool confirm (const std::string&);
// TODO int confirm3 (const std::string&);
@ -113,6 +113,15 @@ int main (int argc, char** argv)
// std::string expandPath (const std::string&);
t.ok (expandPath ("foo") == "foo", "expandPath nop");
t.ok (expandPath ("~/") != "~/", "expandPath ~/");
t.ok (expandPath ("~") != "~", "expandPath ~");
// bool isAbsolutePath (const std::string&);
t.notok (isAbsolutePath ("."), "isAbsolutePath .");
t.notok (isAbsolutePath ("~"), "isAbsolutePath ~");
t.ok (isAbsolutePath (expandPath ("~")), "isAbsolutePath (expandPath ~)");
t.ok (isAbsolutePath (expandPath ("~/")), "isAbsolutePath (expandPath ~/)");
t.ok (isAbsolutePath ("/"), "isAbsolutePath /");
t.ok (isAbsolutePath ("/tmp"), "isAbsolutePath /tmp");
// TODO bool slurp (const std::string&, std::vector <std::string>&, bool trimLines = false);
// TODO bool slurp (const std::string&, std::string&, bool trimLines = false);

View file

@ -355,6 +355,13 @@ std::string expandPath (const std::string& in)
copy.replace (tilde, 1, pw->pw_dir);
}
else if ((tilde = copy.find ("~")) != std::string::npos)
{
struct passwd* pw = getpwuid (getuid ());
std::string home = pw->pw_dir;
home += "/";
copy.replace (tilde, 1, home);
}
else if ((tilde = copy.find ("~")) != std::string::npos)
{
std::string::size_type slash;
if ((slash = copy.find ("/", tilde)) != std::string::npos)
@ -369,6 +376,15 @@ std::string expandPath (const std::string& in)
return copy;
}
////////////////////////////////////////////////////////////////////////////////
bool isAbsolutePath (const std::string& in)
{
if (in.length () && in[0] == '/')
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
// On Solaris no flock function exists.
#ifdef SOLARIS

View file

@ -61,6 +61,7 @@ std::string formatBytes (size_t);
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&);
const std::string uuid ();
std::string expandPath (const std::string&);
bool isAbsolutePath (const std::string&);
#ifdef SOLARIS
#define LOCK_SH 1