mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
28ebe1c97a
## Summary Enables shell_command for windows users, and starts adding some basic command parsing here, to at least remove powershell prefixes. We'll follow this up with command parsing but I wanted to land this change separately with some basic UX. **NOTE**: This implementation parses bash and powershell on both platforms. In theory this is possible, since you can use git bash on windows or powershell on linux. In practice, this may not be worth the complexity of supporting, so I don't feel strongly about the current approach vs. platform-specific branching. ## Testing - [x] Added a bunch of tests - [x] Ran on both windows and os x
94 lines
3.0 KiB
Rust
94 lines
3.0 KiB
Rust
use std::path::PathBuf;
|
|
|
|
use crate::shell::ShellType;
|
|
use crate::shell::detect_shell_type;
|
|
|
|
const POWERSHELL_FLAGS: &[&str] = &["-nologo", "-noprofile", "-command", "-c"];
|
|
|
|
/// Extract the PowerShell script body from an invocation such as:
|
|
///
|
|
/// - ["pwsh", "-NoProfile", "-Command", "Get-ChildItem -Recurse | Select-String foo"]
|
|
/// - ["powershell.exe", "-Command", "Write-Host hi"]
|
|
/// - ["powershell", "-NoLogo", "-NoProfile", "-Command", "...script..."]
|
|
///
|
|
/// Returns (`shell`, `script`) when the first arg is a PowerShell executable and a
|
|
/// `-Command` (or `-c`) flag is present followed by a script string.
|
|
pub fn extract_powershell_command(command: &[String]) -> Option<(&str, &str)> {
|
|
if command.len() < 3 {
|
|
return None;
|
|
}
|
|
|
|
let shell = &command[0];
|
|
if detect_shell_type(&PathBuf::from(shell)) != Some(ShellType::PowerShell) {
|
|
return None;
|
|
}
|
|
|
|
// Find the first occurrence of -Command (accept common short alias -c as well)
|
|
let mut i = 1usize;
|
|
while i + 1 < command.len() {
|
|
let flag = &command[i];
|
|
// Reject unknown flags
|
|
if !POWERSHELL_FLAGS.contains(&flag.to_ascii_lowercase().as_str()) {
|
|
return None;
|
|
}
|
|
if flag.eq_ignore_ascii_case("-Command") || flag.eq_ignore_ascii_case("-c") {
|
|
let script = &command[i + 1];
|
|
return Some((shell, script.as_str()));
|
|
}
|
|
i += 1;
|
|
}
|
|
None
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::extract_powershell_command;
|
|
|
|
#[test]
|
|
fn extracts_basic_powershell_command() {
|
|
let cmd = vec![
|
|
"powershell".to_string(),
|
|
"-Command".to_string(),
|
|
"Write-Host hi".to_string(),
|
|
];
|
|
let (_shell, script) = extract_powershell_command(&cmd).expect("extract");
|
|
assert_eq!(script, "Write-Host hi");
|
|
}
|
|
|
|
#[test]
|
|
fn extracts_lowercase_flags() {
|
|
let cmd = vec![
|
|
"powershell".to_string(),
|
|
"-nologo".to_string(),
|
|
"-command".to_string(),
|
|
"Write-Host hi".to_string(),
|
|
];
|
|
let (_shell, script) = extract_powershell_command(&cmd).expect("extract");
|
|
assert_eq!(script, "Write-Host hi");
|
|
}
|
|
|
|
#[test]
|
|
fn extracts_full_path_powershell_command() {
|
|
let command = if cfg!(windows) {
|
|
"C:\\windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe".to_string()
|
|
} else {
|
|
"/usr/local/bin/powershell.exe".to_string()
|
|
};
|
|
let cmd = vec![command, "-Command".to_string(), "Write-Host hi".to_string()];
|
|
let (_shell, script) = extract_powershell_command(&cmd).expect("extract");
|
|
assert_eq!(script, "Write-Host hi");
|
|
}
|
|
|
|
#[test]
|
|
fn extracts_with_noprofile_and_alias() {
|
|
let cmd = vec![
|
|
"pwsh".to_string(),
|
|
"-NoProfile".to_string(),
|
|
"-c".to_string(),
|
|
"Get-ChildItem | Select-String foo".to_string(),
|
|
];
|
|
let (_shell, script) = extract_powershell_command(&cmd).expect("extract");
|
|
assert_eq!(script, "Get-ChildItem | Select-String foo");
|
|
}
|
|
}
|