gix_filter/driver/
init.rs1use std::process::Stdio;
2
3use bstr::{BStr, BString};
4
5use crate::{
6 driver,
7 driver::{process, substitute_f_parameter, Operation, Process, State},
8 Driver,
9};
10
11#[derive(Debug, thiserror::Error)]
13#[allow(missing_docs)]
14pub enum Error {
15 #[error("Failed to spawn driver: {command:?}")]
16 SpawnCommand {
17 source: std::io::Error,
18 command: std::process::Command,
19 },
20 #[error("Process handshake with command {command:?} failed")]
21 ProcessHandshake {
22 source: process::client::handshake::Error,
23 command: std::process::Command,
24 },
25}
26
27impl State {
29 pub fn maybe_launch_process(
34 &mut self,
35 driver: &Driver,
36 operation: Operation,
37 rela_path: &BStr,
38 ) -> Result<Option<Process<'_>>, Error> {
39 match driver.process.as_ref() {
40 Some(process) => {
41 let client = match self.running.remove(process) {
42 Some(c) => c,
43 None => {
44 let (child, cmd) = spawn_driver(process.clone(), &self.context)?;
45 process::Client::handshake(child, "git-filter", &[2], &["clean", "smudge", "delay"]).map_err(
46 |err| Error::ProcessHandshake {
47 source: err,
48 command: cmd,
49 },
50 )?
51 }
52 };
53
54 self.running.insert(process.clone(), client);
58 let client = self.running.get_mut(process).expect("just inserted");
59
60 Ok(Some(Process::MultiFile {
61 client,
62 key: driver::Key(process.to_owned()),
63 }))
64 }
65 None => {
66 let cmd = match operation {
67 Operation::Clean => driver
68 .clean
69 .as_ref()
70 .map(|cmd| substitute_f_parameter(cmd.as_ref(), rela_path)),
71
72 Operation::Smudge => driver
73 .smudge
74 .as_ref()
75 .map(|cmd| substitute_f_parameter(cmd.as_ref(), rela_path)),
76 };
77
78 let cmd = match cmd {
79 Some(cmd) => cmd,
80 None => return Ok(None),
81 };
82
83 let (child, command) = spawn_driver(cmd, &self.context)?;
84 Ok(Some(Process::SingleFile { child, command }))
85 }
86 }
87 }
88}
89
90fn spawn_driver(
91 cmd: BString,
92 context: &gix_command::Context,
93) -> Result<(std::process::Child, std::process::Command), Error> {
94 let mut cmd: std::process::Command = gix_command::prepare(gix_path::from_bstr(cmd).into_owned())
95 .command_may_be_shell_script()
96 .with_context(context.clone())
97 .stdin(Stdio::piped())
98 .stdout(Stdio::piped())
99 .stderr(Stdio::inherit())
100 .into();
101 gix_trace::debug!(cmd = ?cmd, "launching filter driver");
102 let child = match cmd.spawn() {
103 Ok(child) => child,
104 Err(err) => {
105 return Err(Error::SpawnCommand {
106 source: err,
107 command: cmd,
108 })
109 }
110 };
111 Ok((child, cmd))
112}