Default command with structopt

Hi everyone. I've been playing around with StructOpt for a small command line utility I'm building and it's really great. But I have some very specific requirements that I don't know how to encode properly.
Basically, my cli program has some subcommands, but it also has a "default" behaviour:

  • mess-rs foo # Takes "foo" as a PathBuf and does something with it
  • mess-rs rescue --to=<somefolder> #Executes the "rescue" subcommand which takes an optional "to"
  • etc.

what should:
mess-rs rescue
do? What if I have file with that name?

You could try to parse the command, and if that fails, check if args contains single parameter, basically bypassing structopt.

This seems like a fragile / counter-intuitive design. You should instead use eg. the -- separator or another named argument in order to pass the path to your program.

I think I should back up a bit and talk about what I'm trying to build :slight_smile:
A while ago I read this blog post: http://leahneukirchen.org/blog/archive/2006/01/keeping-your-home-clean-with-mess.html and adopted the scratchspace-methodology it talks about. But I wanted to extend the mess command a bit, and since I wanted to write some more Rust anyway I rewrote it in rust (here).

So the most important part is that mess just returns a temporary directory (and if needed creates it first) in <basepath>/<year>/<week>.

What I've already extended the program by is that I can use mess foo to create a subdirectory foo in my scratchspace so I can start working immediately.

Now those two commands being mess and mess foo respectively is really important to me because it reduces the friction of using the tool, but I do want to add some new functionality, namely mess rescue and mess prune

mess rescue

The methodology defined in the blog says that once you have a new scratchspace directory (a new week begins) you are not allowed to touch projects in the old scratchspace, you are only allowed to copy them to the newest directory. I want to build a subcommand that interactively shows me all projects in old mess directories and allows me to mark them for copying to the newest one.

mess prune

mess prune should allow me to remove old mess directories.

a note about shell integration

Since programs cannot change the cwd of their parent shell, the mess command is actually implemented as a shell function wrapper, in my case (fish shell):

function mess
  if test "$argv" = "--help" || test "$argv" = "-h"
    mess-rs --help
  else
    set -l DIR (mess-rs $argv)
    test $status = 0 && cd "$DIR"
  end
end

That is why the rust program itself is called mess-rs so I don't run into aliasing problems.

back to the problem at hand

So basically what I am trying to get to is the folliwing usage:

mess [dir]
Cd into your current mess directory, optionally creeating a subdirectory `dir`

mess rescue [--to=target]
Open an interactive dialog to move old mess directories

mess prune
Delete old mess directories

Options:
    --basedir    The base directory for all mess dirs, defaults to an os-appropriate data directory

And, following the StructOpt style I would love to have a data structure similar to this:

struct Opts {
    base_dir: Option<PathBuf>,
    command: Command
}

enum Command {
    Default {
        name: Option<PathBuf>
    },
    Rescue {
       to: Option<PathBuf>
    },
    Prune
}

An alternative would be to have mutually-exclusive flags like --rescue|--prune, but I'm also not sure how to properly do that

Alternative

Since with multiple commands the shell wrapper also gets more and more messy, an alternative would be to just have a separate command mess-rescue or messctl that contains the more sophisticated commands. I'm still interested in wether what I want to do would be possible with StructOpt, though.

Sorry for the long post, I found it rather difficult to convey what I'm trying to accomplish (which is most likely not a good sign, but I'm trying anyway^^)

You can just add temp and new subcommands, first makes a temporary directory (mess synonym), second is synonym for mess folder-name. Both are short and easy to type.

About this "structopt or nothing" thing - don't let a tool to define your workflow, make your workflow define the tool instead. For such a non-standard CLI syntax you should use some low level argument parser like getopts