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