[darcs-devel] Darcs Argument Handling

Ben Franksen ben.franksen at online.de
Wed May 7 01:50:33 UTC 2014


Simon Michael wrote:
> As long the tests keep passing, this sounds very good.

Thanks! (Honestly I wasn't sure the silence might mean I offended everybody 
with the harsh critique...)

I have done some preliminary attempts with a Config record, but in order to 
make proper use of it I must change Darcs.UI.Commands.Command and this will 
affect every command. So I won't get a working (testable) version until all 
the command modules have been re-factored. That will be a lot of work and 
I'd *really* like to get some more opinions from the other core devs before 
I commit to this.

In the meantime I re-factored large parts of Darcs.UI.Arguments. The idea 
was to make more use of DarcsMutuallyExclusive options and therefore ensure 
that the flag set contains all the default flags, opening the possibility to 
simplify the flag testing code.

A large majority of the options should in fact be in a mutually exclusive 
group, among them (almost, see below) all options of the yes/no type. There 
are also some options that strongly suggest they belong to a mutually 
exclusive group, but when you test it or look at the implementation you find 
that the actual behavior is different from what the name suggests. (As an 
aside, this effort finally led me to some understanding of how all the 
different parts of the darcs UI work together.)

And yes: the test-suite. Very nice piece of work, that.

And quite useful, too. I have just been running it on my working branch and 
got a few failures. I investigated and found that I had misunderstood the 
semantics of one option pair. This is an interesting case, because it's a 
perfect example of what I hinted at above, so let me briefly explain.

The tests failed because I turned Darcs.UI.Arguments.patchIndex into a mutex 
group with PatchIndexFlag as the default flag. That broke the code in 
Darcs.UI.Commands.Optimize:

  if OptimizePristine `elem` opts then
    doOptimizePristine opts repository
  else if PatchIndexFlag `elem` opts then
    createOrUpdatePatchIndexDisk repository
  else if NoPatchIndexFlag `elem` opts then
    deletePatchIndex repodir
  else ...

because with my changes, PatchIndexFlag would now always be included in the 
flag list. Apparently, although PatchIndexFlag and NoPatchIndexFlag are 
indeed mutually exclusive, none of them is on by default and both cause 
different things to happen. So they actually aren't used as options, but 
rather as sub-commands of optimize, on par with OptimizePristine.

(The help text is a bit weak here, it just says
      --patch-index          Enable patch index
      --disable-patch-index  Disable patch index)

Anyway, the upshot is that optimize should be a super command with a number 
of sub-commands, rather than (ab-)using options for that. Similar 
observations apply to 'darcs convert'.

I think I will open a ticket to propose a UI change that will turn 'convert' 
and 'optimize' into super commands.

Meanwhile, I re-factored Darcs.UI.Arguments again to allow mutually 
exclusive groups without a default, removed the default marker from 
NoPatchIndexFlag, and now the tests all succeed. Yay!

One feature I am planning to implement is a runtime check that gives the 
user a warning (perhaps this should even be an error?) when mutually 
exclusive options are specified at the same level of precedence, e.g. both 
on the command line. The current behaviour is less than ideal: Sometimes one 
option is dominant, i.e. overrides its peers regardless of position. In 
other cases, which option wins depends on the position, i.e. options given 
earlier override those given later. (Some comments in the code suggest that 
at some point the intention was the opposite i.e. later overrides earlier.)

Unfortunately, System.Console.GetOpt has no direct support for mutually 
exclusive options, but I think I have an idea how to implement this in an 
elegant way.

On the side, I have also been investigating more advanced option parsing 
libraries, to see whether darcs could profit by using them instead of the 
somewhat out-dated System.Console.GetOpt. My favorite is optparse-
applicative, which I have used in a few tools I have written. It has 
borrowed many features from darcs and produces very similar usage/help 
output, except AFAIK it doesn't (yet?) support the distinction between basic 
and advanced options.

Enough for now. As always, comments are welcome, and sorry for the (again!) 
somewhat longer posting.

Cheers
Ben
-- 
"Make it so they have to reboot after every typo." -- Scott Adams




More information about the darcs-devel mailing list