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