Skip to content

Commit 849f369

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 ee2fc1b commit 849f369

4 files changed

Lines changed: 152 additions & 113 deletions

File tree

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: 114 additions & 91 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, Convert: Fn(&str) -> T>(
27+
&self,
28+
var: &str,
29+
target: &Target,
30+
convert: Convert,
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,113 @@ 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<Env, Config>(
128+
&self,
129+
target: &Target,
130+
env: Env,
131+
config: Config,
132+
) -> Option<bool>
133+
where
134+
Env: Fn(&Environment, &Target) -> (Option<bool>, Option<bool>),
135+
Config: Fn(&CrossToml, &Target) -> (Option<bool>, Option<bool>),
136+
{
137+
let (env_build, env_target) = env(&self.env, target);
138+
let (toml_build, toml_target) = if let Some(ref toml) = self.toml {
139+
config(toml, target)
148140
} else {
149141
(None, None)
150142
};
151143

152-
match (build_xargo, toml_build_xargo) {
153-
(xargo @ Some(_), _) => return Ok(xargo),
154-
(None, xargo @ Some(_)) => return Ok(xargo),
144+
match (env_build, toml_build) {
145+
(Some(value), _) => return Some(value),
146+
(None, Some(value)) => return Some(value),
155147
(None, None) => {}
156148
};
157149

158-
match (target_xargo, toml_target_xargo) {
159-
(xargo @ Some(_), _) => return Ok(xargo),
160-
(None, xargo @ Some(_)) => return Ok(xargo),
150+
match (env_target, toml_target) {
151+
(Some(value), _) => return Some(value),
152+
(None, Some(value)) => return Some(value),
161153
(None, None) => {}
162154
};
163-
Ok(None)
164-
}
165155

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)))
156+
None
172157
}
173158

174-
pub fn runner(&self, target: &Target) -> Result<Option<String>> {
175-
let env_value = self.env.runner(target);
159+
fn string_from_config<Env, Config>(
160+
&self,
161+
target: &Target,
162+
env: Env,
163+
config: Config,
164+
) -> Result<Option<String>>
165+
where
166+
Env: Fn(&Environment, &Target) -> Option<String>,
167+
Config: Fn(&CrossToml, &Target) -> Option<String>,
168+
{
169+
let env_value = env(&self.env, target);
176170
if let Some(env_value) = env_value {
177171
return Ok(Some(env_value));
178172
}
179173
self.toml
180174
.as_ref()
181-
.map_or(Ok(None), |t| Ok(t.runner(target)))
175+
.map_or(Ok(None), |t| Ok(config(t, target)))
182176
}
183177

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());
178+
fn vec_from_config<Env, ConfigBuild, ConfigTarget>(
179+
&self,
180+
target: &Target,
181+
env: Env,
182+
config_build: ConfigBuild,
183+
config_target: ConfigTarget,
184+
) -> Result<Vec<String>>
185+
where
186+
Env: Fn(&Environment, &Target) -> (Option<Vec<String>>, Option<Vec<String>>),
187+
ConfigBuild: Fn(&CrossToml) -> Vec<String>,
188+
ConfigTarget: Fn(&CrossToml, &Target) -> Vec<String>,
189+
{
190+
let (env_build, env_target) = env(&self.env, target);
191+
192+
let toml_getter = || self.toml.as_ref().map(config_build);
188193
let mut collected = Self::sum_of_env_toml_values(toml_getter, env_build)?;
189194

190-
let toml_getter = || self.toml.as_ref().map(|t| t.env_passthrough_target(target));
195+
let toml_getter = || self.toml.as_ref().map(|t| config_target(t, target));
191196
collected.extend(Self::sum_of_env_toml_values(toml_getter, env_target)?);
192197

193198
Ok(collected)
194199
}
195200

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)?;
201+
#[cfg(test)]
202+
fn new_with(toml: Option<CrossToml>, env: Environment) -> Self {
203+
Config { toml, env }
204+
}
200205

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)?);
206+
pub fn xargo(&self, target: &Target) -> Option<bool> {
207+
self.bool_from_config(target, Environment::xargo, CrossToml::xargo)
208+
}
203209

204-
Ok(collected)
210+
pub fn image(&self, target: &Target) -> Result<Option<String>> {
211+
self.string_from_config(target, Environment::image, CrossToml::image)
212+
}
213+
214+
pub fn runner(&self, target: &Target) -> Result<Option<String>> {
215+
self.string_from_config(target, Environment::runner, CrossToml::runner)
216+
}
217+
218+
pub fn env_passthrough(&self, target: &Target) -> Result<Vec<String>> {
219+
self.vec_from_config(
220+
target,
221+
Environment::passthrough,
222+
CrossToml::env_passthrough_build,
223+
CrossToml::env_passthrough_target,
224+
)
225+
}
226+
227+
pub fn env_volumes(&self, target: &Target) -> Result<Vec<String>> {
228+
self.vec_from_config(
229+
target,
230+
Environment::volumes,
231+
CrossToml::env_volumes_build,
232+
CrossToml::env_volumes_target,
233+
)
205234
}
206235

207236
pub fn target(&self, target_list: &TargetList) -> Option<Target> {
@@ -231,6 +260,7 @@ impl Config {
231260
#[cfg(test)]
232261
mod tests {
233262
use super::*;
263+
use crate::errors::*;
234264
use crate::{Target, TargetList};
235265

236266
fn target_list() -> TargetList {
@@ -257,24 +287,17 @@ mod tests {
257287
map.insert("CROSS_BUILD_XARGO", "tru");
258288

259289
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-
}
290+
assert_eq!(env.xargo(&target()), (Some(true), None));
265291
}
266292

267293
#[test]
268-
pub fn build_and_target_set_returns_tuple() -> Result<()> {
294+
pub fn build_and_target_set_returns_tuple() {
269295
let mut map = std::collections::HashMap::new();
270296
map.insert("CROSS_BUILD_XARGO", "true");
271297
map.insert("CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_XARGO", "false");
272298

273299
let env = Environment::new(Some(map));
274-
275-
assert_eq!(env.xargo(&target())?, (Some(true), Some(false)));
276-
277-
Ok(())
300+
assert_eq!(env.xargo(&target()), (Some(true), Some(false)));
278301
}
279302

280303
#[test]
@@ -329,7 +352,7 @@ mod tests {
329352

330353
let env = Environment::new(Some(map));
331354
let config = Config::new_with(Some(toml(TOML_BUILD_XARGO_FALSE)?), env);
332-
assert!(matches!(config.xargo(&target()), Ok(Some(true))));
355+
assert!(matches!(config.xargo(&target()), Some(true)));
333356

334357
Ok(())
335358
}
@@ -341,7 +364,7 @@ mod tests {
341364
let env = Environment::new(Some(map));
342365

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

346369
Ok(())
347370
}
@@ -352,7 +375,7 @@ mod tests {
352375
map.insert("CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_XARGO", "true");
353376
let env = Environment::new(Some(map));
354377
let config = Config::new_with(Some(toml(TOML_BUILD_XARGO_FALSE)?), env);
355-
assert!(matches!(config.xargo(&target()), Ok(Some(false))));
378+
assert!(matches!(config.xargo(&target()), Some(true)));
356379

357380
Ok(())
358381
}

0 commit comments

Comments
 (0)