sandogasa_cli/lib.rs
1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3//! Shared CLI utilities for sandogasa tools.
4
5use std::process::{Command, Stdio};
6
7/// Check that an external tool is available in `$PATH`.
8///
9/// Runs `<name> <version_arg>` and returns `Ok(())` if it exits
10/// successfully, or an error message with the install hint.
11/// Most tools use `--version`; see [`require_tool`] for a
12/// convenience wrapper.
13///
14/// # Example
15///
16/// ```no_run
17/// // koji uses `version` subcommand instead of `--version`
18/// sandogasa_cli::require_tool_with_arg("koji", "version", "sudo dnf install koji").unwrap();
19/// ```
20pub fn require_tool_with_arg(
21 name: &str,
22 version_arg: &str,
23 install_hint: &str,
24) -> Result<(), String> {
25 match Command::new(name)
26 .arg(version_arg)
27 .stdout(Stdio::null())
28 .stderr(Stdio::null())
29 .status()
30 {
31 Ok(s) if s.success() => Ok(()),
32 Ok(s) => Err(format!(
33 "{name} exited with {s}; is it installed correctly? \
34 Install it with: {install_hint}"
35 )),
36 Err(_) => Err(format!("{name} not found. Install it with: {install_hint}")),
37 }
38}
39
40/// Check that an external tool is available in `$PATH`.
41///
42/// Runs `<name> --version` and returns `Ok(())` if it exits
43/// successfully, or an error message with the install hint.
44///
45/// For tools that use a different version probe (e.g. `koji version`
46/// instead of `koji --version`), use [`require_tool_with_arg`].
47///
48/// # Example
49///
50/// ```no_run
51/// sandogasa_cli::require_tool("fedrq", "sudo dnf install fedrq").unwrap();
52/// ```
53pub fn require_tool(name: &str, install_hint: &str) -> Result<(), String> {
54 require_tool_with_arg(name, "--version", install_hint)
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 #[test]
62 fn require_missing_tool() {
63 let result = require_tool("nonexistent_tool_xyz_123", "magic install");
64 assert!(result.is_err());
65 let msg = result.unwrap_err();
66 assert!(msg.contains("nonexistent_tool_xyz_123"));
67 assert!(msg.contains("magic install"));
68 }
69
70 #[test]
71 fn require_available_tool() {
72 // `true` is a standard Unix utility that always succeeds.
73 // It doesn't support --version but some impls exit 0 anyway.
74 // Use `sh` which reliably exists and handles --version.
75 let result = require_tool("sh", "should already be installed");
76 // sh --version may or may not succeed depending on implementation,
77 // so just verify it doesn't panic.
78 let _ = result;
79 }
80}