cargo_mobile2/
lib.rs

1#![deny(unsafe_code)]
2
3pub mod android;
4#[cfg(target_os = "macos")]
5pub mod apple;
6pub mod bicycle;
7pub mod config;
8pub mod device;
9pub mod doctor;
10pub mod dot_cargo;
11pub mod env;
12pub mod init;
13mod once_cell_regex;
14pub mod opts;
15pub mod os;
16mod project;
17pub mod reserved_names;
18pub mod target;
19mod templating;
20pub mod update;
21pub mod util;
22use std::ffi::OsStr;
23
24pub use duct::Handle as ChildHandle;
25
26pub static NAME: &str = "mobile";
27
28trait DuctExpressionExt {
29    fn vars(self, vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>) -> Self;
30    fn run_and_detach(&self) -> Result<(), std::io::Error>;
31    // Sets the stdin, stdout and stderr to properly
32    // show the command output in a Node.js wrapper (napi-rs).
33    fn dup_stdio(&self) -> Self;
34}
35
36impl DuctExpressionExt for duct::Expression {
37    fn vars(
38        mut self,
39        vars: impl IntoIterator<Item = (impl AsRef<OsStr>, impl AsRef<OsStr>)>,
40    ) -> Self {
41        for (k, v) in vars {
42            self = self.env(&k, &v);
43        }
44        self
45    }
46
47    fn run_and_detach(&self) -> Result<(), std::io::Error> {
48        self.before_spawn(|cmd| {
49            // This is pretty much lifted from the implementation in Alacritty:
50            // https://github.com/alacritty/alacritty/blob/8bd2c13490f8cb6ad6b0c1104f9586b3554efea2/alacritty/src/daemon.rs
51            #[cfg(unix)]
52            #[allow(unsafe_code)]
53            unsafe {
54                use std::os::unix::process::CommandExt as _;
55
56                let display = format!("{cmd:?}");
57                cmd.pre_exec(move || match libc::fork() {
58                    -1 => {
59                        let err = std::io::Error::last_os_error();
60                        log::error!("`fork` failed for command {:?}: {}", display, err);
61                        Err(err)
62                    }
63                    0 => {
64                        if libc::setsid() == -1 {
65                            let err = std::io::Error::last_os_error();
66                            log::error!("`setsid` failed for command {:?}: {}", display, err);
67                            Err(err)
68                        } else {
69                            Ok(())
70                        }
71                    }
72                    _ => libc::_exit(0),
73                });
74            }
75            #[cfg(windows)]
76            {
77                use std::os::windows::process::CommandExt;
78                const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
79                const CREATE_NO_WINDOW: u32 = 0x08000000;
80                cmd.creation_flags(CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW);
81            }
82
83            Ok(())
84        })
85        .stdin_null()
86        .stdout_null()
87        .stderr_null()
88        .start()?;
89        Ok(())
90    }
91
92    fn dup_stdio(&self) -> Self {
93        self.stdin_file(os_pipe::dup_stdin().unwrap())
94            .stdout_file(os_pipe::dup_stdout().unwrap())
95            .stderr_file(os_pipe::dup_stderr().unwrap())
96    }
97}