objdiff_core/build/
mod.rs1pub mod watcher;
2
3use std::process::Command;
4
5use typed_path::{Utf8PlatformPathBuf, Utf8UnixPath};
6
7pub struct BuildStatus {
8 pub success: bool,
9 pub cmdline: String,
10 pub stdout: String,
11 pub stderr: String,
12}
13
14impl Default for BuildStatus {
15 fn default() -> Self {
16 BuildStatus {
17 success: true,
18 cmdline: String::new(),
19 stdout: String::new(),
20 stderr: String::new(),
21 }
22 }
23}
24
25#[derive(Debug, Clone)]
26pub struct BuildConfig {
27 pub project_dir: Option<Utf8PlatformPathBuf>,
28 pub custom_make: Option<String>,
29 pub custom_args: Option<Vec<String>>,
30 #[allow(unused)]
31 pub selected_wsl_distro: Option<String>,
32}
33
34pub fn run_make(config: &BuildConfig, arg: &Utf8UnixPath) -> BuildStatus {
35 let Some(cwd) = &config.project_dir else {
36 return BuildStatus {
37 success: false,
38 stderr: "Missing project dir".to_string(),
39 ..Default::default()
40 };
41 };
42 let make = config.custom_make.as_deref().unwrap_or("make");
43 let make_args = config.custom_args.as_deref().unwrap_or(&[]);
44 #[cfg(not(windows))]
45 let mut command = {
46 let mut command = Command::new(make);
47 command.current_dir(cwd).args(make_args).arg(arg);
48 command
49 };
50 #[cfg(windows)]
51 let mut command = {
52 use alloc::borrow::Cow;
53 use std::os::windows::process::CommandExt;
54
55 let mut command = if config.selected_wsl_distro.is_some() {
56 Command::new("wsl")
57 } else {
58 Command::new(make)
59 };
60 if let Some(distro) = &config.selected_wsl_distro {
61 let wsl_path_prefix = format!("\\\\wsl.localhost\\{}", distro);
63 let cwd = match cwd.strip_prefix(wsl_path_prefix) {
64 Ok(new_cwd) => Cow::Owned(
66 Utf8UnixPath::new("/").join(new_cwd.with_unix_encoding()).into_string(),
67 ),
68 Err(_) => Cow::Borrowed(cwd.as_str()),
70 };
71
72 command
73 .arg("--cd")
74 .arg::<&str>(cwd.as_ref())
75 .arg("-d")
76 .arg(distro)
77 .arg("--")
78 .arg(make)
79 .args(make_args)
80 .arg(arg.as_str());
81 } else {
82 command.current_dir(cwd).args(make_args).arg(arg.as_str());
83 }
84 command.creation_flags(winapi::um::winbase::CREATE_NO_WINDOW);
85 command
86 };
87 let mut cmdline = shell_escape::escape(command.get_program().to_string_lossy()).into_owned();
88 for arg in command.get_args() {
89 cmdline.push(' ');
90 cmdline.push_str(shell_escape::escape(arg.to_string_lossy()).as_ref());
91 }
92 let output = match command.output() {
93 Ok(output) => output,
94 Err(e) => {
95 return BuildStatus {
96 success: false,
97 cmdline,
98 stdout: Default::default(),
99 stderr: e.to_string(),
100 };
101 }
102 };
103 let stdout = String::from_utf8(output.stdout)
105 .unwrap_or_else(|e| String::from_utf8_lossy(e.as_bytes()).into_owned());
106 let stderr = String::from_utf8(output.stderr)
107 .unwrap_or_else(|e| String::from_utf8_lossy(e.as_bytes()).into_owned());
108 BuildStatus { success: output.status.success(), cmdline, stdout, stderr }
109}