From 6cd80f4937c8ac47c460d1ac6a059329b45ea723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=BCtt?= Date: Tue, 4 Oct 2022 10:32:57 +0200 Subject: [PATCH] Update clap, rewrite main CLI logic --- Cargo.lock | 43 +++- lib/cli-compiler/src/commands/compile.rs | 4 +- lib/cli-compiler/src/commands/validate.rs | 2 +- lib/cli-compiler/src/store.rs | 2 +- lib/cli/Cargo.toml | 2 +- lib/cli/src/cli.rs | 242 ++++++---------------- lib/cli/src/commands/compile.rs | 4 +- lib/cli/src/commands/create_exe.rs | 4 +- lib/cli/src/commands/create_obj.rs | 8 +- lib/cli/src/commands/inspect.rs | 2 +- lib/cli/src/commands/run.rs | 2 +- lib/cli/src/commands/run/wasi.rs | 8 +- lib/cli/src/commands/validate.rs | 2 +- lib/cli/src/commands/wast.rs | 2 +- lib/cli/src/compilers/llvm.rs | 6 +- lib/cli/src/store.rs | 2 +- lib/wasi-types-generated/wit-bindgen | 1 - lib/wasi-types/wit-bindgen | 1 + 18 files changed, 126 insertions(+), 211 deletions(-) delete mode 160000 lib/wasi-types-generated/wit-bindgen create mode 160000 lib/wasi-types/wit-bindgen diff --git a/Cargo.lock b/Cargo.lock index 9a2da8f47..4aa3296e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -370,8 +370,8 @@ checksum = "1ed5341b2301a26ab80be5cbdced622e80ed808483c52e45e3310a877d3b37d7" dependencies = [ "atty", "bitflags", - "clap_derive", - "clap_lex", + "clap_derive 3.2.18", + "clap_lex 0.2.4", "indexmap", "once_cell", "strsim 0.10.0", @@ -379,6 +379,21 @@ dependencies = [ "textwrap 0.15.0", ] +[[package]] +name = "clap" +version = "4.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5e0d0fdd7dc774d433c78c9de5695ca04724beaec6a7d4d13ac6014608f3eaf" +dependencies = [ + "atty", + "bitflags", + "clap_derive 4.0.1", + "clap_lex 0.3.0", + "once_cell", + "strsim 0.10.0", + "termcolor", +] + [[package]] name = "clap_derive" version = "3.2.18" @@ -392,6 +407,19 @@ dependencies = [ "syn", ] +[[package]] +name = "clap_derive" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca689d7434ce44517a12a89456b2be4d1ea1cafcd8f581978c03d45f5a5c12a7" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "clap_lex" version = "0.2.4" @@ -401,6 +429,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "cmake" version = "0.1.48" @@ -3079,7 +3116,7 @@ dependencies = [ "atty", "bytesize", "cfg-if 1.0.0", - "clap 3.2.21", + "clap 4.0.5", "colored 2.0.0", "dirs", "distance", diff --git a/lib/cli-compiler/src/commands/compile.rs b/lib/cli-compiler/src/commands/compile.rs index bcffabff5..a98c472a0 100644 --- a/lib/cli-compiler/src/commands/compile.rs +++ b/lib/cli-compiler/src/commands/compile.rs @@ -14,11 +14,11 @@ use wasmer_types::{ /// The options for the `wasmer compile` subcommand pub struct Compile { /// Input file - #[clap(name = "FILE", parse(from_os_str))] + #[clap(name = "FILE", value_parser = clap::value_parser!(std::ffi::OsString))] path: PathBuf, /// Output file - #[clap(name = "OUTPUT PATH", short = 'o', parse(from_os_str))] + #[clap(name = "OUTPUT PATH", short = 'o', value_parser = clap::value_parser!(std::ffi::OsString)))] output: PathBuf, /// Compilation Target triple diff --git a/lib/cli-compiler/src/commands/validate.rs b/lib/cli-compiler/src/commands/validate.rs index e6d832d10..3dd464582 100644 --- a/lib/cli-compiler/src/commands/validate.rs +++ b/lib/cli-compiler/src/commands/validate.rs @@ -9,7 +9,7 @@ use wasmer_types::{is_wasm, CpuFeature, Target, Triple}; /// The options for the `wasmer validate` subcommand pub struct Validate { /// File to validate as WebAssembly - #[clap(name = "FILE", parse(from_os_str))] + #[clap(name = "FILE", value_parser = clap::value_parser!(std::ffi::OsString))] path: PathBuf, #[clap(flatten)] diff --git a/lib/cli-compiler/src/store.rs b/lib/cli-compiler/src/store.rs index 0411798f5..e7bd2b3cb 100644 --- a/lib/cli-compiler/src/store.rs +++ b/lib/cli-compiler/src/store.rs @@ -115,7 +115,7 @@ pub struct CompilerOptions { /// LLVM debug directory, where IR and object files will be written to. #[allow(unused)] #[cfg(feature = "llvm")] - #[cfg_attr(feature = "llvm", clap(long, parse(from_os_str)))] + #[cfg_attr(feature = "llvm", clap(long, value_parser = clap::value_parser!(std::ffi::OsString)))] llvm_debug_dir: Option, #[clap(flatten)] diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index f26d91ef2..45ce77760 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -42,7 +42,7 @@ wasmer-vfs = { version = "=3.0.0-beta.2", path = "../vfs", default-features = f atty = "0.2" colored = "2.0" anyhow = "1.0" -clap = { version = "3.1", features = ["derive"] } +clap = { version = "4.0.5", features = ["derive"] } # For the function names autosuggestion distance = "0.4" # For the inspect subcommand diff --git a/lib/cli/src/cli.rs b/lib/cli/src/cli.rs index 8a5972fd0..9e56d8a0a 100644 --- a/lib/cli/src/cli.rs +++ b/lib/cli/src/cli.rs @@ -14,195 +14,73 @@ use crate::commands::{Cache, Config, Inspect, Run, SelfUpdate, Validate}; use crate::error::PrettyError; use anyhow::Result; -use clap::{ErrorKind, Parser}; - -#[derive(Parser)] -#[cfg_attr( - not(feature = "headless"), - clap( - name = "wasmer", - about = "WebAssembly standalone runtime.", - version, - author - ) -)] -#[cfg_attr( - feature = "headless", - clap( - name = "wasmer-headless", - about = "WebAssembly standalone runtime (headless).", - version, - author - ) -)] -/// The options for the wasmer Command Line Interface -enum WasmerCLIOptions { - /// Run a WebAssembly file. Formats accepted: wasm, wat - #[clap(name = "run")] - Run(Run), - - /// Wasmer cache - #[clap(subcommand, name = "cache")] - Cache(Cache), - - /// Validate a WebAssembly binary - #[clap(name = "validate")] - Validate(Validate), - - /// Compile a WebAssembly binary - #[cfg(feature = "compiler")] - #[clap(name = "compile")] - Compile(Compile), - - /// Compile a WebAssembly binary into a native executable - /// - /// To use, you need to set the `WASMER_DIR` environment variable - /// to the location of your Wasmer installation. This will probably be `~/.wasmer`. It - /// should include a `lib`, `include` and `bin` subdirectories. To create an executable - /// you will need `libwasmer`, so by setting `WASMER_DIR` the CLI knows where to look for - /// header files and libraries. - /// - /// Example usage: - /// - /// ```text - /// $ # in two lines: - /// $ export WASMER_DIR=/home/user/.wasmer/ - /// $ wasmer create-exe qjs.wasm -o qjs.exe # or in one line: - /// $ WASMER_DIR=/home/user/.wasmer/ wasmer create-exe qjs.wasm -o qjs.exe - /// $ file qjs.exe - /// qjs.exe: ELF 64-bit LSB pie executable, x86-64 ... - /// ``` - /// - /// ## Cross-compilation - /// - /// Accepted target triple values must follow the - /// ['target_lexicon'](https://crates.io/crates/target-lexicon) crate format. - /// - /// The recommended targets we try to support are: - /// - /// - "x86_64-linux-gnu" - /// - "aarch64-linux-gnu" - /// - "x86_64-apple-darwin" - /// - "arm64-apple-darwin" - #[cfg(any(feature = "static-artifact-create", feature = "wasmer-artifact-create"))] - #[clap(name = "create-exe", verbatim_doc_comment)] - CreateExe(CreateExe), - - /// Compile a WebAssembly binary into an object file - /// - /// To use, you need to set the `WASMER_DIR` environment variable to the location of your - /// Wasmer installation. This will probably be `~/.wasmer`. It should include a `lib`, - /// `include` and `bin` subdirectories. To create an object you will need `libwasmer`, so by - /// setting `WASMER_DIR` the CLI knows where to look for header files and libraries. - /// - /// Example usage: - /// - /// ```text - /// $ # in two lines: - /// $ export WASMER_DIR=/home/user/.wasmer/ - /// $ wasmer create-obj qjs.wasm --object-format symbols -o qjs.obj # or in one line: - /// $ WASMER_DIR=/home/user/.wasmer/ wasmer create-exe qjs.wasm --object-format symbols -o qjs.obj - /// $ file qjs.obj - /// qjs.obj: ELF 64-bit LSB relocatable, x86-64 ... - /// ``` - /// - /// ## Cross-compilation - /// - /// Accepted target triple values must follow the - /// ['target_lexicon'](https://crates.io/crates/target-lexicon) crate format. - /// - /// The recommended targets we try to support are: - /// - /// - "x86_64-linux-gnu" - /// - "aarch64-linux-gnu" - /// - "x86_64-apple-darwin" - /// - "arm64-apple-darwin" - #[cfg(feature = "static-artifact-create")] - #[structopt(name = "create-obj", verbatim_doc_comment)] - CreateObj(CreateObj), - - /// Get various configuration information needed - /// to compile programs which use Wasmer - #[clap(name = "config")] - Config(Config), - - /// Update wasmer to the latest version - #[clap(name = "self-update")] - SelfUpdate(SelfUpdate), - - /// Inspect a WebAssembly file - #[clap(name = "inspect")] - Inspect(Inspect), - - /// Run spec testsuite - #[cfg(feature = "wast")] - #[clap(name = "wast")] - Wast(Wast), - - /// Unregister and/or register wasmer as binfmt interpreter - #[cfg(target_os = "linux")] - #[clap(name = "binfmt")] - Binfmt(Binfmt), -} - -impl WasmerCLIOptions { - fn execute(&self) -> Result<()> { - match self { - Self::Run(options) => options.execute(), - Self::SelfUpdate(options) => options.execute(), - Self::Cache(cache) => cache.execute(), - Self::Validate(validate) => validate.execute(), - #[cfg(feature = "compiler")] - Self::Compile(compile) => compile.execute(), - #[cfg(any(feature = "static-artifact-create", feature = "wasmer-artifact-create"))] - Self::CreateExe(create_exe) => create_exe.execute(), - #[cfg(feature = "static-artifact-create")] - Self::CreateObj(create_obj) => create_obj.execute(), - Self::Config(config) => config.execute(), - Self::Inspect(inspect) => inspect.execute(), - #[cfg(feature = "wast")] - Self::Wast(wast) => wast.execute(), - #[cfg(target_os = "linux")] - Self::Binfmt(binfmt) => binfmt.execute(), - } - } -} - /// The main function for the Wasmer CLI tool. pub fn wasmer_main() { // We allow windows to print properly colors #[cfg(windows)] colored::control::set_virtual_terminal(true).unwrap(); - // We try to run wasmer with the normal arguments. - // Eg. `wasmer ` - // In case that fails, we fallback trying the Run subcommand directly. - // Eg. `wasmer myfile.wasm --dir=.` - // - // In case we've been run as wasmer-binfmt-interpreter myfile.wasm args, - // we assume that we're registered via binfmt_misc + let cmd_output = parse_cli_args(); + + PrettyError::report(cmd_output); +} + +fn parse_cli_args() -> Result<(), anyhow::Error> { + let args = std::env::args().collect::>(); let binpath = args.get(0).map(|s| s.as_ref()).unwrap_or(""); - let command = args.get(1); - let options = if cfg!(target_os = "linux") && binpath.ends_with("wasmer-binfmt-interpreter") { - WasmerCLIOptions::Run(Run::from_binfmt_args()) - } else { - match command.unwrap_or(&"".to_string()).as_ref() { - "cache" | "compile" | "config" | "create-exe" | "help" | "inspect" | "run" - | "self-update" | "validate" | "wast" | "binfmt" => WasmerCLIOptions::parse(), - _ => { - WasmerCLIOptions::try_parse_from(args.iter()).unwrap_or_else(|e| { - match e.kind() { - // This fixes a issue that: - // 1. Shows the version twice when doing `wasmer -V` - // 2. Shows the run help (instead of normal help) when doing `wasmer --help` - ErrorKind::DisplayVersion | ErrorKind::DisplayHelp => e.exit(), - _ => WasmerCLIOptions::Run(Run::parse()), - } - }) - } - } - }; - PrettyError::report(options.execute()); + // In case we've been run as wasmer-binfmt-interpreter myfile.wasm args, + // we assume that we're registered via binfmt_misc + if cfg!(target_os = "linux") && binpath.ends_with("wasmer-binfmt-interpreter") { + return Run::from_binfmt_args().execute(); + } + + match (args.get(1).map(|s| s.as_str()), args.get(2).map(|s| s.as_str())) { + (None, _) | + (Some("help"), _) | + (Some("--help"), _) => return print_help(), + + (Some("-vV"), _) | + (Some("version"), Some("--verbose")) | + (Some("--version"), Some("--verbose")) => return print_version(false), + + (Some("-v"), _) | + (Some("version"), _) | + (Some("--version"), _) => return print_version(false), + + (Some("cache"), Some(_)) | + (Some("compile"), Some(_)) | + (Some("config"), Some(_)) | + (Some("create-exe"), Some(_)) | + (Some("inspect"), Some(_)) | + (Some("self-update"), _) | + (Some("validate"), Some(_)) | + (Some("wast"), Some(_)) | + (Some("binfmt"), Some(_)) => { + println!("running {:?}", args.get(1)); + return Ok(()) + }, + (Some("run"), Some(_)) | + (Some(_), _) => { + use clap::Parser; + // wasmer run file + // wasmer run [package] + if let Ok(run) = Run::try_parse() { + return run.execute(); + } else { + return print_help(); + } + }, + } } + +fn print_help() -> Result<(), anyhow::Error>{ + println!("help"); + Ok(()) +} + +fn print_version(_: bool) -> Result<(), anyhow::Error> { + println!("version"); + Ok(()) +} \ No newline at end of file diff --git a/lib/cli/src/commands/compile.rs b/lib/cli/src/commands/compile.rs index d6be43411..dd21e5398 100644 --- a/lib/cli/src/commands/compile.rs +++ b/lib/cli/src/commands/compile.rs @@ -9,11 +9,11 @@ use wasmer::*; /// The options for the `wasmer compile` subcommand pub struct Compile { /// Input file - #[clap(name = "FILE", parse(from_os_str))] + #[clap(name = "FILE", value_parser = clap::value_parser!(std::ffi::OsString))] path: PathBuf, /// Output file - #[clap(name = "OUTPUT PATH", short = 'o', parse(from_os_str))] + #[clap(name = "OUTPUT PATH", short = 'o', value_parser = clap::value_parser!(std::ffi::OsString))] output: PathBuf, /// Compilation Target triple diff --git a/lib/cli/src/commands/create_exe.rs b/lib/cli/src/commands/create_exe.rs index a3b51f083..0f1dff2c5 100644 --- a/lib/cli/src/commands/create_exe.rs +++ b/lib/cli/src/commands/create_exe.rs @@ -46,11 +46,11 @@ struct CrossCompileSetup { /// The options for the `wasmer create-exe` subcommand pub struct CreateExe { /// Input file - #[clap(name = "FILE", parse(from_os_str))] + #[clap(name = "FILE", value_parser = clap::value_parser!(std::ffi::OsString))] path: PathBuf, /// Output file - #[clap(name = "OUTPUT PATH", short = 'o', parse(from_os_str))] + #[clap(name = "OUTPUT PATH", short = 'o', value_parser = clap::value_parser!(std::ffi::OsString))] output: PathBuf, /// Compilation Target triple diff --git a/lib/cli/src/commands/create_obj.rs b/lib/cli/src/commands/create_obj.rs index 79995fd6f..f86db8418 100644 --- a/lib/cli/src/commands/create_obj.rs +++ b/lib/cli/src/commands/create_obj.rs @@ -19,18 +19,18 @@ const WASMER_SERIALIZED_HEADER: &[u8] = include_bytes!("wasmer_deserialize_modul /// The options for the `wasmer create-exe` subcommand pub struct CreateObj { /// Input file - #[clap(name = "FILE", parse(from_os_str))] + #[clap(name = "FILE", value_parser = clap::value_parser!(std::ffi::OsString))] path: PathBuf, /// Output file - #[clap(name = "OUTPUT_PATH", short = 'o', parse(from_os_str))] + #[clap(name = "OUTPUT_PATH", short = 'o', value_parser = clap::value_parser!(std::ffi::OsString))] output: PathBuf, /// Header output file #[clap( name = "OUTPUT_HEADER_PATH", long = "output-header-path", - parse(from_os_str) + value_parser = clap::value_parser!(std::ffi::OsString) )] header_output: Option, @@ -56,7 +56,7 @@ pub struct CreateObj { #[clap(name = "OBJECT_FORMAT", long = "object-format", verbatim_doc_comment)] object_format: Option, - #[clap(short = 'm', multiple = true, number_of_values = 1)] + #[clap(short = 'm', number_of_values = 1)] cpu_features: Vec, #[clap(flatten)] diff --git a/lib/cli/src/commands/inspect.rs b/lib/cli/src/commands/inspect.rs index 4d56faa61..461e20e27 100644 --- a/lib/cli/src/commands/inspect.rs +++ b/lib/cli/src/commands/inspect.rs @@ -9,7 +9,7 @@ use wasmer::*; /// The options for the `wasmer validate` subcommand pub struct Inspect { /// File to validate as WebAssembly - #[clap(name = "FILE", parse(from_os_str))] + #[clap(name = "FILE", value_parser = clap::value_parser!(std::ffi::OsString))] path: PathBuf, #[clap(flatten)] diff --git a/lib/cli/src/commands/run.rs b/lib/cli/src/commands/run.rs index c6e0fde6e..965a35985 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -30,7 +30,7 @@ pub struct Run { disable_cache: bool, /// File to run - #[clap(name = "FILE", parse(from_os_str))] + #[clap(name = "FILE", value_parser = clap::value_parser!(std::ffi::OsString))] path: PathBuf, /// Invoke a specified function diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index 2fd31666b..37c64473a 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -18,18 +18,18 @@ pub struct Wasi { pre_opened_directories: Vec, /// Map a host directory to a different location for the Wasm module - #[clap( + #[arg( long = "mapdir", name = "GUEST_DIR:HOST_DIR", - parse(try_from_str = parse_mapdir), + value_parser = parse_mapdir, )] mapped_dirs: Vec<(String, PathBuf)>, /// Pass custom environment variables - #[clap( + #[arg( long = "env", name = "KEY=VALUE", - parse(try_from_str = parse_envvar), + value_parser = parse_envvar, )] env_vars: Vec<(String, String)>, diff --git a/lib/cli/src/commands/validate.rs b/lib/cli/src/commands/validate.rs index 4f620ecc3..a1baf49ba 100644 --- a/lib/cli/src/commands/validate.rs +++ b/lib/cli/src/commands/validate.rs @@ -8,7 +8,7 @@ use wasmer::*; /// The options for the `wasmer validate` subcommand pub struct Validate { /// File to validate as WebAssembly - #[clap(name = "FILE", parse(from_os_str))] + #[clap(name = "FILE", value_parser = clap::value_parser!(std::ffi::OsString))] path: PathBuf, #[clap(flatten)] diff --git a/lib/cli/src/commands/wast.rs b/lib/cli/src/commands/wast.rs index 5064a94c8..c8d62d518 100644 --- a/lib/cli/src/commands/wast.rs +++ b/lib/cli/src/commands/wast.rs @@ -9,7 +9,7 @@ use wasmer_wast::Wast as WastSpectest; /// The options for the `wasmer wast` subcommand pub struct Wast { /// Wast file to run - #[clap(name = "FILE", parse(from_os_str))] + #[clap(name = "FILE", value_parser = clap::value_parser!(std::ffi::OsString))] path: PathBuf, #[clap(flatten)] diff --git a/lib/cli/src/compilers/llvm.rs b/lib/cli/src/compilers/llvm.rs index b7a7a95e4..fd312a1fd 100644 --- a/lib/cli/src/compilers/llvm.rs +++ b/lib/cli/src/compilers/llvm.rs @@ -2,15 +2,15 @@ /// LLVM backend flags. pub struct LLVMCLIOptions { /// Emit LLVM IR before optimization pipeline. - #[clap(long = "llvm-pre-opt-ir", parse(from_os_str))] + #[clap(long = "llvm-pre-opt-ir", value_parser = clap::value_parser!(std::ffi::OsString))] pre_opt_ir: Option, /// Emit LLVM IR after optimization pipeline. - #[clap(long = "llvm-post-opt-ir", parse(from_os_str))] + #[clap(long = "llvm-post-opt-ir", value_parser = clap::value_parser!(std::ffi::OsString))] post_opt_ir: Option, /// Emit LLVM generated native code object file. - #[clap(long = "llvm-object-file", parse(from_os_str))] + #[clap(long = "llvm-object-file", value_parser = clap::value_parser!(std::ffi::OsString))] obj_file: Option, } diff --git a/lib/cli/src/store.rs b/lib/cli/src/store.rs index 49b897c7b..76ee227e2 100644 --- a/lib/cli/src/store.rs +++ b/lib/cli/src/store.rs @@ -47,7 +47,7 @@ pub struct CompilerOptions { /// LLVM debug directory, where IR and object files will be written to. #[cfg(feature = "llvm")] - #[clap(long, parse(from_os_str))] + #[clap(long, value_parser = clap::value_parser!(std::ffi::OsString))] llvm_debug_dir: Option, #[clap(flatten)] diff --git a/lib/wasi-types-generated/wit-bindgen b/lib/wasi-types-generated/wit-bindgen deleted file mode 160000 index 095d295be..000000000 --- a/lib/wasi-types-generated/wit-bindgen +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 095d295be6392259924e48488af188d3ed3e4102 diff --git a/lib/wasi-types/wit-bindgen b/lib/wasi-types/wit-bindgen new file mode 160000 index 000000000..44a2bf814 --- /dev/null +++ b/lib/wasi-types/wit-bindgen @@ -0,0 +1 @@ +Subproject commit 44a2bf8148932590479bd64b9f90502b14c3b0d3