diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-08-18 06:38:26 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-08-18 06:38:26 +0900 |
| commit | bed0cd33ca32b95aed9d65891f97649a6f9d0069 (patch) | |
| tree | c04f9f3d6c89198222f9617f4dc84bed14fc0b4e /crates/shirabe/src/util/git.rs | |
| parent | ced1f9aa91ee36857fec9664c9ccd86ba2310821 (diff) | |
| download | php-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.rs | 41 |
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); |
