Skip to content

Conversation

@matklad
Copy link
Contributor

@matklad matklad commented Jan 22, 2017

Hi! So I've finally got to try the thing we have briefly discussed at RustConf: removing duplication of docopt options in different commands. This PR is a rough proof of concept to gather feedback and decide if we need this at all.

The approach here is to use hand-rolled code generation: all commands are specified in options.txt file, from which options.rs with docopt usage strings and options strutcs is generated. In options.txt, we can defined option groups and then use them to assemble full docopt description of the command.

I've decided to go with code generation and not with runtime string concatenation for the following reasons:

  • In some sense, it is simpler: to understand the end result, you need to look only at options.rs, which contains usual self-describing docopt usages and structs. You don't need to understand the tricky string concatenation stuff.

  • We can generate not only the usage strings, but also the structs with options. I think this can be extended to also generate bash completions.

  • This can be extended to generate structs for different option groups, so instead of config.configure(options.flag_verbose, options.flag_quiet, &options.flag_color, options.flag_frozen, options.flag_locked)?; one can write config.configure(options.color_options(), options.lockfile_options()).

So that's the plan :)

Current implementation applies it only to build and publish commands, to show what's possible without creating a huge diff. Generation is done with a separate binary generate-options.rs and not via build.rs just because it was easier to debug. However I think it maybe better to avoid build.rs and just to commit the generated options.rs together with options.txt: the generated code is supposed to be very readable, and you might want to inspect it to see if the help message is wrapped properly, for example.

generate-options.rs is very rough: lots of unwraps and does not handle multiline flag descriptions :)

@matklad
Copy link
Contributor Author

matklad commented Jan 23, 2017

Hm, I now think there's a fundamental limitation here... To have a perfect CLI, we might need to wrap the same option differently depending on the subcommand. And ideally we should rewrap the help message to fit the actual terminal width. AFAIK docopt does not support this.

I'll explore if we could switch from docopt to clap, it does rewrapping automatically, and should be easier to compose.

@alexcrichton
Copy link
Member

Looking good! If the goal here is to reduce duplication then I wonder if we may want to pursue an alternate option parsing library? It may be the case that docopt isn't the best for Cargo's purposes, but perhaps we could investigate alternate libraries like clap? IIRC that has Rust-builder-style definitions which might allow common configuration to be refactored into helper methods.

@matklad
Copy link
Contributor Author

matklad commented Jan 23, 2017

I'll then look into clap then! Now I am 90% sure that it would be a proper solution. The remaining 10% are for the chance that it might be impossible to replicate current interface backward compatibly.

@matklad matklad closed this Jan 23, 2017
@matklad matklad deleted the dedup branch February 25, 2017 10:56
@matklad matklad mentioned this pull request Mar 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants