Skip to content

Commit 894bb7e

Browse files
authored
Merge pull request #263 from nix-community/fix-homes
home: ensure `--configuration` is correctly passed to switch
2 parents 96bc0f5 + e8b5d1d commit 894bb7e

File tree

4 files changed

+140
-43
lines changed

4 files changed

+140
-43
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
1+
<!-- markdownlint-disable no-duplicate-headings -->
2+
13
# NH Changelog
24

5+
## 4.0.3
6+
7+
### Added
8+
9+
- Nh now supports specifying `NH_SUDO_ASKPASS` to pass a custom value to
10+
`SUDO_ASKPASS` in self-elevation. If specified, `sudo` will be called with
11+
`-A` and the `NH_SUDO_ASKPASS` will be `SUDO_ASKPASS` locally.
12+
13+
### Fixed
14+
15+
- Fix `--configuration` being ignored in `nh home switch`
16+
([#262](https://github.com/nix-community/nh/issues/262))
17+
318
## 4.0.2
419

520
### Added

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "nh"
3-
version = "4.0.2"
3+
version = "4.0.3"
44
edition = "2021"
55
license = "EUPL-1.2"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

src/home.rs

Lines changed: 123 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::env;
2+
use std::ffi::OsString;
23
use std::path::PathBuf;
34

45
use color_eyre::eyre::bail;
@@ -45,7 +46,7 @@ impl HomeRebuildArgs {
4546
let out_path: Box<dyn crate::util::MaybeTempPath> = match self.common.out_link {
4647
Some(ref p) => Box::new(p.clone()),
4748
None => Box::new({
48-
let dir = tempfile::Builder::new().prefix("nh-os").tempdir()?;
49+
let dir = tempfile::Builder::new().prefix("nh-home").tempdir()?;
4950
(dir.as_ref().join("result"), dir)
5051
}),
5152
};
@@ -71,7 +72,12 @@ impl HomeRebuildArgs {
7172
self.common.installable.clone()
7273
};
7374

74-
let toplevel = toplevel_for(installable, true, &self.extra_args)?;
75+
let toplevel = toplevel_for(
76+
installable,
77+
true,
78+
&self.extra_args,
79+
self.configuration.clone(),
80+
)?;
7581

7682
commands::Build::new(toplevel)
7783
.extra_arg("--out-link")
@@ -106,7 +112,7 @@ impl HomeRebuildArgs {
106112

107113
debug!("target_specialisation: {target_specialisation:?}");
108114

109-
let target_profile = match &target_specialisation {
115+
let target_profile: Box<dyn crate::util::MaybeTempPath> = match &target_specialisation {
110116
None => out_path,
111117
Some(spec) => Box::new(out_path.get_path().join("specialisation").join(spec)),
112118
};
@@ -158,13 +164,14 @@ fn toplevel_for<I, S>(
158164
installable: Installable,
159165
push_drv: bool,
160166
extra_args: I,
167+
configuration_name: Option<String>,
161168
) -> Result<Installable>
162169
where
163170
I: IntoIterator<Item = S>,
164171
S: AsRef<std::ffi::OsStr>,
165172
{
166173
let mut res = installable.clone();
167-
let extra_args = {
174+
let extra_args: Vec<OsString> = {
168175
let mut vec = Vec::new();
169176
for elem in extra_args.into_iter() {
170177
vec.push(elem.as_ref().to_owned());
@@ -180,25 +187,27 @@ where
180187
Installable::Flake {
181188
ref reference,
182189
ref mut attribute,
183-
} => 'flake: {
184-
// If user explicitly selects some other attribute, don't push homeConfigurations
190+
} => {
191+
// If user explicitly selects some other attribute in the installable itself
192+
// then don't push homeConfigurations
185193
if !attribute.is_empty() {
186-
break 'flake;
194+
debug!(
195+
"Using explicit attribute path from installable: {:?}",
196+
attribute
197+
);
198+
return Ok(res);
187199
}
188200

189201
attribute.push(String::from("homeConfigurations"));
190202

191-
// check for <user> and <user@hostname>
192-
let username = std::env::var("USER").expect("Couldn't get username");
193-
let hostname = get_hostname()?;
194-
195203
let flake_reference = reference.clone();
204+
let mut found_config = false;
196205

197-
let mut tried = vec![];
198-
199-
for attr in [format!("{username}@{hostname}"), username.to_string()] {
200-
let func = format!(r#" x: x ? "{}" "#, attr);
201-
let res = commands::Command::new("nix")
206+
// Check if an explicit configuration name was provided via the flag
207+
if let Some(config_name) = configuration_name {
208+
// Verify the provided configuration exists
209+
let func = format!(r#" x: x ? "{}" "#, config_name);
210+
let check_res = commands::Command::new("nix")
202211
.arg("eval")
203212
.args(&extra_args)
204213
.arg("--apply")
@@ -211,41 +220,109 @@ where
211220
.to_args(),
212221
)
213222
.run_capture()
214-
.expect("Checking home-manager output");
215-
216-
tried.push({
217-
let mut attribute = attribute.clone();
218-
attribute.push(attr.clone());
219-
attribute
220-
});
221-
222-
match res.map(|s| s.trim().to_owned()).as_deref() {
223+
.map_err(|e| {
224+
color_eyre::eyre::eyre!(
225+
"Failed running nix eval to check for explicit configuration '{}': {}",
226+
config_name,
227+
e
228+
)
229+
})?;
230+
231+
match check_res.map(|s| s.trim().to_owned()).as_deref() {
223232
Some("true") => {
224-
attribute.push(attr.clone());
233+
debug!("Using explicit configuration from flag: {}", config_name);
234+
attribute.push(config_name.clone());
225235
if push_drv {
226-
attribute.extend(toplevel);
236+
attribute.extend(toplevel.clone());
227237
}
228-
break 'flake;
238+
found_config = true;
229239
}
230240
_ => {
231-
continue;
241+
// Explicit config provided but not found
242+
let tried_attr_path = {
243+
let mut attr_path = attribute.clone();
244+
attr_path.push(config_name.clone());
245+
Installable::Flake {
246+
reference: flake_reference.clone(),
247+
attribute: attr_path,
248+
}
249+
.to_args()
250+
.join(" ")
251+
};
252+
bail!("Explicitly specified home-manager configuration not found: {tried_attr_path}");
232253
}
233254
}
234255
}
235256

236-
let tried_str = tried
237-
.into_iter()
238-
.map(|a| {
239-
let f = Installable::Flake {
240-
reference: flake_reference.clone(),
241-
attribute: a,
257+
// If no explicit config was found via flag, try automatic detection
258+
if !found_config {
259+
let username = std::env::var("USER").expect("Couldn't get username");
260+
let hostname = get_hostname()?;
261+
let mut tried = vec![];
262+
263+
for attr_name in [format!("{username}@{hostname}"), username.to_string()] {
264+
let func = format!(r#" x: x ? "{}" "#, attr_name);
265+
let check_res = commands::Command::new("nix")
266+
.arg("eval")
267+
.args(&extra_args)
268+
.arg("--apply")
269+
.arg(func)
270+
.args(
271+
(Installable::Flake {
272+
reference: flake_reference.clone(),
273+
attribute: attribute.clone(),
274+
})
275+
.to_args(),
276+
)
277+
.run_capture()
278+
.map_err(|e| {
279+
color_eyre::eyre::eyre!(
280+
"Failed running nix eval to check for automatic configuration '{}': {}",
281+
attr_name,
282+
e
283+
)
284+
})?;
285+
286+
let current_try_attr = {
287+
let mut attr_path = attribute.clone();
288+
attr_path.push(attr_name.clone());
289+
attr_path
242290
};
243-
f.to_args().join(" ")
244-
})
245-
.collect::<Vec<_>>()
246-
.join(", ");
291+
tried.push(current_try_attr.clone());
292+
293+
match check_res.map(|s| s.trim().to_owned()).as_deref() {
294+
Some("true") => {
295+
debug!("Using automatically detected configuration: {}", attr_name);
296+
attribute.push(attr_name.clone());
297+
if push_drv {
298+
attribute.extend(toplevel.clone());
299+
}
300+
found_config = true;
301+
break;
302+
}
303+
_ => {
304+
continue;
305+
}
306+
}
307+
}
247308

248-
bail!("Couldn't find home-manager configuration, tried {tried_str}");
309+
// If still not found after automatic detection, error out
310+
if !found_config {
311+
let tried_str = tried
312+
.into_iter()
313+
.map(|a| {
314+
Installable::Flake {
315+
reference: flake_reference.clone(),
316+
attribute: a,
317+
}
318+
.to_args()
319+
.join(" ")
320+
})
321+
.collect::<Vec<_>>()
322+
.join(", ");
323+
bail!("Couldn't find home-manager configuration automatically, tried: {tried_str}");
324+
}
325+
}
249326
}
250327
Installable::File {
251328
ref mut attribute, ..
@@ -288,7 +365,12 @@ impl HomeReplArgs {
288365
self.installable
289366
};
290367

291-
let toplevel = toplevel_for(installable, false, &self.extra_args)?;
368+
let toplevel = toplevel_for(
369+
installable,
370+
false,
371+
&self.extra_args,
372+
self.configuration.clone(),
373+
)?;
292374

293375
Command::new("nix")
294376
.arg("repl")

0 commit comments

Comments
 (0)