Skip to content

Commit 407d6c4

Browse files
author
faukah
committed
installable: make installable attribute be a String
There is no point in making the attribute of an Installable be a Vec. Attributes can are used in one of: - Flake: FLAKEREF#ATTRIBUTE: Here, we cannot pass multiple attributes anyways. - File, Expression: The Nix expression (in that file), or any selected attribute, must evaluate to a derivation. It is fine to only accept a single attribute here, since no one is going to add several attributes corresponding to {nixos,home,darwin}Configurations, here.
1 parent 1bff86a commit 407d6c4

File tree

5 files changed

+45
-149
lines changed

5 files changed

+45
-149
lines changed

src/commands.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,7 +1124,7 @@ mod tests {
11241124
fn test_build_new() {
11251125
let installable = Installable::Flake {
11261126
reference: "github:user/repo".to_string(),
1127-
attribute: vec!["package".to_string()],
1127+
attribute: "package".to_string(),
11281128
};
11291129

11301130
let build = Build::new(installable.clone());
@@ -1140,7 +1140,7 @@ mod tests {
11401140
fn test_build_builder_pattern() {
11411141
let installable = Installable::Flake {
11421142
reference: "github:user/repo".to_string(),
1143-
attribute: vec!["package".to_string()],
1143+
attribute: "package".to_string(),
11441144
};
11451145

11461146
let build = Build::new(installable)

src/darwin.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,7 @@ impl DarwinRebuildArgs {
8686
Some(r) => r.to_owned(),
8787
None => return Err(eyre!("NH_DARWIN_FLAKE missing reference part")),
8888
};
89-
let attribute = elems
90-
.next()
91-
.map(crate::installable::parse_attribute)
92-
.unwrap_or_default();
89+
let attribute = elems.next().unwrap_or_default().to_string();
9390

9491
Installable::Flake {
9592
reference,
@@ -107,8 +104,7 @@ impl DarwinRebuildArgs {
107104
// If user explicitly selects some other attribute, don't push
108105
// darwinConfigurations
109106
if attribute.is_empty() {
110-
attribute.push(String::from("darwinConfigurations"));
111-
attribute.push(hostname.clone());
107+
*attribute = format!("darwinConfigurations.{hostname}");
112108
}
113109
}
114110

@@ -205,10 +201,7 @@ impl DarwinReplArgs {
205201
Some(r) => r.to_owned(),
206202
None => return Err(eyre!("NH_DARWIN_FLAKE missing reference part")),
207203
};
208-
let attribute = elems
209-
.next()
210-
.map(crate::installable::parse_attribute)
211-
.unwrap_or_default();
204+
let attribute = elems.next().unwrap_or_default().to_string();
212205

213206
Installable::Flake {
214207
reference,
@@ -229,8 +222,7 @@ impl DarwinReplArgs {
229222
} = target_installable
230223
{
231224
if attribute.is_empty() {
232-
attribute.push(String::from("darwinConfigurations"));
233-
attribute.push(hostname);
225+
*attribute = format!("darwinConfigurations.{hostname}");
234226
}
235227
}
236228

src/home.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,7 @@ impl HomeRebuildArgs {
6969
Some(r) => r.to_owned(),
7070
None => return Err(eyre!("NH_HOME_FLAKE missing reference part")),
7171
};
72-
let attribute = elems
73-
.next()
74-
.map(crate::installable::parse_attribute)
75-
.unwrap_or_default();
72+
let attribute = elems.next().unwrap_or_default().to_string();
7673

7774
Installable::Flake {
7875
reference,
@@ -223,7 +220,7 @@ where
223220
return Ok(res);
224221
}
225222

226-
attribute.push(String::from("homeConfigurations"));
223+
*attribute = String::from("homeConfigurations");
227224

228225
let flake_reference = reference.clone();
229226
let mut found_config = false;
@@ -254,7 +251,7 @@ where
254251
if check_res.map(|s| s.trim().to_owned()).as_deref() == Some("true") {
255252
debug!("Using explicit configuration from flag: {config_name:?}");
256253

257-
attribute.push(config_name);
254+
attribute.push_str(&config_name);
258255
if push_drv {
259256
attribute.extend(toplevel.clone());
260257
}
@@ -264,7 +261,7 @@ where
264261
// Explicit config provided but not found
265262
let tried_attr_path = {
266263
let mut attr_path = attribute.clone();
267-
attr_path.push(config_name);
264+
attr_path.push_str(&config_name);
268265
Installable::Flake {
269266
reference: flake_reference,
270267
attribute: attr_path,
@@ -309,7 +306,7 @@ where
309306

310307
let current_try_attr = {
311308
let mut attr_path = attribute.clone();
312-
attr_path.push(attr_name.clone());
309+
attr_path.push_str(&attr_name);
313310
attr_path
314311
};
315312
tried.push(current_try_attr.clone());
@@ -318,7 +315,7 @@ where
318315
check_res.map(|s| s.trim().to_owned()).as_deref()
319316
{
320317
debug!("Using automatically detected configuration: {}", attr_name);
321-
attribute.push(attr_name);
318+
attribute.push_str(&attr_name);
322319
if push_drv {
323320
attribute.extend(toplevel.clone());
324321
}
@@ -379,10 +376,7 @@ impl HomeReplArgs {
379376
Some(r) => r.to_owned(),
380377
None => return Err(eyre!("NH_HOME_FLAKE missing reference part")),
381378
};
382-
let attribute = elems
383-
.next()
384-
.map(crate::installable::parse_attribute)
385-
.unwrap_or_default();
379+
let attribute = elems.next().unwrap_or_default().to_string();
386380

387381
Installable::Flake {
388382
reference,

src/installable.rs

Lines changed: 26 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ use yansi::{Color, Paint};
1010
pub enum Installable {
1111
Flake {
1212
reference: String,
13-
attribute: Vec<String>,
13+
attribute: String,
1414
},
1515
File {
1616
path: PathBuf,
17-
attribute: Vec<String>,
17+
attribute: String,
1818
},
1919
Store {
2020
path: PathBuf,
2121
},
2222
Expression {
2323
expression: String,
24-
attribute: Vec<String>,
24+
attribute: String,
2525
},
2626
}
2727

@@ -51,14 +51,14 @@ impl FromArgMatches for Installable {
5151
if let Some(f) = file {
5252
return Ok(Self::File {
5353
path: PathBuf::from(f),
54-
attribute: parse_attribute(installable.cloned().unwrap_or_default()),
54+
attribute: installable.cloned().unwrap_or_default(),
5555
});
5656
}
5757

5858
if let Some(e) = expr {
5959
return Ok(Self::Expression {
6060
expression: e.to_string(),
61-
attribute: parse_attribute(installable.cloned().unwrap_or_default()),
61+
attribute: installable.cloned().unwrap_or_default(),
6262
});
6363
}
6464

@@ -67,12 +67,10 @@ impl FromArgMatches for Installable {
6767
let reference = elems.next().unwrap().to_owned();
6868
return Ok(Self::Flake {
6969
reference,
70-
attribute: parse_attribute(
71-
elems
72-
.next()
73-
.map(std::string::ToString::to_string)
74-
.unwrap_or_default(),
75-
),
70+
attribute: elems
71+
.next()
72+
.map(std::string::ToString::to_string)
73+
.unwrap_or_default(),
7674
});
7775
}
7876

@@ -82,12 +80,10 @@ impl FromArgMatches for Installable {
8280
let mut elems = f.splitn(2, '#');
8381
Installable::Flake {
8482
reference: elems.next().unwrap().to_owned(),
85-
attribute: parse_attribute(
86-
elems
87-
.next()
88-
.map(std::string::ToString::to_string)
89-
.unwrap_or_default(),
90-
),
83+
attribute: elems
84+
.next()
85+
.map(std::string::ToString::to_string)
86+
.unwrap_or_default(),
9187
}
9288
})
9389
}
@@ -124,7 +120,7 @@ impl FromArgMatches for Installable {
124120
if let Ok(f) = env::var("NH_FILE") {
125121
return Ok(Self::File {
126122
path: PathBuf::from(f),
127-
attribute: parse_attribute(env::var("NH_ATTRP").unwrap_or_default()),
123+
attribute: env::var("NH_ATTRP").unwrap_or_default(),
128124
});
129125
}
130126

@@ -206,82 +202,35 @@ Nix accepts various kinds of installables:
206202
}
207203
}
208204

209-
// TODO: should handle quoted attributes, like foo."bar.baz" -> ["foo",
210-
// "bar.baz"] maybe use chumsky?
211-
pub fn parse_attribute<S>(s: S) -> Vec<String>
212-
where
213-
S: AsRef<str>,
214-
{
215-
let s = s.as_ref();
216-
let mut res = Vec::new();
217-
218-
if s.is_empty() {
219-
return res;
220-
}
221-
222-
let mut in_quote = false;
223-
224-
let mut elem = String::new();
225-
for char in s.chars() {
226-
match char {
227-
'.' => {
228-
if in_quote {
229-
elem.push(char);
230-
} else {
231-
res.push(elem.clone());
232-
elem = String::new();
233-
}
234-
},
235-
'"' => {
236-
in_quote = !in_quote;
237-
},
238-
_ => elem.push(char),
239-
}
240-
}
241-
242-
res.push(elem);
243-
244-
assert!(!in_quote, "Failed to parse attribute: {s}");
245-
246-
res
247-
}
248-
249-
#[test]
250-
fn test_parse_attribute() {
251-
assert_eq!(parse_attribute(r"foo.bar"), vec!["foo", "bar"]);
252-
assert_eq!(parse_attribute(r#"foo."bar.baz""#), vec!["foo", "bar.baz"]);
253-
let v: Vec<String> = vec![];
254-
assert_eq!(parse_attribute(""), v);
255-
}
256-
257205
impl Installable {
258206
#[must_use]
259207
pub fn to_args(&self) -> Vec<String> {
260-
let mut res = Vec::new();
261208
match self {
262209
Self::Flake {
263210
reference,
264211
attribute,
265212
} => {
266-
res.push(format!("{reference}#{}", join_attribute(attribute)));
213+
vec![format!("{reference}#{attribute}")]
267214
},
268215
Self::File { path, attribute } => {
269-
res.push(String::from("--file"));
270-
res.push(path.to_str().unwrap().to_string());
271-
res.push(join_attribute(attribute));
216+
vec![
217+
String::from("--file"),
218+
path.to_str().unwrap().to_string(),
219+
attribute.to_string(),
220+
]
272221
},
273222
Self::Expression {
274223
expression,
275224
attribute,
276225
} => {
277-
res.push(String::from("--expr"));
278-
res.push(expression.to_string());
279-
res.push(join_attribute(attribute));
226+
vec![
227+
String::from("--expr"),
228+
expression.to_string(),
229+
attribute.to_string(),
230+
]
280231
},
281-
Self::Store { path } => res.push(path.to_str().unwrap().to_string()),
232+
Self::Store { path } => vec![path.to_str().unwrap().to_string()],
282233
}
283-
284-
res
285234
}
286235
}
287236

@@ -306,38 +255,6 @@ fn test_installable_to_args() {
306255
);
307256
}
308257

309-
fn join_attribute<I>(attribute: I) -> String
310-
where
311-
I: IntoIterator,
312-
I::Item: AsRef<str>,
313-
{
314-
let mut res = String::new();
315-
let mut first = true;
316-
for elem in attribute {
317-
if first {
318-
first = false;
319-
} else {
320-
res.push('.');
321-
}
322-
323-
let s = elem.as_ref();
324-
325-
if s.contains('.') {
326-
res.push_str(&format!(r#""{s}""#));
327-
} else {
328-
res.push_str(s);
329-
}
330-
}
331-
332-
res
333-
}
334-
335-
#[test]
336-
fn test_join_attribute() {
337-
assert_eq!(join_attribute(vec!["foo", "bar"]), "foo.bar");
338-
assert_eq!(join_attribute(vec!["foo", "bar.baz"]), r#"foo."bar.baz""#);
339-
}
340-
341258
impl Installable {
342259
#[must_use]
343260
pub const fn str_kind(&self) -> &str {

0 commit comments

Comments
 (0)