Skip to content

Commit 9af7611

Browse files
committed
Simplify config internals.
Simplifies the `config.rs` and `cross_toml.rs` to have more reusable functions, and implement logic in terms of these functions, so we can add more config options in the future. This also simplifies maintenance, since we can use 1-line logic for most config variables now.
1 parent fdd7058 commit 9af7611

File tree

4 files changed

+142
-125
lines changed

4 files changed

+142
-125
lines changed

src/cli.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use std::str::FromStr;
21
use std::{env, path::PathBuf};
32

43
use crate::cargo::Subcommand;
4+
use crate::config::bool_from_envvar;
55
use crate::errors::Result;
66
use crate::rustc::TargetList;
77
use crate::Target;
@@ -28,16 +28,6 @@ fn absolute_path(path: PathBuf) -> Result<PathBuf> {
2828
})
2929
}
3030

31-
fn bool_from_envvar(envvar: &str) -> bool {
32-
if let Ok(value) = bool::from_str(envvar) {
33-
value
34-
} else if let Ok(value) = i32::from_str(envvar) {
35-
value != 0
36-
} else {
37-
!envvar.is_empty()
38-
}
39-
}
40-
4131
pub fn is_subcommand_list(stdout: &str) -> bool {
4232
stdout.starts_with("Installed Commands:")
4333
}

src/config.rs

Lines changed: 105 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::{CrossToml, Result, Target, TargetList};
22

3-
use crate::errors::*;
43
use std::collections::HashMap;
54
use std::env;
5+
use std::str::FromStr;
66

