cargo_mobile2/util/
cargo.rs

1use std::{collections::HashMap, ffi::OsString, path::PathBuf};
2
3use crate::{env::ExplicitEnv, DuctExpressionExt};
4
5#[derive(Debug)]
6pub struct CargoCommand<'a> {
7    subcommand: &'a str,
8    verbose: bool,
9    package: Option<&'a str>,
10    manifest_path: Option<PathBuf>,
11    target: Option<&'a str>,
12    no_default_features: bool,
13    features: Option<&'a [String]>,
14    args: Option<&'a [String]>,
15    release: bool,
16}
17
18impl<'a> CargoCommand<'a> {
19    pub fn new(subcommand: &'a str) -> Self {
20        Self {
21            subcommand,
22            verbose: Default::default(),
23            package: Default::default(),
24            manifest_path: Default::default(),
25            target: Default::default(),
26            no_default_features: Default::default(),
27            features: Default::default(),
28            args: Default::default(),
29            release: Default::default(),
30        }
31    }
32
33    pub fn with_verbose(mut self, verbose: bool) -> Self {
34        self.verbose = verbose;
35        self
36    }
37
38    pub fn with_package(mut self, package: Option<&'a str>) -> Self {
39        self.package = package;
40        self
41    }
42
43    pub fn with_manifest_path(mut self, manifest_path: Option<PathBuf>) -> Self {
44        self.manifest_path = manifest_path.map(|manifest_path| {
45            dunce::canonicalize(manifest_path).expect("Failed to canonicalize manifest path")
46        });
47        self
48    }
49
50    pub fn with_target(mut self, target: Option<&'a str>) -> Self {
51        self.target = target;
52        self
53    }
54
55    pub fn with_no_default_features(mut self, no_default_features: bool) -> Self {
56        self.no_default_features = no_default_features;
57        self
58    }
59
60    pub fn with_features(mut self, features: Option<&'a [String]>) -> Self {
61        self.features = features;
62        self
63    }
64
65    pub fn with_args(mut self, args: Option<&'a [String]>) -> Self {
66        self.args = args;
67        self
68    }
69
70    pub fn with_release(mut self, release: bool) -> Self {
71        self.release = release;
72        self
73    }
74
75    pub fn build(self, env: &impl ExplicitEnv) -> duct::Expression {
76        let mut args = vec![self.subcommand.to_owned()];
77        if self.verbose {
78            args.push("-vv".into());
79        }
80        if let Some(package) = self.package {
81            args.extend_from_slice(&["--package".into(), package.to_owned()]);
82        }
83        if let Some(manifest_path) = self.manifest_path {
84            if !manifest_path.exists() {
85                log::error!("manifest path {:?} doesn't exist!", manifest_path);
86            }
87            args.extend_from_slice(&[
88                "--manifest-path".into(),
89                manifest_path.to_string_lossy().to_string(),
90            ]);
91        }
92        if let Some(target) = self.target {
93            // We used to use `util::host_target_triple` to avoid explicitly
94            // specifying the default target triple here, since specifying it
95            // results in a different `target` subdir being used... however,
96            // for reasons noted in `crate::init::exec`, we now favor explicitly
97            // specifying `--target` when possible. Though, due to the
98            // solution described in the aforementioned function, omitting the
99            // default target here wouldn't actually have any negative effect,
100            // but it wouldn't accomplish anything either.
101            args.extend_from_slice(&["--target".into(), target.to_owned()]);
102        }
103        if self.no_default_features {
104            args.push("--no-default-features".into());
105        }
106        if let Some(features) = self.features {
107            let features = features.join(" ");
108            args.extend_from_slice(&["--features".into(), features.as_str().to_string()]);
109        }
110        if let Some(a) = self.args {
111            args.extend_from_slice(a);
112        }
113        if self.release {
114            args.push("--release".into());
115        }
116
117        duct::cmd("cargo", args)
118            .vars(env.explicit_env())
119            .vars(explicit_cargo_env())
120            .dup_stdio()
121    }
122}
123
124fn explicit_cargo_env() -> HashMap<String, OsString> {
125    let mut vars = HashMap::new();
126    if let Some(target_dir) = std::env::var_os("CARGO_TARGET_DIR") {
127        vars.insert("CARGO_TARGET_DIR".into(), target_dir);
128    }
129    if let Some(target_dir) = std::env::var_os("CARGO_BUILD_TARGET_DIR") {
130        vars.insert("CARGO_BUILD_TARGET_DIR".into(), target_dir);
131    }
132    vars
133}