-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcommand.rs
More file actions
122 lines (110 loc) · 3.73 KB
/
Copy pathcommand.rs
File metadata and controls
122 lines (110 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
//! Command execution utilities
//!
//! This module provides utilities for executing system commands and checking
//! if commands exist in the system PATH.
// Standard library
use std::process::Command;
// External crates
use thiserror::Error;
// ============================================================================
// PUBLIC API - Functions
// ============================================================================
/// Check if a command exists in the system PATH
///
/// # Platform Support
///
/// Currently uses the `which` command on Unix-like systems. Windows support
/// would require using `where` command or a different approach.
///
/// # Examples
///
/// ```rust
/// use torrust_dependency_installer::command::command_exists;
///
/// // Check if 'cargo' is installed
/// let exists = command_exists("cargo").unwrap();
/// assert!(exists);
/// ```
///
/// # Errors
///
/// Returns an error if the 'which' command fails to execute
pub fn command_exists(command: &str) -> Result<bool, CommandError> {
// Use 'which' on Unix-like systems to check if command exists
// Note: This is Unix-specific. For Windows support, use 'where' command.
let output =
Command::new("which")
.arg(command)
.output()
.map_err(|e| CommandError::ExecutionFailed {
command: format!("which {command}"),
source: e,
})?;
Ok(output.status.success())
}
/// Execute a command and return its stdout as a string
///
/// # Examples
///
/// ```rust,no_run
/// use torrust_dependency_installer::command::execute_command;
///
/// // Get cargo version
/// let version = execute_command("cargo", &["--version"]).unwrap();
/// println!("Cargo version: {}", version);
/// ```
///
/// # Errors
///
/// Returns an error if the command is not found or fails to execute
pub fn execute_command(command: &str, args: &[&str]) -> Result<String, CommandError> {
let output = Command::new(command).args(args).output().map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
CommandError::CommandNotFound {
command: command.to_string(),
}
} else {
CommandError::ExecutionFailed {
command: format!("{command} {}", args.join(" ")),
source: e,
}
}
})?;
if !output.status.success() {
return Err(CommandError::ExecutionFailed {
command: format!("{command} {}", args.join(" ")),
source: std::io::Error::other(format!("Command exited with status: {}", output.status)),
});
}
String::from_utf8(output.stdout)
.map(|s| s.trim().to_string())
.map_err(|e| CommandError::ExecutionFailed {
command: format!("{command} {}", args.join(" ")),
source: std::io::Error::new(std::io::ErrorKind::InvalidData, e),
})
}
// ============================================================================
// ERROR TYPES - Secondary Concerns
// ============================================================================
/// Error types for command execution utilities
#[derive(Debug, Error)]
pub enum CommandError {
#[error("Failed to execute command '{command}': {source}")]
ExecutionFailed {
command: String,
#[source]
source: std::io::Error,
},
#[error("Command '{command}' not found in PATH")]
CommandNotFound { command: String },
}
impl From<CommandError> for std::io::Error {
fn from(error: CommandError) -> Self {
match error {
CommandError::ExecutionFailed { source, .. } => source,
CommandError::CommandNotFound { command } => {
std::io::Error::new(std::io::ErrorKind::NotFound, command)
}
}
}
}