77
#[derive(Debug)]
88
struct Environment(&'static str, Option<HashMap<&'static str, &'static str>>);
@@ -23,6 +23,19 @@ impl Environment {
2323
.or_else(|| env::var(name).ok())
2424
}
2525

26+
fn get_values_for<T>(
27+
&self,
28+
var: &str,
29+
target: &Target,
30+
convert: impl Fn(&str) -> T,
31+
) -> (Option<T>, Option<T>) {
32+
let target_values = self.get_target_var(target, var).map(|ref s| convert(s));
33+
34+
let build_values = self.get_build_var(var).map(|ref s| convert(s));
35+
36+
(build_values, target_values)
37+
}
38+
2639
fn target_path(target: &Target, key: &str) -> String {
2740
format!("TARGET_{target}_{key}")
2841
}
@@ -39,27 +52,8 @@ impl Environment {
3952
self.get_var(&self.build_var_name(&Self::target_path(target, key)))
4053
}
4154

42-
fn xargo(&self, target: &Target) -> Result<(Option<bool>, Option<bool>)> {
43-
let (build_xargo, target_xargo) = (
44-
self.get_build_var("XARGO"),
45-
self.get_target_var(target, "XARGO"),
46-
);
47-
let build_env = if let Some(value) = build_xargo {
48-
Some(value.parse::<bool>().wrap_err_with(|| {
49-
format!("error parsing {value} from XARGO environment variable")
50-
})?)
51-
} else {
52-
None
53-
};
54-
let target_env = if let Some(value) = target_xargo {
55-
Some(value.parse::<bool>().wrap_err_with(|| {
56-
format!("error parsing {} from XARGO environment variable", value)
57-
})?)
58-
} else {
59-
None
60-
};
61-
62-
Ok((build_env, target_env))
55+
fn xargo(&self, target: &Target) -> (Option<bool>, Option<bool>) {
56+
self.get_values_for("XARGO", target, bool_from_envvar)
6357
}
6458

6559
fn image(&self, target: &Target) -> Option<String> {
@@ -71,38 +65,32 @@ impl Environment {
7165
}
7266

7367
fn passthrough(&self, target: &Target) -> (Option<Vec<String>>, Option<Vec<String>>) {
74-
self.get_values_for("ENV_PASSTHROUGH", target)
68+
self.get_values_for("ENV_PASSTHROUGH", target, split_to_cloned_by_ws)
7569
}
7670

7771
fn volumes(&self, target: &Target) -> (Option<Vec<String>>, Option<Vec<String>>) {
78-
self.get_values_for("ENV_VOLUMES", target)
72+
self.get_values_for("ENV_VOLUMES", target, split_to_cloned_by_ws)
7973
}
8074

8175
fn target(&self) -> Option<String> {
8276
self.get_build_var("TARGET")
8377
}
84-
85-
fn get_values_for(
86-
&self,
87-
var: &str,
88-
target: &Target,
89-
) -> (Option<Vec<String>>, Option<Vec<String>>) {
90-
let target_values = self
91-
.get_target_var(target, var)
92-
.map(|ref s| split_to_cloned_by_ws(s));
93-
94-
let build_values = self
95-
.get_build_var(var)
96-
.map(|ref s| split_to_cloned_by_ws(s));
97-
98-
(build_values, target_values)
99-
}
10078
}
10179

10280
fn split_to_cloned_by_ws(string: &str) -> Vec<String> {
10381
string.split_whitespace().map(String::from).collect()
10482
}
10583

84+
pub fn bool_from_envvar(envvar: &str) -> bool {
85+
if let Ok(value) = bool::from_str(envvar) {
86+
value
87+
} else if let Ok(value) = i32::from_str(envvar) {
88+
value != 0
89+
} else {
90+
!envvar.is_empty()
91+
}
92+
}
93+
10694
#[derive(Debug)]
10795
pub struct Config {
10896
toml: Option<CrossToml>,
@@ -136,72 +124,97 @@ impl Config {
136124
}
137125
}
138126

139-
#[cfg(test)]
140-
fn new_with(toml: Option<CrossToml>, env: Environment) -> Self {
141-
Config { toml, env }
142-
}
143-
144-
pub fn xargo(&self, target: &Target) -> Result<Option<bool>> {
145-
let (build_xargo, target_xargo) = self.env.xargo(target)?;
146-
let (toml_build_xargo, toml_target_xargo) = if let Some(ref toml) = self.toml {
147-
toml.xargo(target)
127+
fn bool_from_config(
128+
&self,
129+
target: &Target,
130+
env: impl Fn(&Environment, &Target) -> (Option<bool>, Option<bool>),
131+
config: impl Fn(&CrossToml, &Target) -> (Option<bool>, Option<bool>),
132+
) -> Option<bool> {
133+
let (env_build, env_target) = env(&self.env, target);
134+
let (toml_build, toml_target) = if let Some(ref toml) = self.toml {
135+
config(toml, target)
148136
} else {
149137
(None, None)
150138
};
151139

152-
match (build_xargo, toml_build_xargo) {
153-
(xargo @ Some(_), _) => return Ok(xargo),
154-
(None, xargo @ Some(_)) => return Ok(xargo),
140+
match (env_build, toml_build) {
141+
(Some(value), _) => return Some(value),
142+
(None, Some(value)) => return Some(value),
155143
(None, None) => {}
156144
};
157145

158-
match (target_xargo, toml_target_xargo) {
159-
(xargo @ Some(_), _) => return Ok(xargo),
160-
(None, xargo @ Some(_)) => return Ok(xargo),
146+
match (env_target, toml_target) {
147+
(Some(value), _) => return Some(value),
148+
(None, Some(value)) => return Some(value),
161149
(None, None) => {}
162150
};
163-
Ok(None)
164-
}
165151

166-
pub fn image(&self, target: &Target) -> Result<Option<String>> {
167-
let env_value = self.env.image(target);
168-
if let Some(env_value) = env_value {
169-
return Ok(Some(env_value));
170-
}
171-
self.toml.as_ref().map_or(Ok(None), |t| Ok(t.image(target)))
152+
None
172153
}
173154

174-
pub fn runner(&self, target: &Target) -> Result<Option<String>> {
175-
let env_value = self.env.runner(target);
155+
fn string_from_config(
156+
&self,
157+
target: &Target,
158+
env: impl Fn(&Environment, &Target) -> Option<String>,
159+
config: impl Fn(&CrossToml, &Target) -> Option<String>,
160+
) -> Result<Option<String>> {
161+
let env_value = env(&self.env, target);
176162
if let Some(env_value) = env_value {
177163
return Ok(Some(env_value));
178164
}
179165
self.toml
180166
.as_ref()
181-
.map_or(Ok(None), |t| Ok(t.runner(target)))
167+
.map_or(Ok(None), |t| Ok(config(t, target)))
182168
}
183169

184-
pub fn env_passthrough(&self, target: &Target) -> Result<Vec<String>> {
185-
let (env_build, env_target) = self.env.passthrough(target);
186-
187-
let toml_getter = || self.toml.as_ref().map(|t| t.env_passthrough_build());
188-
let mut collected = Self::sum_of_env_toml_values(toml_getter, env_build)?;
170+
fn vec_from_config(
171+
&self,
172+
target: &Target,
173+
env: impl Fn(&Environment, &Target) -> (Option<Vec<String>>, Option<Vec<String>>),
174+
config_build: impl for<'a> Fn(&'a CrossToml) -> &'a [String],
175+
config_target: impl for<'a> Fn(&'a CrossToml, &Target) -> &'a [String],
176+
) -> Result<Vec<String>> {
177+
let (env_build, env_target) = env(&self.env, target);
189178

190-
let toml_getter = || self.toml.as_ref().map(|t| t.env_passthrough_target(target));
191-
collected.extend(Self::sum_of_env_toml_values(toml_getter, env_target)?);
179+
let mut collected = self.sum_of_env_toml_values(env_build, config_build)?;
180+
collected.extend(self.sum_of_env_toml_values(env_target, |t| config_target(t, target))?);
192181

193182
Ok(collected)
194183
}
195184

196-
pub fn env_volumes(&self, target: &Target) -> Result<Vec<String>> {
197-
let (env_build, env_target) = self.env.volumes(target);
198-
let toml_getter = || self.toml.as_ref().map(|t| t.env_volumes_build());
199-
let mut collected = Self::sum_of_env_toml_values(toml_getter, env_build)?;
185+
#[cfg(test)]
186+
fn new_with(toml: Option<CrossToml>, env: Environment) -> Self {
187+
Config { toml, env }
188+
}
200189

201-
let toml_getter = || self.toml.as_ref().map(|t| t.env_volumes_target(target));
202-
collected.extend(Self::sum_of_env_toml_values(toml_getter, env_target)?);
190+
pub fn xargo(&self, target: &Target) -> Option<bool> {
191+
self.bool_from_config(target, Environment::xargo, CrossToml::xargo)
192+
}
203193

204-
Ok(collected)
194+
pub fn image(&self, target: &Target) -> Result<Option<String>> {
195+
self.string_from_config(target, Environment::image, CrossToml::image)
196+
}
197+
198+
pub fn runner(&self, target: &Target) -> Result<Option<String>> {
199+
self.string_from_config(target, Environment::runner, CrossToml::runner)
200+
}
201+
202+
pub fn env_passthrough(&self, target: &Target) -> Result<Vec<String>> {
203+
self.vec_from_config(
204+
target,
205+
Environment::passthrough,
206+
CrossToml::env_passthrough_build,
207+
CrossToml::env_passthrough_target,
208+
)
209+
}
210+
211+
pub fn env_volumes(&self, target: &Target) -> Result<Vec<String>> {
212+
self.vec_from_config(
213+
target,
214+
Environment::volumes,
215+
CrossToml::env_volumes_build,
216+
CrossToml::env_volumes_target,
217+
)
205218
}
206219

207220
pub fn target(&self, target_list: &TargetList) -> Option<Target> {
@@ -213,15 +226,16 @@ impl Config {
213226
.and_then(|t| t.default_target(target_list))
214227
}
215228

216-
fn sum_of_env_toml_values(
217-
toml_getter: impl FnOnce() -> Option<Vec<String>>,
229+
fn sum_of_env_toml_values<'a>(
230+
&'a self,
218231
env_values: Option<Vec<String>>,
232+
toml_getter: impl FnOnce(&'a CrossToml) -> &'a [String],
219233
) -> Result<Vec<String>> {
220234
let mut collect = vec![];
221235
if let Some(mut vars) = env_values {
222236
collect.append(&mut vars);
223-
} else if let Some(toml_values) = toml_getter() {
224-
collect.extend(toml_values.into_iter());
237+
} else if let Some(toml_values) = self.toml.as_ref().map(toml_getter) {
238+
collect.extend(toml_values.iter().cloned());
225239
}
226240

227241
Ok(collect)
@@ -231,6 +245,7 @@ impl Config {
231245
#[cfg(test)]
232246
mod tests {
233247
use super::*;
248+
use crate::errors::*;
234249
use crate::{Target, TargetList};
235250

236251
fn target_list() -> TargetList {
@@ -257,24 +272,17 @@ mod tests {
257272
map.insert("CROSS_BUILD_XARGO", "tru");
258273

259274
let env = Environment::new(Some(map));
260-
261-
let res = env.xargo(&target());
262-
if res.is_ok() {
263-
panic!("invalid bool string parsing should fail");
264-
}
275+
assert_eq!(env.xargo(&target()), (Some(true), None));
265276
}
266277

267278
#[test]
268-
pub fn build_and_target_set_returns_tuple() -> Result<()> {
279+
pub fn build_and_target_set_returns_tuple() {
269280
let mut map = std::collections::HashMap::new();
270281
map.insert("CROSS_BUILD_XARGO", "true");
271282
map.insert("CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_XARGO", "false");
272283

273284
let env = Environment::new(Some(map));
274-
275-
assert_eq!(env.xargo(&target())?, (Some(true), Some(false)));
276-
277-
Ok(())
285+
assert_eq!(env.xargo(&target()), (Some(true), Some(false)));
278286
}
279287

280288
#[test]
@@ -329,7 +337,7 @@ mod tests {
329337

330338
let env = Environment::new(Some(map));
331339
let config = Config::new_with(Some(toml(TOML_BUILD_XARGO_FALSE)?), env);
332-
assert!(matches!(config.xargo(&target()), Ok(Some(true))));
340+
assert!(matches!(config.xargo(&target()), Some(true)));
333341

334342
Ok(())
335343
}
@@ -341,7 +349,7 @@ mod tests {
341349
let env = Environment::new(Some(map));
342350

343351
let config = Config::new_with(Some(toml(TOML_TARGET_XARGO_FALSE)?), env);
344-
assert!(matches!(config.xargo(&target()), Ok(Some(true))));
352+
assert!(matches!(config.xargo(&target()), Some(true)));
345353

346354
Ok(())
347355
}
@@ -352,7 +360,7 @@ mod tests {
352360
map.insert("CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_XARGO", "true");
353361
let env = Environment::new(Some(map));
354362
let config = Config::new_with(Some(toml(TOML_BUILD_XARGO_FALSE)?), env);
355-
assert!(matches!(config.xargo(&target()), Ok(Some(false))));
363+
assert!(matches!(config.xargo(&target()), Some(false)));
356364

357365
Ok(())
358366
}

0 commit comments

Comments
 (0)