Skip to content

Commit 27a7939

Browse files
authored
Merge pull request #296 from nix-community/fix-diffs
treewide: fix nvd diffs and internal cleanup
2 parents 45048d3 + 272e743 commit 27a7939

File tree

5 files changed

+91
-26
lines changed

5 files changed

+91
-26
lines changed

src/commands.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub struct Command {
2929
args: Vec<OsString>,
3030
elevate: bool,
3131
ssh: Option<String>,
32+
show_output: bool,
3233
}
3334

3435
impl Command {
@@ -40,6 +41,7 @@ impl Command {
4041
args: vec![],
4142
elevate: false,
4243
ssh: None,
44+
show_output: false,
4345
}
4446
}
4547

@@ -53,6 +55,11 @@ impl Command {
5355
self
5456
}
5557

58+
pub const fn show_output(mut self, show_output: bool) -> Self {
59+
self.show_output = show_output;
60+
self
61+
}
62+
5663
pub fn ssh(mut self, ssh: Option<String>) -> Self {
5764
self.ssh = ssh;
5865
self
@@ -113,8 +120,15 @@ impl Command {
113120
} else {
114121
Exec::cmd(&self.command).args(&self.args)
115122
};
116-
let cmd =
117-
ssh_wrap(cmd.stderr(Redirection::None), self.ssh.as_deref()).stdout(Redirection::None);
123+
// Configure output redirection based on show_output setting
124+
let cmd = ssh_wrap(
125+
if self.show_output {
126+
cmd.stderr(Redirection::Merge)
127+
} else {
128+
cmd.stderr(Redirection::None).stdout(Redirection::None)
129+
},
130+
self.ssh.as_deref(),
131+
);
118132

119133
if let Some(m) = &self.message {
120134
info!("{}", m);

src/darwin.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,24 @@ impl DarwinRebuildArgs {
103103

104104
let target_profile = out_path.get_path().to_owned();
105105

106+
// Take a strong reference to out_path to prevent premature dropping
107+
// We need to keep this alive through the entire function scope to prevent
108+
// the tempdir from being dropped early, which would cause nvd diff to fail
109+
#[allow(unused_variables)]
110+
let keep_alive = out_path.get_path().to_owned();
111+
debug!(
112+
"Registered keep_alive reference to: {}",
113+
keep_alive.display()
114+
);
115+
106116
target_profile.try_exists().context("Doesn't exist")?;
107117

108118
Command::new("nvd")
109119
.arg("diff")
110120
.arg(CURRENT_PROFILE)
111121
.arg(&target_profile)
112122
.message("Comparing changes")
123+
.show_output(true)
113124
.run()?;
114125

115126
if self.common.ask && !self.common.dry && !matches!(variant, Build) {
@@ -151,6 +162,10 @@ impl DarwinRebuildArgs {
151162

152163
// Make sure out_path is not accidentally dropped
153164
// https://docs.rs/tempfile/3.12.0/tempfile/index.html#early-drop-pitfall
165+
debug!(
166+
"Completed operation with output path: {:?}",
167+
out_path.get_path()
168+
);
154169
drop(out_path);
155170

156171
Ok(())

src/generations.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub fn from_dir(generation_dir: &Path) -> Option<u64> {
4343
})
4444
}
4545

46-
pub fn describe(generation_dir: &Path, current_profile: &Path) -> Option<GenerationInfo> {
46+
pub fn describe(generation_dir: &Path) -> Option<GenerationInfo> {
4747
let generation_number = from_dir(generation_dir)?;
4848

4949
// Get metadata once and reuse for both date and existence checks

src/home.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,17 @@ impl HomeRebuildArgs {
112112

113113
debug!("target_specialisation: {target_specialisation:?}");
114114

115-
let target_profile: Box<dyn crate::util::MaybeTempPath> = match &target_specialisation {
116-
None => out_path,
117-
Some(spec) => Box::new(out_path.get_path().join("specialisation").join(spec)),
118-
};
115+
let target_profile: Box<dyn crate::util::MaybeTempPath> =
116+
if let Some(spec) = &target_specialisation {
117+
Box::new(out_path.get_path().join("specialisation").join(spec))
118+
} else {
119+
out_path
120+
};
121+
122+
// Take a strong reference to ensure the TempDir isn't dropped
123+
// This prevents early dropping of the tempdir, which causes nvd diff to fail
124+
#[allow(unused_variables)]
125+
let keep_alive = target_profile.get_path().to_owned();
119126

120127
// just do nothing for None case (fresh installs)
121128
if let Some(generation) = prev_generation {
@@ -124,6 +131,7 @@ impl HomeRebuildArgs {
124131
.arg(generation)
125132
.arg(target_profile.get_path())
126133
.message("Comparing changes")
134+
.show_output(true)
127135
.run()?;
128136
}
129137

@@ -154,6 +162,10 @@ impl HomeRebuildArgs {
154162

155163
// Make sure out_path is not accidentally dropped
156164
// https://docs.rs/tempfile/3.12.0/tempfile/index.html#early-drop-pitfall
165+
debug!(
166+
"Completed operation with output path: {:?}",
167+
target_profile.get_path()
168+
);
157169
drop(target_profile);
158170

159171
Ok(())

src/nixos.rs

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ enum OsRebuildVariant {
5656
impl OsBuildVmArgs {
5757
fn build_vm(self) -> Result<()> {
5858
let final_attr = get_final_attr(true, self.with_bootloader);
59+
debug!("Building VM with attribute: {}", final_attr);
5960
self.common
6061
.rebuild(OsRebuildVariant::BuildVm, Some(final_attr))
6162
}
@@ -97,7 +98,16 @@ impl OsRebuildArgs {
9798
Some(h) => h.to_owned(),
9899
None => match &system_hostname {
99100
Some(hostname) => {
100-
tracing::warn!("Guessing system is {hostname} for a VM image. If this isn't intended, use --hostname to change.");
101+
// Only show the warning if we're explicitly building a VM
102+
// by directly calling build_vm(), not when the BuildVm variant
103+
// is used internally via other code paths
104+
if matches!(variant, OsRebuildVariant::BuildVm)
105+
&& final_attr
106+
.as_deref()
107+
.map_or(false, |attr| attr == "vm" || attr == "vmWithBootLoader")
108+
{
109+
tracing::warn!("Guessing system is {hostname} for a VM image. If this isn't intended, use --hostname to change.");
110+
}
101111
hostname.clone()
102112
}
103113
None => return Err(eyre!("Unable to fetch hostname, and no hostname supplied.")),
@@ -143,7 +153,6 @@ impl OsRebuildArgs {
143153
BuildVm => "Building NixOS VM image",
144154
_ => "Building NixOS configuration",
145155
};
146-
147156
commands::Build::new(toplevel)
148157
.extra_arg("--out-link")
149158
.extra_arg(out_path.get_path())
@@ -168,19 +177,38 @@ impl OsRebuildArgs {
168177
Some(spec) => out_path.get_path().join("specialisation").join(spec),
169178
};
170179

171-
debug!("exists: {}", target_profile.exists());
180+
debug!("Output path: {}", out_path.get_path().display());
181+
debug!("Target profile path: {}", target_profile.display());
182+
debug!("Target profile exists: {}", target_profile.exists());
183+
184+
// Note: out_path itself is kept alive until the end of this function,
185+
// which prevents the tempdir (if any) from being dropped early
172186

173-
target_profile.try_exists().context("Doesn't exist")?;
187+
if !target_profile
188+
.try_exists()
189+
.context("Failed to check if target profile exists")?
190+
{
191+
return Err(eyre!(
192+
"Target profile path does not exist: {}",
193+
target_profile.display()
194+
));
195+
}
174196

175197
if self.build_host.is_none()
176198
&& self.target_host.is_none()
177199
&& system_hostname.map_or(true, |h| h == target_hostname)
178200
{
201+
debug!(
202+
"Comparing with target profile: {}",
203+
target_profile.display()
204+
);
205+
179206
Command::new("nvd")
180207
.arg("diff")
181208
.arg(CURRENT_PROFILE)
182209
.arg(&target_profile)
183210
.message("Comparing changes")
211+
.show_output(true)
184212
.run()?;
185213
} else {
186214
debug!("Not running nvd as the target hostname is different from the system hostname.");
@@ -253,8 +281,12 @@ impl OsRebuildArgs {
253281
.run()?;
254282
}
255283

256-
// Make sure out_path is not accidentally dropped
284+
// Make sure out_path is not acidentally dropped
257285
// https://docs.rs/tempfile/3.12.0/tempfile/index.html#early-drop-pitfall
286+
debug!(
287+
"Completed operation with output path: {:?}",
288+
out_path.get_path()
289+
);
258290
drop(out_path);
259291

260292
Ok(())
@@ -305,6 +337,7 @@ impl OsRollbackArgs {
305337
.arg(CURRENT_PROFILE)
306338
.arg(&generation_link)
307339
.message("Comparing changes")
340+
.show_output(true)
308341
.run()?;
309342

310343
if self.dry {
@@ -345,9 +378,6 @@ impl OsRollbackArgs {
345378
.message("Setting system profile")
346379
.run()?;
347380

348-
// Set up rollback protection flag
349-
let mut rollback_profile = false;
350-
351381
// Determine the correct profile to use with specialisations
352382
let final_profile = match &target_specialisation {
353383
None => generation_link,
@@ -383,10 +413,8 @@ impl OsRollbackArgs {
383413
);
384414
}
385415
Err(e) => {
386-
rollback_profile = true;
387-
388416
// If activation fails, rollback the profile
389-
if rollback_profile && current_gen_number > 0 {
417+
if current_gen_number > 0 {
390418
let current_gen_link =
391419
profile_dir.join(format!("system-{current_gen_number}-link"));
392420

@@ -421,7 +449,7 @@ fn find_previous_generation() -> Result<generations::GenerationInfo> {
421449
if let Some(filename) = path.file_name() {
422450
if let Some(name) = filename.to_str() {
423451
if name.starts_with("system-") && name.ends_with("-link") {
424-
return generations::describe(&path, &profile_path);
452+
return generations::describe(&path);
425453
}
426454
}
427455
}
@@ -467,7 +495,7 @@ fn find_generation_by_number(number: u64) -> Result<generations::GenerationInfo>
467495
if let Some(filename) = path.file_name() {
468496
if let Some(name) = filename.to_str() {
469497
if name.starts_with("system-") && name.ends_with("-link") {
470-
return generations::describe(&path, &profile_path);
498+
return generations::describe(&path);
471499
}
472500
}
473501
}
@@ -492,11 +520,7 @@ fn get_current_generation_number() -> Result<u64> {
492520
.parent()
493521
.unwrap_or(Path::new("/nix/var/nix/profiles")),
494522
)?
495-
.filter_map(|entry| {
496-
entry
497-
.ok()
498-
.and_then(|e| generations::describe(&e.path(), &profile_path))
499-
})
523+
.filter_map(|entry| entry.ok().and_then(|e| generations::describe(&e.path())))
500524
.collect();
501525

502526
let current_gen = generations
@@ -641,7 +665,7 @@ impl OsGenerationsArgs {
641665

642666
let descriptions: Vec<generations::GenerationInfo> = generations
643667
.iter()
644-
.filter_map(|gen_dir| generations::describe(gen_dir, &profile))
668+
.filter_map(|gen_dir| generations::describe(gen_dir))
645669
.collect();
646670

647671
generations::print_info(descriptions);

0 commit comments

Comments
 (0)