hugr_cli/lib.rs
1//! Standard command line tools for the HUGR format.
2//!
3//! This library provides utilities for the HUGR CLI.
4//!
5//! ## CLI Usage
6//!
7//! Run `cargo install hugr-cli` to install the CLI tools. This will make the
8//! `hugr` executable available in your shell as long as you have [cargo's bin
9//! directory](https://doc.rust-lang.org/book/ch14-04-installing-binaries.html)
10//! in your path.
11//!
12//! The CLI provides two subcommands:
13//!
14//! - `validate` for validating HUGR files.
15//! - `mermaid` for visualizing HUGR files as mermaid diagrams.
16//!
17//! ### Validate
18//!
19//! Validate and visualize a HUGR file
20//!
21//! Usage: `hugr validate [OPTIONS] [INPUT]`
22//!
23//! ```text
24//! Options:
25//! -v, --verbose... Increase logging verbosity
26//! -q, --quiet... Decrease logging verbosity
27//! -h, --help Print help (see more with '--help')
28//! -V, --version Print version
29//!
30//! Input:
31//! --no-std Don't use standard extensions when validating hugrs. Prelude is still used.
32//! -e, --extensions <EXTENSIONS> Paths to serialised extensions to validate against.
33//! --hugr-json Read the input as a HUGR JSON file instead of an envelope
34//! [INPUT] Input file. Defaults to `-` for stdin
35//! ```
36//!
37//! ### Mermaid
38//!
39//! Write HUGR as mermaid diagrams
40//!
41//! Usage: `hugr mermaid [OPTIONS] [INPUT]`
42//!
43//! ```text
44//! Options:
45//! --validate Validate before rendering, includes extension inference.
46//! -o, --output <OUTPUT> Output file '-' for stdout [default: -]
47//! -v, --verbose... Increase logging verbosity
48//! -q, --quiet... Decrease logging verbosity
49//! -h, --help Print help (see more with '--help')
50//! -V, --version Print version
51//!
52//! Input:
53//! --no-std Don't use standard extensions when validating hugrs. Prelude is still used.
54//! -e, --extensions <EXTENSIONS> Paths to serialised extensions to validate against.
55//! --hugr-json Read the input as a HUGR JSON file instead of an envelope
56//! [INPUT] Input file. Defaults to `-` for stdin.
57//! ```
58
59use clap::{Parser, crate_version};
60use clap_verbosity_flag::log::Level;
61use clap_verbosity_flag::{InfoLevel, Verbosity};
62use hugr::envelope::EnvelopeError;
63use hugr::package::PackageValidationError;
64use std::ffi::OsString;
65
66pub mod extensions;
67pub mod hugr_io;
68pub mod mermaid;
69pub mod validate;
70
71/// CLI arguments.
72#[derive(Parser, Debug)]
73#[clap(version = crate_version!(), long_about = None)]
74#[clap(about = "HUGR CLI tools.")]
75#[group(id = "hugr")]
76#[non_exhaustive]
77pub enum CliArgs {
78 /// Validate and visualize a HUGR file.
79 Validate(validate::ValArgs),
80 /// Write standard extensions out in serialized form.
81 GenExtensions(extensions::ExtArgs),
82 /// Write HUGR as mermaid diagrams.
83 Mermaid(mermaid::MermaidArgs),
84 /// External commands
85 #[command(external_subcommand)]
86 External(Vec<OsString>),
87}
88
89/// Error type for the CLI.
90#[derive(Debug, derive_more::Display, derive_more::Error, derive_more::From)]
91#[non_exhaustive]
92pub enum CliError {
93 /// Error reading input.
94 #[display("Error reading from path: {_0}")]
95 InputFile(std::io::Error),
96 /// Error parsing input.
97 #[display("Error parsing package: {_0}")]
98 Parse(serde_json::Error),
99 #[display("Error validating HUGR: {_0}")]
100 /// Errors produced by the `validate` subcommand.
101 Validate(PackageValidationError),
102 #[display("Error decoding HUGR envelope: {_0}")]
103 /// Errors produced by the `validate` subcommand.
104 Envelope(EnvelopeError),
105 /// Pretty error when the user passes a non-envelope file.
106 #[display(
107 "Input file is not a HUGR envelope. Invalid magic number.\n\nUse `--hugr-json` to read a raw HUGR JSON file instead."
108 )]
109 NotAnEnvelope,
110}
111
112/// Other arguments affecting the HUGR CLI runtime.
113#[derive(Parser, Debug)]
114pub struct OtherArgs {
115 /// Verbosity.
116 #[command(flatten)]
117 pub verbose: Verbosity<InfoLevel>,
118}
119
120impl OtherArgs {
121 /// Test whether a `level` message should be output.
122 #[must_use]
123 pub fn verbosity(&self, level: Level) -> bool {
124 self.verbose.log_level_filter() >= level
125 }
126}