summaryrefslogtreecommitdiffstats
path: root/sq
diff options
context:
space:
mode:
authorNora Widdecke <nora@sequoia-pgp.org>2022-05-06 17:57:06 +0200
committerNora Widdecke <nora@sequoia-pgp.org>2022-05-16 14:23:08 +0200
commitf17ada2baf2866e90ac1f9d68309ed9b8d8347f8 (patch)
tree3d3e47c2f9eb69cb41a56ce91fcadf42ed008f96 /sq
parente41ce7b791031bf40d0035673fd2f32b2a2a029c (diff)
sq: Port command line handling from clap 2 to 3.
Change sq command line handling from using clap version 2 to version 3, and adapt to all the breaking changes. Clap version 3 is a major new version with a number of breaking changes. It also adds functionality to allow a structopt style declarative way of defining command line syntax. We want to use that, but first we need to port the old "builder style" of defining the command line syntax to clap version 3. The change to use the "derive style" comes later. The semantics of clap version 2's .multiple function were hard to understand and it was replaced with .multiple_occurences. Care was taken to preserve the original intention regarding an argument's number of occurrences and number of values. There are some changes to help output (in src/sq-usage.rs). These are mostly from upstream changes and we think the differences are minor so we are okay with following upstream's lead. In summary: FLAGS and OPTIONS are merged into just OPTIONS; the layout of subcommand lists are a little different (split into two lines); there is no "[--]" before filename arguments anymore; default and allowed values for options are on a separate line now; --version isn't repeated for every subcommand anymore; help is listed for each subcommand separately. In addition, we will help clap upstream fix a problem where the help output doesn't have a "..." to indicate that an option may be used several times. Further, upstream has changed --help text to be of the form "Print help", when it earlier was "Prints help". We will change our own help texts to follow suite in a future commit. We don't do it in this commit, to avoid making an even larger diff. By default, clap v3 now colors its help output. However, this does not support custom sections like our examples. Clap is tracking this as https://github.com/clap-rs/clap/issues/3108. In the meantime, disable colors.
Diffstat (limited to 'sq')
-rw-r--r--sq/Cargo.toml5
-rw-r--r--sq/build.rs13
-rw-r--r--sq/src/commands/autocrypt.rs4
-rw-r--r--sq/src/commands/key.rs10
-rw-r--r--sq/src/commands/keyring.rs10
-rw-r--r--sq/src/commands/net.rs10
-rw-r--r--sq/src/commands/revoke.rs6
-rw-r--r--sq/src/sq-usage.rs1154
-rw-r--r--sq/src/sq.rs38
-rw-r--r--sq/src/sq_cli.rs678
10 files changed, 936 insertions, 992 deletions
diff --git a/sq/Cargo.toml b/sq/Cargo.toml
index 2007616d..47f121ea 100644
--- a/sq/Cargo.toml
+++ b/sq/Cargo.toml
@@ -32,7 +32,7 @@ sequoia-autocrypt = { path = "../autocrypt", version = "0.24", default-features
sequoia-net = { path = "../net", version = "0.24", default-features = false }
anyhow = "1.0.18"
chrono = "0.4.10"
-clap = { version = "2.33", features = ["wrap_help"] }
+clap = { version = "3", features = ["derive", "wrap_help"] }
itertools = "0.10"
tempfile = "3.1"
term_size = "0.3"
@@ -40,7 +40,8 @@ tokio = { version = "1.13.1" }
rpassword = "5.0"
[build-dependencies]
-clap = "2.33"
+clap = "3"
+clap_complete = "3"
sequoia-openpgp = { path = "../openpgp", version = "1.0.0", default-features = false }
subplot-build = "0.4.0"
diff --git a/sq/build.rs b/sq/build.rs
index 71399d46..efc13f8d 100644
--- a/sq/build.rs
+++ b/sq/build.rs
@@ -2,7 +2,7 @@ use std::env;
use std::fs;
use std::io::{self, Write};
use std::path::Path;
-use clap::Shell;
+use clap_complete::Shell;
mod sq_cli {
include!("src/sq_cli.rs");
@@ -18,7 +18,7 @@ fn main() {
.expect("failed to generate code with Subplot");
let mut sq = sq_cli::configure(
- clap::App::new("sq").set_term_width(80),
+ clap::Command::new("sq").term_width(80),
cfg!(feature = "autocrypt"),
);
let mut main = fs::File::create("src/sq-usage.rs").unwrap();
@@ -38,14 +38,15 @@ fn main() {
};
fs::create_dir_all(&outdir).unwrap();
let mut sq = sq_cli::build();
+
for shell in &[Shell::Bash, Shell::Fish, Shell::Zsh, Shell::PowerShell,
Shell::Elvish] {
- sq.gen_completions("sq", *shell, &outdir);
- }
+ clap_complete::generate_to(*shell, &mut sq, "sq", &outdir).unwrap();
+ };
}
fn dump_help(sink: &mut dyn io::Write,
- sq: &mut clap::App,
+ sq: &mut clap::Command,
cmd: Vec<String>,
heading: &str)
-> io::Result<()>
@@ -67,7 +68,7 @@ fn dump_help(sink: &mut dyn io::Write,
.chain(std::iter::once("--help"))
.collect::<Vec<_>>();
- let help = sq.get_matches_from_safe_borrow(&args)
+ let help = sq.try_get_matches_from_mut(&args)
.unwrap_err().to_string();
writeln!(sink, "//! ```text")?;
diff --git a/sq/src/commands/autocrypt.rs b/sq/src/commands/autocrypt.rs
index ac852958..8ca018bf 100644
--- a/sq/src/commands/autocrypt.rs
+++ b/sq/src/commands/autocrypt.rs
@@ -15,7 +15,7 @@ use crate::{
pub fn dispatch(config: Config, m: &clap::ArgMatches) -> Result<()> {
match m.subcommand() {
- ("decode", Some(m)) => {
+ Some(("decode", m)) => {
let input = open_or_stdin(m.value_of("input"))?;
let mut output =
config.create_or_stdout_pgp(m.value_of("output"),
@@ -29,7 +29,7 @@ pub fn dispatch(config: Config, m: &clap::ArgMatches) -> Result<()> {
}
output.finalize()?;
},
- ("encode-sender", Some(m)) => {
+ Some(("encode-sender", m)) => {
let input = open_or_stdin(m.value_of("input"))?;
let mut output =
config.create_or_stdout_safe(m.value_of("output"))?;
diff --git a/sq/src/commands/key.rs b/sq/src/commands/key.rs
index aa03f2e1..99e849d9 100644
--- a/sq/src/commands/key.rs
+++ b/sq/src/commands/key.rs
@@ -26,11 +26,11 @@ use crate::decrypt_key;
pub fn dispatch(config: Config, m: &clap::ArgMatches) -> Result<()> {
match m.subcommand() {
- ("generate", Some(m)) => generate(config, m)?,
- ("password", Some(m)) => password(config, m)?,
- ("extract-cert", Some(m)) => extract_cert(config, m)?,
- ("adopt", Some(m)) => adopt(config, m)?,
- ("attest-certifications", Some(m)) =>
+ Some(("generate", m)) => generate(config, m)?,
+ Some(("password", m)) => password(config, m)?,
+ Some(("extract-cert", m)) => extract_cert(config, m)?,
+ Some(("adopt", m)) => adopt(config, m)?,
+ Some(("attest-certifications", m)) =>
attest_certifications(config, m)?,
_ => unreachable!(),
}
diff --git a/sq/src/commands/keyring.rs b/sq/src/commands/keyring.rs
index 0fc2f51a..994c5fab 100644
--- a/sq/src/commands/keyring.rs
+++ b/sq/src/commands/keyring.rs
@@ -33,7 +33,7 @@ use crate::{
pub fn dispatch(config: Config, m: &clap::ArgMatches) -> Result<()> {
match m.subcommand() {
- ("filter", Some(m)) => {
+ Some(("filter", m)) => {
let any_uid_predicates =
m.is_present("userid")
|| m.is_present("name")
@@ -151,7 +151,7 @@ pub fn dispatch(config: Config, m: &clap::ArgMatches) -> Result<()> {
to_certificate)?;
output.finalize()
},
- ("join", Some(m)) => {
+ Some(("join", m)) => {
// XXX: Armor type selection is a bit problematic. If any
// of the certificates contain a secret key, it would be
// better to use Kind::SecretKey here. However, this
@@ -164,7 +164,7 @@ pub fn dispatch(config: Config, m: &clap::ArgMatches) -> Result<()> {
filter(m.values_of("input"), &mut output, Some, false)?;
output.finalize()
},
- ("merge", Some(m)) => {
+ Some(("merge", m)) => {
let mut output =
config.create_or_stdout_pgp(m.value_of("output"),
m.is_present("binary"),
@@ -172,11 +172,11 @@ pub fn dispatch(config: Config, m: &clap::ArgMatches) -> Result<()> {
merge(m.values_of("input"), &mut output)?;
output.finalize()
},
- ("list", Some(m)) => {
+ Some(("list", m)) => {
let mut input = open_or_stdin(m.value_of("input"))?;
list(config, &mut input, m.is_present("all-userids"))
},
- ("split", Some(m)) => {
+ Some(("split", m)) => {
let mut input = open_or_stdin(m.value_of("input"))?;
let prefix =
// The prefix is either specified explicitly...
diff --git a/sq/src/commands/net.rs b/sq/src/commands/net.rs
index 44046ee8..dbd33227 100644
--- a/sq/src/commands/net.rs
+++ b/sq/src/commands/net.rs
@@ -53,7 +53,7 @@ pub fn dispatch_keyserver(config: Config, m: &clap::ArgMatches) -> Result<()> {
.build()?;
match m.subcommand() {
- ("get", Some(m)) => {
+ Some(("get", m)) => {
let query = m.value_of("query").unwrap();
let handle = query.parse::<KeyHandle>();
@@ -83,7 +83,7 @@ pub fn dispatch_keyserver(config: Config, m: &clap::ArgMatches) -> Result<()> {
or an email address: {:?}", query));
}
},
- ("send", Some(m)) => {
+ Some(("send", m)) => {
let mut input = open_or_stdin(m.value_of("input"))?;
let cert = Cert::from_reader(&mut input).
context("Malformed key")?;
@@ -106,7 +106,7 @@ pub fn dispatch_wkd(config: Config, m: &clap::ArgMatches) -> Result<()> {
.build()?;
match m.subcommand() {
- ("url", Some(m)) => {
+ Some(("url", m)) => {
let email_address = m.value_of("input").unwrap();
let wkd_url = wkd::Url::from(email_address)?;
// XXX: Add other subcomand to specify whether it should be
@@ -114,7 +114,7 @@ pub fn dispatch_wkd(config: Config, m: &clap::ArgMatches) -> Result<()> {
let url = wkd_url.to_url(None)?;
println!("{}", url);
},
- ("get", Some(m)) => {
+ Some(("get", m)) => {
// Check that the policy allows https.
network_policy.assert(net::Policy::Encrypted)?;
@@ -137,7 +137,7 @@ pub fn dispatch_wkd(config: Config, m: &clap::ArgMatches) -> Result<()> {
serialize_keyring(&mut output, &certs,
m.is_present("binary"))?;
},
- ("generate", Some(m)) => {
+ Some(("generate", m)) => {
let domain = m.value_of("domain").unwrap();
let skip = m.is_present("skip");
let f = open_or_stdin(m.value_of("input"))?;
diff --git a/sq/src/commands/revoke.rs b/sq/src/commands/revoke.rs
index b863f245..3e020ea0 100644
--- a/sq/src/commands/revoke.rs
+++ b/sq/src/commands/revoke.rs
@@ -47,8 +47,8 @@ impl Subcommand {
pub fn dispatch(config: Config, m: &clap::ArgMatches) -> Result<()> {
let (subcommand, m) = match m.subcommand() {
- ("certificate", Some(m)) => (Subcommand::Certificate, m),
- ("subkey", Some(m)) => {
+ Some(("certificate", m)) => (Subcommand::Certificate, m),
+ Some(("subkey", m)) => {
let subkey = m.value_of("subkey").expect("required");
let kh: KeyHandle = subkey
.parse()
@@ -58,7 +58,7 @@ pub fn dispatch(config: Config, m: &clap::ArgMatches) -> Result<()> {
(Subcommand::Subkey(kh), m)
}
- ("userid", Some(m)) => {
+ Some(("userid", m)) => {
let userid = m.value_of("userid").expect("required");
(Subcommand::UserID(userid.into()), m)
diff --git a/sq/src/sq-usage.rs b/sq/src/sq-usage.rs
index c588c213..66ba9d38 100644
--- a/sq/src/sq-usage.rs
+++ b/sq/src/sq-usage.rs
@@ -18,42 +18,56 @@
//! to refer to OpenPGP keys that do contain secrets.
//!
//! USAGE:
-//! sq [FLAGS] [OPTIONS] <SUBCOMMAND>
+//! sq [OPTIONS] <SUBCOMMAND>
//!
-//! FLAGS:
+//! OPTIONS:
//! -f, --force
//! Overwrites existing files
//!
//! -h, --help
-//! Prints help information
-//!
-//! -V, --version
-//! Prints version information
+//! Print help information
//!
-//!
-//! OPTIONS:
-//! --known-notation <NOTATION>...
+//! --known-notation <NOTATION>
//! Adds NOTATION to the list of known notations. This is used when
//! validating signatures. Signatures that have unknown notations with
//! the critical bit set are considered invalid.
//!
+//! -V, --version
+//! Print version information
+//!
//! SUBCOMMANDS:
-//! encrypt Encrypts a message
-//! decrypt Decrypts a message
-//! sign Signs messages or data files
-//! verify Verifies signed messages or detached signatures
-//! key Manages keys
-//! keyring Manages collections of keys or certs
-//! certify Certifies a User ID for a Certificate
-//! autocrypt Communicates certificates using Autocrypt
-//! keyserver Interacts with keyservers
-//! wkd Interacts with Web Key Directories
-//! armor Converts binary to ASCII
-//! dearmor Converts ASCII to binary
-//! inspect Inspects data, like file(1)
-//! packet Low-level packet manipulation
-//! revoke Generates revocation certificates
-//! help Prints this message or the help of the given subcommand(s)
+//! encrypt
+//! Encrypts a message
+//! decrypt
+//! Decrypts a message
+//! sign
+//! Signs messages or data files
+//! verify
+//! Verifies signed messages or detached signatures
+//! key
+//! Manages keys
+//! keyring
+//! Manages collections of keys or certs
+//! certify
+//! Certifies a User ID for a Certificate
+//! autocrypt
+//! Communicates certificates using Autocrypt
+//! keyserver
+//! Interacts with keyservers
+//! wkd
+//! Interacts with Web Key Directories
+//! armor
+//! Converts binary to ASCII
+//! dearmor
+//! Converts ASCII to binary
+//! inspect
+//! Inspects data, like file(1)
+//! packet
+//! Low-level packet manipulation
+//! revoke
+//! Generates revocation certificates
+//! help
+//! Print this message or the help of the given subcommand(s)
//! ```
//!
//! ## Subcommand encrypt
@@ -67,52 +81,57 @@
//! The converse operation is "sq decrypt".
//!
//! USAGE:
-//! sq encrypt [FLAGS] [OPTIONS] [--] [FILE]
+//! sq encrypt [OPTIONS] [FILE]
+//!
+//! ARGS:
+//! <FILE>
+//! Reads from FILE or stdin if omitted
//!
-//! FLAGS:
+//! OPTIONS:
//! -B, --binary
//! Emits binary data
//!
-//! -h, --help
-//! Prints help information
+//! --compression <KIND>
+//! Selects compression scheme to use
+//!
+//! [default: pad]
+//! [possible values: none, pad, zip, zlib, bzip2]
//!
-//! -s, --symmetric
-//! Adds a password to encrypt with. The message can be decrypted with
-//! either one of the recipient's keys, or any password.
-//! --use-expired-subkey
-//! If a certificate has only expired encryption-capable subkeys, falls
-//! back to using the one that expired last
+//! -h, --help
+//! Print help information
//!
-//! OPTIONS:
-//! --compression <KIND>
-//! Selects compression scheme to use [default: pad] [possible values:
-//! none, pad, zip, zlib, bzip2]
//! --mode <MODE>
//! Selects what kind of keys are considered for encryption. Transport
//! select subkeys marked as suitable for transport encryption, rest
//! selects those for encrypting data at rest, and all selects all
-//! encryption-capable subkeys. [default: all] [possible values:
-//! transport, rest, all]
+//! encryption-capable subkeys.
+//!
+//! [default: all]
+//! [possible values: transport, rest, all]
+//!
//! -o, --output <FILE>
//! Writes to FILE or stdout if omitted
//!
//! --private-key-store <KEY_STORE>
//! Provides parameters for private key store
//!
-//! --recipient-cert <CERT-RING>...
+//! --recipient-cert <CERT-RING>
//! Encrypts for all recipients in CERT-RING
//!
-//! --signer-key <KEY>...
+//! -s, --symmetric
+//! Adds a password to encrypt with. The message can be decrypted with
+//! either one of the recipient's keys, or any password.
+//!
+//! --signer-key <KEY>
//! Signs the message with KEY
//!
//! -t, --time <TIME>
//! Chooses keys valid at the specified time and sets the signature's
//! creation time
//!
-//! ARGS:
-//! <FILE>
-//! Reads from FILE or stdin if omitted
-//!
+//! --use-expired-subkey
+//! If a certificate has only expired encryption-capable subkeys, falls
+//! back to using the one that expired last
//!
//! EXAMPLES:
//!
@@ -150,9 +169,13 @@
//! The converse operation is "sq encrypt".
//!
//! USAGE:
-//! sq decrypt [FLAGS] [OPTIONS] [--] [FILE]
+//! sq decrypt [OPTIONS] [FILE]
+//!
+//! ARGS:
+//! <FILE>
+//! Reads from FILE or stdin if omitted
//!
-//! FLAGS:
+//! OPTIONS:
//! --dump
//! Prints a packet dump to stderr
//!
@@ -160,34 +183,27 @@
//! Prints the session key to stderr
//!
//! -h, --help
-//! Prints help information
-//!
-//! -x, --hex
-//! Prints a hexdump (implies --dump)
+//! Print help information
//!
+//! -n, --signatures <N>
+//! Sets the threshold of valid signatures to N. The message will only
+//! be considered verified if this threshold is reached. [default: 1 if
+//! at least one signer cert file is given, 0 otherwise]
//!
-//! OPTIONS:
//! -o, --output <FILE>
//! Writes to FILE or stdout if omitted
//!
//! --private-key-store <KEY_STORE>
//! Provides parameters for private key store
//!
-//! --recipient-key <KEY>...
+//! --recipient-key <KEY>
//! Decrypts with KEY
//!
-//! --signer-cert <CERT>...
+//! --signer-cert <CERT>
//! Verifies signatures with CERT
//!
-//! -n, --signatures <N>
-//! Sets the threshold of valid signatures to N. The message will only
-//! be considered verified if this threshold is reached. [default: 1 if
-//! at least one signer cert file is given, 0 otherwise]
-//!
-//! ARGS:
-//! <FILE>
-//! Reads from FILE or stdin if omitted
-//!
+//! -x, --hex
+//! Prints a hexdump (implies --dump)
//!
//! EXAMPLES:
//!
@@ -212,9 +228,13 @@
//! The converse operation is "sq verify".
//!
//! USAGE:
-//! sq sign [FLAGS] [OPTIONS] [--] [FILE]
+//! sq sign [OPTIONS] [--] [FILE]
//!
-//! FLAGS:
+//! ARGS:
+//! <FILE>
+//! Reads from FILE or stdin if omitted
+//!
+//! OPTIONS:
//! -a, --append
//! Appends a signature to existing signature
//!
@@ -228,16 +248,14 @@
//! Creates a detached signature
//!
//! -h, --help
-//! Prints help information
-//!
-//! -n, --notarize
-//! Signs a message and all existing signatures
+//! Print help information
//!
-//!
-//! OPTIONS:
//! --merge <SIGNED-MESSAGE>
//! Merges signatures from the input and SIGNED-MESSAGE
//!
+//! -n, --notarize
+//! Signs a message and all existing signatures
+//!
//! --notation <NAME> <VALUE>
//! Adds a notation to the certification. A user-defined notation's
//! name must be of the form "name@a.domain.you.control.org". If the
@@ -245,24 +263,20 @@
//! being critical. If a consumer of a signature doesn't understand a
//! critical notation, then it will ignore the signature. The notation
//! is marked as being human readable.
+//!
//! -o, --output <FILE>
//! Writes to FILE or stdout if omitted
//!
//! --private-key-store <KEY_STORE>
//! Provides parameters for private key store
//!
-//! --signer-key <KEY>...
+//! --signer-key <KEY>
//! Signs using KEY
//!
//! -t, --time <TIME>
//! Chooses keys valid at the specified time and sets the signature's
//! creation time
//!
-//! ARGS:
-//! <FILE>
-//! Reads from FILE or stdin if omitted
-//!
-//!
//! EXAMPLES:
//!
//! # Create a signed message
@@ -294,32 +308,30 @@
//! The converse operation is "sq sign".
//!
//! USAGE:
-//! sq verify [OPTIONS] [--] [FILE]
-//!
-//! FLAGS:
-//! -h, --help
-//! Prints help information
+//! sq verify [OPTIONS] [FILE]
//!
+//! ARGS:
+//! <FILE>
+//! Reads from FILE or stdin if omitted
//!
//! OPTIONS:
//! --detached <SIG>
//! Verifies a detached signature
//!
-//! -o, --output <FILE>
-//! Writes to FILE or stdout if omitted
-//!
-//! --signer-cert <CERT>...
-//! Verifies signatures with CERT
+//! -h, --help
+//! Print help information
//!
//! -n, --signatures <N>
//! Sets the threshold of valid signatures to N. If this threshold is
-//! not reached, the message will not be considered verified. [default:
-//! 1]
+//! not reached, the message will not be considered verified.
+//!
+//! [default: 1]
//!
-//! ARGS:
-//! <FILE>
-//! Reads from FILE or stdin if omitted
+//! -o, --output <FILE>
+//! Writes to FILE or stdout if omitted
//!
+//! --signer-cert <CERT>
+//! Verifies signatures with CERT
//!
//! EXAMPLES:
//!
@@ -351,19 +363,23 @@
//! USAGE:
//! sq key <SUBCOMMAND>
//!
-//! FLAGS:
+//! OPTIONS:
//! -h, --help
-//! Prints help information
-//!
+//! Print help information
//!
//! SUBCOMMANDS:
-//! generate Generates a new key
-//! password Changes password protecting secrets
-//! extract-cert Converts a key to a cert
-//! attest-certifications Attests to third-party certifications
-//! adopt Binds keys from one certificate to another
+//! generate
+//! Generates a new key
+//! password
+//! Changes password protecting secrets
+//! extract-cert
+//! Converts a key to a cert
+//! attest-certifications
+//! Attests to third-party certifications
+//! adopt
+//! Binds keys from one certificate to another
//! help
-//! Prints this message or the help of the given subcommand(s)
+//! Print this message or the help of the given subcommand(s)
//! ```
//!
//! ### Subcommand key generate
@@ -385,12 +401,25 @@
//! uploading it to a keyserver.
//!
//! USAGE:
-//! sq key generate [FLAGS] [OPTIONS] --export <OUTFILE>
+//! sq key generate [OPTIONS] --export <OUTFILE>
+//!
+//! OPTIONS:
+//! -c, --cipher-suite <CIPHER-SUITE>
+//! Selects the cryptographic algorithms for the key
+//!
+//! [default: cv25519]
+//! [possible values: rsa3k, rsa4k, cv25519]
//!
-//! FLAGS:
//! --can-authenticate
//! Adds an authentication-capable subkey (default)
//!
+//! --can-encrypt <PURPOSE>
+//! Adds an encryption-capable subkey. Encryption-capable subkeys can be
+//! marked as suitable for transport encryption, storage encryption, or
+//! both. [default: universal]
+//!
+//! [possible values: transport, storage, universal]
+//!
//! --can-sign
//! Adds a signing-capable subkey (default)
//!
@@ -403,25 +432,6 @@
//! --cannot-sign
//! Adds no signing-capable subkey
//!
-//! -h, --help
-//! Prints help information
-//!
-//! -V, --version
-//! Prints version information
-//!
-//! --with-password
-//! Protects the key with a password
-//!
-//!
-//! OPTIONS:
-//! --can-encrypt <PURPOSE>
-//! Adds an encryption-capable subkey. Encryption-capable subkeys can be
-//! marked as suitable for transport encryption, storage encryption, or
-//! both. [default: universal] [possible values: transport, storage,
-//! universal]
-//! -c, --cipher-suite <CIPHER-SUITE>
-//! Selects the cryptographic algorithms for the key [default: cv25519]
-//! [possible values: rsa3k, rsa4k, cv25519]
//! --creation-time <CREATION_TIME>
//! Sets the key's creation time to TIME. TIME is interpreted as an ISO
//! 8601
@@ -437,21 +447,30 @@
//!
//! $ sq key generate --creation-time 20110609T1938+0200 --export
//! noam.pgp
+//!
+//! -e, --export <OUTFILE>
+//! Writes the key to OUTFILE
+//!
//! --expires <TIME>
//! Makes the key expire at TIME (as ISO 8601). Use "never" to create
//! keys that do not expire.
+//!
//! --expires-in <DURATION>
//! Makes the key expire after DURATION. Either "N[ymwds]", for N years,
//! months, weeks, days, seconds, or "never".
-//! -e, --export <OUTFILE>
-//! Writes the key to OUTFILE
+//!
+//! -h, --help
+//! Print help information
//!
//! --rev-cert <FILE or ->
//! Writes the revocation certificate to FILE. mandatory if OUTFILE is<