Specification
Our new commandments for a better, brighter, command line:
- Send output to stdout. The primary output for your command should go to stdout. Anything that is machine readable should also go to stdout—this is where piping sends things by default.
- Send messaging to stderr. Log messages, errors, and so on should all be sent to stderr. This means that when commands are piped together, these messages are displayed to the user and not fed into the next command.
- When we are displaying output text to indicate success, we need to be brief. Feedback is always preferred, even though deviating from UNIX conventions.
- The output from stderr can be redirected to
/dev/null, but we're going to provide more verbosity options that suppresses all non-essential text (feedback, warnings, etc.).
- We should ALWAYS be using
camelCase for anything going to stdout. As we prioritize parsability, this needs to be the default. No more manually outputting strings like Name: amy.
- Nested structures should always be avoided in
dicts formats wherever possible. Instead, the nested structure should be spread into the data.
- Streaming with the JSON format should output the objects in JSONL format. To parse it with
jq, one needs to use --slurp
STDOUT
Traditionally, we have constructed human readable dictionaries as such:
process.stdout.write(
binUtils.outputFormatter({
type: options.format === 'json' ? 'json' : 'list',
data: [`Root certificate:\t\t${response.getCert()}`],
}),
);
This is clunky, inconsistent, worse for parsability and more...
In all cases where the output is "semantically" a list, the output should use either json or list. In all other cases, the list option should be replaced with dict. This should be done like this:
process.stdout.write(
binUtils.outputFormatter({
type: options.format === 'json' ? 'json' : 'dict',
data: { rootCertificate: response.getCert() },
}),
);
The data parameter must be kept as close to the return value of the RPC call possible. This ensures that our output is predictable. Furthermore
STDERR
Log messages, errors, and so on should all be sent to stderr. This means that when commands are piped together, these messages are displayed to the user and not fed into the next command.
Most STDERR messages should either be using the raw or list format. This is because they are intended to be human readable. Under json format, the data should always be { message: "..." }.
process.stderr.write(
binUtils.outputFormatter({
type: 'list',
data: ['Message 1'],
}),
);
process.stderr.write(
binUtils.outputFormatter({
type: 'raw',
data: 'Message 1',
}),
);
process.stderr.write(
binUtils.outputFormatter({
type: 'json',
data: { message: "Message 1" },
}),
);
STDIN
STDIN should always be checked for interactivity before asking prompts. This means that if a Polykey Client session has not already been opened, we should error before asking for a password prompt on a non-interactive terminal.
If input or output is a file, support - to read from stdin or write to stdout. This lets the output of another command be the input of your command and vice versa, without using a temporary file. For example:
cat secret.txt | polykey secret create - vault:secret
Piping
There is currently issues with piping input into Polykey-CLI: #139
TBD...
Additional context
Tasks
- Ensure that the output formatter can correctly format output for all possible format options without modifying content
- Replace all usage of the
list format option with dict (except in situations where the output is more semantically suited to a list)
- Ensure that there are no tabs or spaces in json output (as this needs to be machine readable)
- Replace usage of the output formatter with just outputting a single string in cases where this is appropriate
- Implement
-q argument to suppress non-essential output.
- Review commands for new specification changes
- Agent - 7/7
- Bootstrap - 1/1
- Identities - 13/13
- Keys - 12/12
- Nodes - 6/6
- Notifications - 3/3
- Secrets - 12/12
- Vaults - 12/12
Specification
Our new commandments for a better, brighter, command line:
/dev/null, but we're going to provide more verbosity options that suppresses all non-essential text (feedback, warnings, etc.).camelCasefor anything going tostdout. As we prioritize parsability, this needs to be the default. No more manually outputting strings likeName: amy.dictsformats wherever possible. Instead, the nested structure should be spread into thedata.jq, one needs to use--slurpSTDOUT
Traditionally, we have constructed human readable dictionaries as such:
This is clunky, inconsistent, worse for parsability and more...
In all cases where the output is "semantically" a list, the output should use either
jsonorlist. In all other cases, thelistoption should be replaced withdict. This should be done like this:The
dataparameter must be kept as close to the return value of the RPC call possible. This ensures that our output is predictable. FurthermoreSTDERR
Log messages, errors, and so on should all be sent to stderr. This means that when commands are piped together, these messages are displayed to the user and not fed into the next command.
Most STDERR messages should either be using the
raworlistformat. This is because they are intended to be human readable. Underjsonformat, the data should always be{ message: "..." }.STDIN
STDIN should always be checked for interactivity before asking prompts. This means that if a Polykey Client session has not already been opened, we should error before asking for a password prompt on a non-interactive terminal.
If input or output is a file, support
-to read from stdin or write to stdout. This lets the output of another command be the input of your command and vice versa, without using a temporary file. For example:cat secret.txt | polykey secret create - vault:secretPiping
There is currently issues with piping input into Polykey-CLI: #139
TBD...
Additional context
Tasks
listformat option withdict(except in situations where the output is more semantically suited to a list)-qargument to suppress non-essential output.