ic_build/cargo/selection/
mod.rs1use std::{
4 collections::BTreeSet,
5 ffi::OsString,
6 path::{Component, Path},
7};
8
9#[cfg(test)]
10mod tests;
11
12#[derive(Clone, Debug, Eq, PartialEq)]
14pub struct CargoFeatureSelection {
15 pub features: BTreeSet<String>,
17 pub all_features: bool,
19 pub default_features: bool,
21}
22
23impl Default for CargoFeatureSelection {
24 fn default() -> Self {
25 Self {
26 features: BTreeSet::new(),
27 default_features: true,
28 all_features: false,
29 }
30 }
31}
32
33impl CargoFeatureSelection {
34 pub(crate) fn arguments(&self) -> Vec<OsString> {
35 let mut arguments = Vec::new();
36 if self.all_features {
37 arguments.push("--all-features".into());
38 }
39 if !self.default_features {
40 arguments.push("--no-default-features".into());
41 }
42 if !self.features.is_empty() {
43 arguments.push(
44 format!(
45 "--features={}",
46 self.features
47 .iter()
48 .map(String::as_str)
49 .collect::<Vec<_>>()
50 .join(",")
51 )
52 .into(),
53 );
54 }
55 arguments
56 }
57}
58
59#[derive(Clone, Debug, Default, Eq, PartialEq)]
67pub struct CargoSelection {
68 pub profile: Option<String>,
70 pub features: CargoFeatureSelection,
72 pub locked: bool,
74 pub offline: bool,
76}
77
78impl CargoSelection {
79 pub(crate) fn profile_target_dir(&self) -> Result<&str, &'static str> {
80 let profile = self.profile.as_deref().unwrap_or("dev");
81 let directory = match profile {
82 "dev" | "test" => "debug",
83 "bench" => "release",
84 custom => custom,
85 };
86 if !is_normal_component(Path::new(directory)) {
87 return Err("Cargo profile must select one normal output directory component");
88 }
89 Ok(directory)
90 }
91
92 pub(crate) fn metadata_arguments(&self) -> Vec<OsString> {
93 graph_arguments(&self.features, self.locked, self.offline)
94 }
95
96 pub(crate) fn build_arguments(&self) -> Vec<OsString> {
97 let mut arguments = Vec::new();
98 if let Some(profile) = &self.profile {
99 arguments.push(if profile == "release" {
100 "--release".into()
101 } else {
102 format!("--profile={profile}").into()
103 });
104 }
105 arguments.extend(self.metadata_arguments());
106 arguments
107 }
108}
109
110pub(crate) fn graph_arguments(
112 features: &CargoFeatureSelection,
113 locked: bool,
114 offline: bool,
115) -> Vec<OsString> {
116 let mut arguments = Vec::new();
117 for (enabled, flag) in [(locked, "--locked"), (offline, "--offline")] {
118 if enabled {
119 arguments.push(flag.into());
120 }
121 }
122 arguments.extend(features.arguments());
123 arguments
124}
125
126pub(crate) fn is_normal_component(path: &Path) -> bool {
129 let mut components = path.components();
130 matches!(
131 (components.next(), components.next()),
132 (Some(Component::Normal(_)), None)
133 )
134}