From 3298a6adf10cd0f4807bbcd6ce93c39af336779f Mon Sep 17 00:00:00 2001 From: doug-q <141026920+doug-q@users.noreply.github.com> Date: Wed, 29 May 2024 10:43:09 +0100 Subject: [PATCH] feat(cli): Add verbosity, return `Hugr` from `run`. (#1116) --- Cargo.toml | 3 ++- hugr-cli/Cargo.toml | 3 ++- hugr-cli/src/lib.rs | 26 ++++++++++++++++++++------ hugr/src/main.rs | 6 ++++-- hugr/tests/cli.rs | 22 ++++++++++++++++++++-- 5 files changed, 48 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54fed82da..8330b6447 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,9 +57,10 @@ typetag = "0.2.7" urlencoding = "2.1.2" webbrowser = "1.0.0" clap = { version = "4.5.4"} +clap-stdin = "0.4.0" +clap-verbosity-flag = "2.2.0" assert_cmd = "2.0.14" assert_fs = "1.1.1" -clap-stdin = "0.4.0" predicates = "3.1.0" [profile.dev.package] diff --git a/hugr-cli/Cargo.toml b/hugr-cli/Cargo.toml index 067a08a67..90f71e362 100644 --- a/hugr-cli/Cargo.toml +++ b/hugr-cli/Cargo.toml @@ -15,7 +15,8 @@ categories = ["compilers"] [dependencies] clap = {workspace = true, features = ["derive"]} -clap-stdin = { workspace = true } +clap-stdin.workspace = true +clap-verbosity-flag.workspace = true hugr-core = { path = "../hugr-core", version = "0.0.0" } serde_json.workspace = true thiserror.workspace = true diff --git a/hugr-cli/src/lib.rs b/hugr-cli/src/lib.rs index 421a900fa..07982b589 100644 --- a/hugr-cli/src/lib.rs +++ b/hugr-cli/src/lib.rs @@ -1,13 +1,18 @@ //! Standard command line tools, used by the hugr binary. -pub use clap::Parser; use clap_stdin::FileOrStdin; -use hugr_core::{extension::ExtensionRegistry, Hugr, HugrView}; +use clap_verbosity_flag::{InfoLevel, Verbosity}; use thiserror::Error; +/// We reexport some clap types that are used in the public API. +pub use {clap::Parser, clap_verbosity_flag::Level}; + +use hugr_core::{extension::ExtensionRegistry, Hugr, HugrView}; + /// Validate and visualise a HUGR file. #[derive(Parser, Debug)] #[clap(version = "1.0", long_about = None)] #[clap(about = "Validate a HUGR.")] +#[group(id = "hugr")] pub struct CmdLineArgs { input: FileOrStdin, /// Visualise with mermaid. @@ -16,6 +21,9 @@ pub struct CmdLineArgs { /// Skip validation. #[arg(short, long, help = "Skip validation.")] no_validate: bool, + /// Verbosity. + #[command(flatten)] + verbose: Verbosity, // TODO YAML extensions } @@ -38,7 +46,7 @@ pub const VALID_PRINT: &str = "HUGR valid!"; impl CmdLineArgs { /// Run the HUGR cli and validate against an extension registry. - pub fn run(&self, registry: &ExtensionRegistry) -> Result<(), CliError> { + pub fn run(&self, registry: &ExtensionRegistry) -> Result { let mut hugr: Hugr = serde_json::from_reader(self.input.into_reader()?)?; if self.mermaid { println!("{}", hugr.mermaid_string()); @@ -46,9 +54,15 @@ impl CmdLineArgs { if !self.no_validate { hugr.update_validate(registry)?; - - println!("{}", VALID_PRINT); + if self.verbosity(Level::Info) { + eprintln!("{}", VALID_PRINT); + } } - Ok(()) + Ok(hugr) + } + + /// Test whether a `level` message should be output. + pub fn verbosity(&self, level: Level) -> bool { + self.verbose.log_level_filter() >= level } } diff --git a/hugr/src/main.rs b/hugr/src/main.rs index a1bf109f4..2febb3baf 100644 --- a/hugr/src/main.rs +++ b/hugr/src/main.rs @@ -9,7 +9,7 @@ use hugr::std_extensions::logic::EXTENSION as LOGICS_EXTENSION; use hugr::extension::{ExtensionRegistry, PRELUDE}; -use hugr_cli::{CmdLineArgs, Parser}; +use hugr_cli::{CmdLineArgs, Level, Parser}; fn main() { let opts = CmdLineArgs::parse(); @@ -27,7 +27,9 @@ fn main() { .unwrap(); if let Err(e) = opts.run(®) { - eprintln!("{}", e); + if opts.verbosity(Level::Error) { + eprintln!("{}", e); + } std::process::exit(1); } } diff --git a/hugr/tests/cli.rs b/hugr/tests/cli.rs index 99ced61a4..1df2199a8 100644 --- a/hugr/tests/cli.rs +++ b/hugr/tests/cli.rs @@ -48,7 +48,7 @@ fn test_doesnt_exist(mut cmd: Command) { #[rstest] fn test_validate(test_hugr_file: NamedTempFile, mut cmd: Command) { cmd.arg(test_hugr_file.path()); - cmd.assert().success().stdout(contains(VALID_PRINT)); + cmd.assert().success().stderr(contains(VALID_PRINT)); } #[rstest] @@ -56,7 +56,15 @@ fn test_stdin(test_hugr_string: String, mut cmd: Command) { cmd.write_stdin(test_hugr_string); cmd.arg("-"); - cmd.assert().success().stdout(contains(VALID_PRINT)); + cmd.assert().success().stderr(contains(VALID_PRINT)); +} + +#[rstest] +fn test_stdin_silent(test_hugr_string: String, mut cmd: Command) { + cmd.args(["-", "-q"]); + cmd.write_stdin(test_hugr_string); + + cmd.assert().success().stderr(contains(VALID_PRINT).not()); } #[rstest] @@ -91,3 +99,13 @@ fn test_bad_json(mut cmd: Command) { .failure() .stderr(contains("Error parsing input")); } + +#[rstest] +fn test_bad_json_silent(mut cmd: Command) { + cmd.write_stdin(r#"{"foo": "bar"}"#); + cmd.args(["-", "-qqq"]); + + cmd.assert() + .failure() + .stderr(contains("Error parsing input").not()); +}