From 296ee164fe55d41c070af95c2a18c5cc0f0aa433 Mon Sep 17 00:00:00 2001 From: Edoardo Marangoni Date: Tue, 14 May 2024 13:52:15 +0200 Subject: [PATCH 1/2] feat(cli): Add subcommands to generate completion scripts and manpages --- Cargo.lock | 27 ++++++++++++++++++++ lib/cli/Cargo.toml | 3 +++ lib/cli/src/commands/app/delete.rs | 2 +- lib/cli/src/commands/app/get.rs | 2 +- lib/cli/src/commands/app/list.rs | 2 +- lib/cli/src/commands/app/logs.rs | 2 +- lib/cli/src/commands/gen_completions.rs | 34 +++++++++++++++++++++++++ lib/cli/src/commands/gen_manpage.rs | 23 +++++++++++++++++ lib/cli/src/commands/mod.rs | 14 +++++++++- lib/cli/src/commands/package/publish.rs | 1 - lib/cli/src/commands/package/push.rs | 4 --- lib/cli/src/commands/run/mod.rs | 2 +- 12 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 lib/cli/src/commands/gen_completions.rs create mode 100644 lib/cli/src/commands/gen_manpage.rs diff --git a/Cargo.lock b/Cargo.lock index e3466dbf0d8..7c505068ff1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -608,6 +608,15 @@ dependencies = [ "strsim", ] +[[package]] +name = "clap_complete" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" +dependencies = [ + "clap", +] + [[package]] name = "clap_derive" version = "4.4.7" @@ -626,6 +635,16 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +[[package]] +name = "clap_mangen" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1dd95b5ebb5c1c54581dd6346f3ed6a79a3eef95dd372fc2ac13d535535300e" +dependencies = [ + "clap", + "roff", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -4033,6 +4052,12 @@ dependencies = [ "serde", ] +[[package]] +name = "roff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" + [[package]] name = "rpassword" version = "7.3.1" @@ -6470,6 +6495,8 @@ dependencies = [ "cfg-if 1.0.0", "chrono", "clap", + "clap_complete", + "clap_mangen", "colored 2.1.0", "comfy-table", "dialoguer", diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index 69bd5414b2b..d05a362d3ab 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -227,6 +227,9 @@ tokio-tungstenite = { version = "0.20.1", features = [ mac_address = { version = "1.1.5", optional = true } tun-tap = { version = "0.1.3", features = ["tokio"], optional = true } +clap_complete = "4.5.2" +clap_mangen = "0.2.20" + # NOTE: Must use different features for clap because the "color" feature does not # work on wasi due to the anstream dependency not compiling. [target.'cfg(not(target_family = "wasm"))'.dependencies] diff --git a/lib/cli/src/commands/app/delete.rs b/lib/cli/src/commands/app/delete.rs index a92f5bb991e..58b7bd445ce 100644 --- a/lib/cli/src/commands/app/delete.rs +++ b/lib/cli/src/commands/app/delete.rs @@ -6,7 +6,7 @@ use is_terminal::IsTerminal; use super::util::AppIdentOpts; use crate::{commands::AsyncCliCommand, opts::ApiOpts}; -/// Show an app. +/// Delete an existing Edge app #[derive(clap::Parser, Debug)] pub struct CmdAppDelete { #[clap(flatten)] diff --git a/lib/cli/src/commands/app/get.rs b/lib/cli/src/commands/app/get.rs index 5c1663652c4..c3e32d9c3fd 100644 --- a/lib/cli/src/commands/app/get.rs +++ b/lib/cli/src/commands/app/get.rs @@ -8,7 +8,7 @@ use crate::{ opts::{ApiOpts, ItemFormatOpts}, }; -/// Show an app. +/// Retrieve detailed informations about an app #[derive(clap::Parser, Debug)] pub struct CmdAppGet { #[clap(flatten)] diff --git a/lib/cli/src/commands/app/list.rs b/lib/cli/src/commands/app/list.rs index 053879e5ad4..86acc4601b8 100644 --- a/lib/cli/src/commands/app/list.rs +++ b/lib/cli/src/commands/app/list.rs @@ -10,7 +10,7 @@ use crate::{ opts::{ApiOpts, ListFormatOpts}, }; -/// List apps. +/// List apps belonging to a namespace #[derive(clap::Parser, Debug)] pub struct CmdAppList { #[clap(flatten)] diff --git a/lib/cli/src/commands/app/logs.rs b/lib/cli/src/commands/app/logs.rs index d6792ad0266..db2e0681713 100644 --- a/lib/cli/src/commands/app/logs.rs +++ b/lib/cli/src/commands/app/logs.rs @@ -17,7 +17,7 @@ pub enum LogStreamArg { Stderr, } -/// Show an app. +/// Retrieve the logs of an app #[derive(clap::Parser, Debug)] pub struct CmdAppLogs { #[clap(flatten)] diff --git a/lib/cli/src/commands/gen_completions.rs b/lib/cli/src/commands/gen_completions.rs new file mode 100644 index 00000000000..271c704a79c --- /dev/null +++ b/lib/cli/src/commands/gen_completions.rs @@ -0,0 +1,34 @@ +use super::WasmerCmd; +use clap::CommandFactory; +use clap_complete::{generate, Shell}; +use std::fs::OpenOptions; + +#[derive(Debug, Clone, clap::Parser)] +pub struct CmdGenCompletions { + /// The shell to generate the autocompletions script for. + pub shell: Shell, + + /// Where to store the generated file(s) to. Defaults to stdout. + #[clap(long)] + pub out: Option, +} + +impl CmdGenCompletions { + pub fn execute(&self) -> anyhow::Result<()> { + let mut cmd = WasmerCmd::command(); + + let name = cmd.get_name().to_string(); + if let Some(out) = &self.out { + let mut f = OpenOptions::new() + .truncate(true) + .create(true) + .write(true) + .open(out)?; + generate(self.shell, &mut cmd, name, &mut f); + Ok(()) + } else { + generate(self.shell, &mut cmd, name, &mut std::io::stdout()); + Ok(()) + } + } +} diff --git a/lib/cli/src/commands/gen_manpage.rs b/lib/cli/src/commands/gen_manpage.rs new file mode 100644 index 00000000000..e09f440828d --- /dev/null +++ b/lib/cli/src/commands/gen_manpage.rs @@ -0,0 +1,23 @@ +use super::WasmerCmd; +use anyhow::Context; +use clap::CommandFactory; +use clap_mangen::generate_to; + +#[derive(Debug, Clone, clap::Parser)] +pub struct CmdGenManPage { + /// Where to store the generated file(s) to. + #[clap(long)] + pub out: Option, +} + +impl CmdGenManPage { + pub fn execute(&self) -> anyhow::Result<()> { + let cmd = WasmerCmd::command(); + let outpath = if let Some(out) = &self.out { + out.clone() + } else { + "~/.local/share/man".to_string() + }; + generate_to(cmd, &outpath).context(format!("While generating the man page(s) to {outpath}")) + } +} diff --git a/lib/cli/src/commands/mod.rs b/lib/cli/src/commands/mod.rs index ca1ad56defb..c670b2c616a 100644 --- a/lib/cli/src/commands/mod.rs +++ b/lib/cli/src/commands/mod.rs @@ -16,6 +16,8 @@ mod create_obj; pub(crate) mod domain; #[cfg(feature = "static-artifact-create")] mod gen_c_header; +mod gen_completions; +mod gen_manpage; mod init; mod inspect; #[cfg(feature = "journal")] @@ -115,6 +117,8 @@ impl WasmerCmd { } match cmd { + Some(Cmd::GenManPage(cmd)) => cmd.execute(), + Some(Cmd::GenCompletions(cmd)) => cmd.execute(), Some(Cmd::Run(options)) => options.execute(output), Some(Cmd::SelfUpdate(options)) => options.execute(), Some(Cmd::Cache(cache)) => cache.execute(), @@ -220,7 +224,7 @@ enum Cmd { #[clap(name = "publish")] Publish(crate::commands::package::publish::PackagePublish), - /// Wasmer cache + /// Manage the local Wasmer cache Cache(Cache), /// Validate a WebAssembly binary @@ -363,6 +367,14 @@ enum Cmd { /// Manage DNS records #[clap(subcommand, alias = "domains")] Domain(crate::commands::domain::CmdDomain), + + /// Generate autocompletion for different shells + #[clap(name = "gen-completions")] + GenCompletions(crate::commands::gen_completions::CmdGenCompletions), + + /// Generate man pages + #[clap(name = "gen-man")] + GenManPage(crate::commands::gen_manpage::CmdGenManPage), } fn is_binfmt_interpreter() -> bool { diff --git a/lib/cli/src/commands/package/publish.rs b/lib/cli/src/commands/package/publish.rs index e5e27bccfc0..0a2a23867f0 100644 --- a/lib/cli/src/commands/package/publish.rs +++ b/lib/cli/src/commands/package/publish.rs @@ -97,7 +97,6 @@ impl PackagePublish { quiet: self.quiet, package_namespace: self.package_namespace.clone(), timeout: self.timeout, - bump: self.bump, non_interactive: self.non_interactive, wait: self.wait, package_path: self.package_path.clone(), diff --git a/lib/cli/src/commands/package/push.rs b/lib/cli/src/commands/package/push.rs index 59d9c413cab..10303dc5d83 100644 --- a/lib/cli/src/commands/package/push.rs +++ b/lib/cli/src/commands/package/push.rs @@ -41,10 +41,6 @@ pub struct PackagePush { #[clap(long, default_value = "5m")] pub timeout: humantime::Duration, - /// Whether or not the patch field of the version of the package - if any - should be bumped. - #[clap(long, conflicts_with = "version")] - pub bump: bool, - /// Do not prompt for user input. #[clap(long, default_value_t = !std::io::stdin().is_terminal())] pub non_interactive: bool, diff --git a/lib/cli/src/commands/run/mod.rs b/lib/cli/src/commands/run/mod.rs index bfe988ddbea..eac19537da7 100644 --- a/lib/cli/src/commands/run/mod.rs +++ b/lib/cli/src/commands/run/mod.rs @@ -79,7 +79,7 @@ pub struct Run { #[clap(short, long, aliases = &["command", "invoke", "command-name"])] entrypoint: Option, /// Generate a coredump at this path if a WebAssembly trap occurs - #[clap(name = "COREDUMP PATH", long)] + #[clap(name = "COREDUMP_PATH", long)] coredump_on_trap: Option, /// The file, URL, or package to run. #[clap(value_parser = PackageSource::infer)] From ae43c8f30faa2c6e9c3c54907242f5606707d9c7 Mon Sep 17 00:00:00 2001 From: Edoardo Marangoni Date: Tue, 14 May 2024 15:26:01 +0200 Subject: [PATCH 2/2] feat(cli): Hide the gen-man command from help, different default value for man dir --- lib/cli/Cargo.toml | 2 +- lib/cli/src/commands/gen_manpage.rs | 19 +++++++++++-------- lib/cli/src/commands/mod.rs | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index d05a362d3ab..b918d8018f4 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -169,7 +169,7 @@ bytesize = "1.0" cfg-if = "1.0" tempfile = "3.6.0" serde = { version = "1.0.147", features = ["derive"] } -dirs = { version = "4.0" } +dirs = "4.0" serde_json = { version = "1.0" } target-lexicon = { version = "0.12", features = ["std"] } wasmer-config = { version = "0.2.0", path = "../config" } diff --git a/lib/cli/src/commands/gen_manpage.rs b/lib/cli/src/commands/gen_manpage.rs index e09f440828d..d82b9dd2714 100644 --- a/lib/cli/src/commands/gen_manpage.rs +++ b/lib/cli/src/commands/gen_manpage.rs @@ -2,22 +2,25 @@ use super::WasmerCmd; use anyhow::Context; use clap::CommandFactory; use clap_mangen::generate_to; +use std::path::PathBuf; + +lazy_static::lazy_static! { + static ref DEFAULT_MAN_DIR_PATH: PathBuf = dirs::data_dir().unwrap_or_default().join("man"); +} #[derive(Debug, Clone, clap::Parser)] pub struct CmdGenManPage { /// Where to store the generated file(s) to. - #[clap(long)] - pub out: Option, + #[clap(long, default_value = DEFAULT_MAN_DIR_PATH.as_os_str())] + pub out: PathBuf, } impl CmdGenManPage { pub fn execute(&self) -> anyhow::Result<()> { let cmd = WasmerCmd::command(); - let outpath = if let Some(out) = &self.out { - out.clone() - } else { - "~/.local/share/man".to_string() - }; - generate_to(cmd, &outpath).context(format!("While generating the man page(s) to {outpath}")) + generate_to(cmd, &self.out).context(format!( + "While generating the man page(s) to {}", + self.out.display() + )) } } diff --git a/lib/cli/src/commands/mod.rs b/lib/cli/src/commands/mod.rs index c670b2c616a..acf7a50833b 100644 --- a/lib/cli/src/commands/mod.rs +++ b/lib/cli/src/commands/mod.rs @@ -373,7 +373,7 @@ enum Cmd { GenCompletions(crate::commands::gen_completions::CmdGenCompletions), /// Generate man pages - #[clap(name = "gen-man")] + #[clap(name = "gen-man", hide = true)] GenManPage(crate::commands::gen_manpage::CmdGenManPage), }