Monday, July 16, 2007

Mono.GetOptions working overtime

When I started tf4mono, the command line Team Foundation client, I didn't really want to invent yet another option parsing library and it seemed like Mono.GetOptions would fit the bill.

Over time though I found myself adding more and more options to my Options.cs file, which really got out of hand. Finally, I found myself in a hotel room in Tulsa, Oklahoma with no internet access - a perfect time for code cleanups!

I ended up keeping global options in my Options.cs and moving all command specific options into each *Command.cs file, then I give both the global driver and the desired command a crack at parsing the arg array. With a little extra hackery to support command chaining, I ended up being able to do a huge code cleanup and really enhance the builtin tf help command.

While I was mucking around in there, I added a custom "Command" attribute to decorate my Command classes. Now each command in the tf client looks something like this:

[Command("history", "Display changelog history for specified file.")]
class HistoryCommand : Command
{
[Option("Recursive", "R", "recursive")]
private bool OptionRecursive = false;

[Option("Stop After", "", "stopafter")]
private int OptionStopAfter = -1;

With a little reflection, the tf client now has a reasonable tf help <cmd> feature, which gives you:
(/usr/local/src/tfs/tools/tf) tf help hist
history (alias hist)
Display changelog history for specified file.

Valid options:
/format:ARG Format "brief" or "detailed" (also /F:ARG)
/recursive Recursive (also /R)
/stopafter:ARG Stop After
/workspace:ARG Workspace name (also /W:ARG)
Now I just need to figure out a way to generate the asciidoc manpage source file from the builtin help and life will be golden.

2 comments:

Daedius said...

Cool idea! =)

scott said...

that's a clever use of attributes