blob: ccab574bc27d1f02a40ba9313e57992335d19052 [file] [log] [blame] [view] [edit]
# CLI Guidelines
Define standard options to create a consistent CLI experience across tools.
When developers get used to certain option behavior, having them available
across all tools makes things much easier & smoother.
Conversely, when the same option name is used but with wildly different
meanings, this can be very surprising for developers, and possibly lead them
to do something destructive they didn't intend.
[TOC]
## Required Option Conventions
Tools should adhere to these conventions whenever possible, and any deviation
should be strongly reconsidered.
| Short | Long | Description |
|:-----:|---------------|-------------|
| | [--debug] | Show debugging information. |
| [-f] | [--force] | Force an operation. |
| [-h] | [--help] | Show tool help/usage output. |
| [-j] | [--jobs] | Control parallelization. |
| [-n] | [--dry-run] | Show what would be done. |
| [-q] | [--quiet] | Quiet(er) output. |
| [-v] | [--verbose] | Verbose(r) output. |
| | [--version] | Show tool version information. |
| [-y] | [--yes] | Skip prompts. |
### --debug {#debug}
Show internal debugging information that the user would find helpful.
This may be very verbose.
[--debug] may be specified multiple times to make the output even debuggier.
The short option [-d] may be used depending on the tool, but usually enabling
extra debugging is not a common operation.
[-d]: #debug
[--debug]: #debug
### --force {#force}
The user wants to bypass any safety checks.
The help text should provide clear guidance on how this will affect behavior
since it can potentially be very dangerous and lead to data loss.
For example, when imaging a device, do not prompt the user whether they really
meant to erase the non-removable `/dev/sda` hard drive.
Or if there are mismatches in hashes or other integrity checks, attempt to do
the operation anyways (installing files, etc...).
Do not confuse this with the [--yes] option for agreeing to common prompts.
The short option [-f] may be used or omitted depending on how dangerous the
option actually is in practice.
If the tool might delete the user's desktop or source, probably safer to make
them type out the full [--force].
If the tool would only delete some temporary files or something that could be
recreated (even if it requires a bit of effort), then [-f] is OK.
[-f]: #force
[--force]: #force
### --help {#help}
Show the tool usage, examples, and other helpful information.
Since the user has explicitly requested the help output, this does not need to
be terse.
Normal output should only go to stdout, and the tool should exit 0.
When processing unknown or invalid options, it's OK to show a short summary of
the specific option, or of valid options, but it should not be the full detailed
output like [--help].
The user should be able to focus on what they got wrong, not wade throw pages of
output to try and track down the one error line.
This output should only go to stderr, and the tool should exit non-zero (either
`1` or `64`).
Use of the short [-h] option is recommended out of wide convention.
Avoid reusing this for something else like `--human`, and definitely never use
it for something destructive or unrecoverable.
[-h]: #help
[--help]: #help
### --jobs {#jobs}
Limit how much parallelism should be used.
This typically translates to how many threads or CPUs to utilize.
The special value `0` should be used to indicate "use all available CPU cores".
The default does not have to always be `1` thus forcing users to manually pick
a value, nor does it have to always be `0`.
Try to balance how expensive a particular job is (network, servers, I/O, RAM,
etc...) with a reasonable default.
For example, when talking to a network service, high values like 72 will
probably cause many connections to be rejected so it won't be overwhelmed, so
find a default that balances real world improvements (compared to `-j1`) with
the server costs.
The default should rarely be hardcoded to a value above 1 -- run it through a
max function with how many cores are available.
For example, the default could be `max(4, os.cpu_count())`.
To determine how many CPU cores are available:
* Python: `os.cpu_count()`
* Shell: `getconf _NPROCESSORS_CONF 2>/dev/null || echo 1`
Use of the short [-j] option is recommended out of wide convention.
[-j]: #jobs
[--jobs]: #jobs
### --dry-run {#dryrun}
Show what would be done, but don't actually "do" anything.
Users should be able to add this option anywhere and expect that the tool will
not make any changes anywhere.
Basically this should always be a harmless idempotent operation.
Use of [--dry-run] is, by itself, not an error, thus it should normally exit 0.
This allows the user to quickly detect problems before trying to make changes.
For example, if invalid options were specified, the tool can show fatal errors.
Or if inputs don't exist, or are corrupt, they may be diagnosed.
The tool may talk to network services, or otherwise make expensive computations,
as long as it doesn't make any changes, and may be rerun many times.
The tool should display what it would have done were [--dry-run] not specified.
This will often take the form like `Would have run command: git push ...`.
Bypassing reasonable prompts is permitted as long as no changes are made.
In other words, this may behave like [--yes] or [--force] in some situations.
Use your best judgment as to what constitutes the best user experience.
Use of the short [-n] option is recommended out of wide convention, and because
use of dry-run first is a common user flow.
The [--dryrun] option should be accepted as an alias to [--dry-run], but should
be omitted from documentation (i.e. [--help] output).
This helps users who typo things, and because some tools have adopted one that
convention instead of [--dry-run] (although the latter is still more common).
[-n]: #dryrun
[--dry-run]: #dryrun
[--dryrun]: #dryrun
### --quiet {#quiet}
Make the output less verbose.
General information should be omitted, and only display warnings or errors.
[--quiet] may be specified multiple times to make the output even quieter.
Some recommended settings:
* *default*: Show important events, warnings, and worse.
* `-q`: Only show warnings and worse.
* `-qq`: Only show (fatal) errors and worse.
* `-qqq`: Don't show any output -- rely on exit status to indicate pass/fail.
Use of the short [-q] option is recommended out of wide convention.
If desired, [--silent] may be used as an alias to `-qqq` behavior; i.e. do not
emit any output, only exit 0/non-zero.
[-q]: #quiet
[--quiet]: #quiet
[--silent]: #quiet
### --verbose
Make the output more verbose.
This may include some helpful info or progress steps.
Important information for the user should not be hidden behind [--verbose];
i.e. users should not be expected to use [--verbose] all the time.
[--verbose] may be specified multiple times to make the output even verboser.
Debugging information should not be included here -- use [--debug] instead.
Use your best judgement as to what is verbose output and what is debug output.
Use of the short [-v] option is recommended out of wide convention, and because
it can be common to type `-vvv` to quickly get more verbose output when trying
to track down problems.
[-v]: #verbose
[--verbose]: #verbose
### --version {#version}
Show version information for the current tool.
Normal output should only go to stdout, and the tool should exit 0.
The default output should be short & to the point, and cheap to produce.
This may include terse authorship information if desired.
If combined with [--verbose], related package/tool information may be included.
If combined with [--quiet], the output should be just the version number.
For example, common output might look like:
```
$ tool --version
CrOS tool v1.2.3
Written by some decent engineers.
$ tool --version --quiet
1.2.3
$ tool --version --verbose
CrOS tool v1.2.3
Current git repo is at add119cea9ebfd7ba89f7606ed04cac7cacaa43d.
Some important library information:
foo lib v2
another lib v3.4
Written by some decent engineers.
```
No short option should be provided for [--version].
It's not a common operation, so allocating one of the limited short options
is a waste.
[--version]: #version
### --yes {#yes}
The user wants to "agree" to any standard prompts shown by the tool.
This should not be used by itself to bypass safety checks -- see [--force]
instead, with which this can be combined.
The prompts that would have been shown should still be emitted so it's clear
what the user has agreed to, and include fake input. For example:
```
$ do-something --yes
Do you want to do something? (Y/n) <yes>
```
Use of the short [-y] option is recommended out of wide convention, and because
skipping the same set of prompts is a common flow to avoid annoying users.
[-y]: #yes
[--yes]: #yes