aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/src/util/git.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-18 06:38:26 +0900
committernsfisis <nsfisis@gmail.com>2026-08-18 06:38:26 +0900
commitbed0cd33ca32b95aed9d65891f97649a6f9d0069 (patch)
treec04f9f3d6c89198222f9617f4dc84bed14fc0b4e /crates/shirabe/src/util/git.rs
parentced1f9aa91ee36857fec9664c9ccd86ba2310821 (diff)
downloadphp-shirabe-bed0cd33ca32b95aed9d65891f97649a6f9d0069.tar.gz
php-shirabe-bed0cd33ca32b95aed9d65891f97649a6f9d0069.tar.zst
php-shirabe-bed0cd33ca32b95aed9d65891f97649a6f9d0069.zip
fix(process-executor): model commands as a CommandLine enum
Commands were carried as `PhpMixed`, whose `String`/`List` variants do not tell a shell command line apart from an argv list at the type level. `Perforce::execute_command` and `Git::run_command` therefore funnelled string commands through `execute_args`, spawning `p4 set` or `git command` as a single argument instead of running it through a shell as PHP does; their tests were written against that shape. Introduce `CommandLine::{Shell, Args}` and use it for every `ProcessExecutor` entry point, the mock expectation queue and the `Git::run_command` callables. The unreachable "Invalid command type" branches disappear with it, and the affected tests go back to the string expectations the PHP suite uses. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/src/util/git.rs')
-rw-r--r--crates/shirabe/src/util/git.rs41
1 files changed, 16 insertions, 25 deletions
diff --git a/crates/shirabe/src/util/git.rs b/crates/shirabe/src/util/git.rs
index 78c1acb5..5577250f 100644
--- a/crates/shirabe/src/util/git.rs
+++ b/crates/shirabe/src/util/git.rs
@@ -5,6 +5,7 @@ use crate::io::IOInterface;
use crate::io::IOInterfaceImmutable;
use crate::io::io_interface;
use crate::util::Bitbucket;
+use crate::util::CommandLine;
use crate::util::Filesystem;
use crate::util::GitHub;
use crate::util::GitLab;
@@ -101,10 +102,10 @@ impl Git {
initial_clone: bool,
command_output: impl RunCommandOutput,
) -> anyhow::Result<()> {
- let mut callables: Vec<Box<dyn Fn(&str) -> Vec<String>>> = vec![];
+ let mut callables: Vec<Box<dyn Fn(&str) -> CommandLine>> = vec![];
for cmd in commands {
let cmd_clone = cmd.clone();
- callables.push(Box::new(move |url: &str| -> Vec<String> {
+ callables.push(Box::new(move |url: &str| -> CommandLine {
let mut map: IndexMap<String, String> = IndexMap::new();
map.insert("%url%".to_string(), url.to_string());
map.insert(
@@ -112,10 +113,10 @@ impl Git {
preg_replace(php_regex!(r"{://([^@]+?):(.+?)@}"), "://", url),
);
- array_map(
+ CommandLine::Args(array_map(
|value: &String| map.get(value).cloned().unwrap_or_else(|| value.clone()),
&cmd_clone,
- )
+ ))
}));
}
@@ -127,7 +128,7 @@ impl Git {
/// mirroring `Git::runCommand` as exercised by `GitTest`.
pub fn __run_command(
&mut self,
- command_callable: Vec<Box<dyn Fn(&str) -> Vec<String>>>,
+ command_callable: Vec<Box<dyn Fn(&str) -> CommandLine>>,
url: &str,
cwd: Option<&str>,
initial_clone: bool,
@@ -140,14 +141,14 @@ impl Git {
/// if a callable is passed it will be used as output handler
fn run_command(
&mut self,
- command_callable: Vec<Box<dyn Fn(&str) -> Vec<String>>>,
+ command_callable: Vec<Box<dyn Fn(&str) -> CommandLine>>,
url: &str,
cwd: Option<&str>,
initial_clone: bool,
mut command_output: impl RunCommandOutput,
) -> anyhow::Result<()> {
let command_callables = command_callable;
- let mut last_command: PhpMixed = PhpMixed::String(String::new());
+ let mut last_command = CommandLine::Shell(String::new());
// Ensure we are allowed to use this URL by config
self.config.borrow_mut().prohibit_url_by_config(
@@ -167,7 +168,7 @@ impl Git {
// PHP closure: $runCommands = function ($url) use (...) { ... };
let run_commands_inline = |url_arg: &str,
this_process: &mut ProcessExecutor,
- last_cmd: &mut PhpMixed,
+ last_cmd: &mut CommandLine,
output: &mut dyn RunCommandOutput|
-> i64 {
let collect_outputs = output.collect_outputs();
@@ -176,8 +177,7 @@ impl Git {
let mut status: i64 = 0;
for (counter, callable) in command_callables.iter().enumerate() {
let cmd = callable(url_arg);
- *last_cmd =
- PhpMixed::List(cmd.iter().map(|s| PhpMixed::String(s.clone())).collect());
+ *last_cmd = cmd.clone();
let exec_cwd = if initial_clone && counter == 0 {
None
} else {
@@ -185,16 +185,13 @@ impl Git {
};
if collect_outputs {
let mut local_output = String::new();
- status =
- this_process.execute_args(&cmd, &mut local_output, exec_cwd.as_deref());
+ status = this_process
+ .execute(cmd, &mut local_output, exec_cwd.as_deref())
+ .unwrap_or(1);
outputs.push(local_output);
} else {
status = this_process
- .execute(
- &cmd[..],
- output.make_handler().unwrap(),
- exec_cwd.as_deref(),
- )
+ .execute(cmd, output.make_handler().unwrap(), exec_cwd.as_deref())
.unwrap_or(1);
}
if status != 0 {
@@ -747,14 +744,8 @@ impl Git {
}
let mut last_command_str = match &last_command {
- PhpMixed::List(l) => {
- let parts: Vec<String> = l
- .iter()
- .filter_map(|v| v.as_string().map(|s| s.to_string()))
- .collect();
- implode(" ", &parts)
- }
- _ => last_command.as_string().unwrap_or("").to_string(),
+ CommandLine::Args(args) => implode(" ", args),
+ CommandLine::Shell(command) => command.clone(),
};
if (credentials.len() as i64) > 0 {
last_command_str = self.mask_credentials(&last_command_str, &credentials);