Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions hugr-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ assert_cmd = { workspace = true }
assert_fs = { workspace = true }
predicates = { workspace = true }
rstest.workspace = true
tempfile = "3"

[[bin]]
name = "hugr"
Expand Down
30 changes: 24 additions & 6 deletions hugr-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,30 @@ fn main() {
CliArgs::Validate(args) => run_validate(args),
CliArgs::GenExtensions(args) => args.run_dump(&hugr::std_extensions::STD_REG),
CliArgs::Mermaid(args) => run_mermaid(args),
CliArgs::External(_) => {
// TODO: Implement support for external commands.
// Running `hugr COMMAND` would look for `hugr-COMMAND` in the path
// and run it.
eprintln!("External commands are not supported yet.");
std::process::exit(1);
CliArgs::External(args) => {
// External subcommand support: invoke `hugr-<subcommand>`
if args.is_empty() {
eprintln!("No external subcommand specified.");
std::process::exit(1);
}
let subcmd = args[0].to_string_lossy();
let exe = format!("hugr-{}", subcmd);
let rest: Vec<_> = args[1..].iter().map(|s| s.to_string_lossy().to_string()).collect();
match std::process::Command::new(&exe).args(&rest).status() {
Ok(status) => {
if !status.success() {
std::process::exit(status.code().unwrap_or(1));
}
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
eprintln!("error: no such subcommand: '{}'.\nCould not find '{}' in PATH.", subcmd, exe);
std::process::exit(1);
}
Err(e) => {
eprintln!("error: failed to invoke '{}': {}", exe, e);
std::process::exit(1);
}
}
}
_ => {
eprintln!("Unknown command");
Expand Down
42 changes: 42 additions & 0 deletions hugr-cli/tests/external.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//! Tests for external subcommand support in hugr-cli.
#![cfg(all(test, not(miri)))]

use assert_cmd::Command;
use predicates::str::contains;
use std::env;
use std::fs;
use std::os::unix::fs::PermissionsExt;
use tempfile::TempDir;

#[test]
fn test_missing_external_command() {
let mut cmd = Command::cargo_bin("hugr").unwrap();
cmd.arg("idontexist");
cmd.assert()
.failure()
.stderr(contains("no such subcommand"));
}

#[test]
fn test_external_command_invocation() {
// Create a dummy external command in a temp dir
let tempdir = TempDir::new().unwrap();
let bin_path = tempdir.path().join("hugr-dummy");
fs::write(&bin_path, b"#!/bin/sh\necho dummy called: $@\nexit 42\n").unwrap();
let mut perms = fs::metadata(&bin_path).unwrap().permissions();
perms.set_mode(0o755);
fs::set_permissions(&bin_path, perms).unwrap();

// Prepend tempdir to PATH
let orig_path = env::var("PATH").unwrap();
let new_path = format!("{}:{}", tempdir.path().display(), orig_path);
let mut cmd = Command::cargo_bin("hugr").unwrap();
cmd.env("PATH", new_path);
cmd.arg("dummy");
cmd.arg("foo");
cmd.arg("bar");
cmd.assert()
.failure()
.stdout(contains("dummy called: foo bar"))
.code(42);
}
Loading