From b61886f0f9fba82322ac916bfc1d085f22b22d81 Mon Sep 17 00:00:00 2001 From: Gideon <87426140+GideonBear@users.noreply.github.com> Date: Sat, 8 Nov 2025 11:07:01 +0100 Subject: [PATCH] ref(nix): Deduplicate run_nix and run_nix_self_upgrade nix --version checking (#1376) --- src/steps/os/unix.rs | 132 +++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 60 deletions(-) diff --git a/src/steps/os/unix.rs b/src/steps/os/unix.rs index edda5b25..3919fdb0 100644 --- a/src/steps/os/unix.rs +++ b/src/steps/os/unix.rs @@ -418,6 +418,74 @@ pub fn run_guix(ctx: &ExecutionContext) -> Result<()> { Ok(()) } +struct NixVersion { + version_string: String, +} + +impl NixVersion { + fn new(ctx: &ExecutionContext, nix: &Path) -> Result { + let version_output = ctx.execute(nix).arg("--version").output_checked_utf8()?; + + debug!( + output=%version_output, + "`nix --version` output" + ); + + let version_string = version_output + .stdout + .lines() + .next() + .ok_or_else(|| eyre!("`nix --version` output is empty"))? + .to_string(); + + if version_string.is_empty() { + return Err(eyre!("`nix --version` output was empty")); + } + + Ok(Self { version_string }) + } + + fn version(&self) -> Result { + static NIX_VERSION_REGEX: LazyLock = + LazyLock::new(|| Regex::new(r"^nix \([^)]*\) ([0-9.]+)").expect("Nix version regex always compiles")); + + let captures = NIX_VERSION_REGEX + .captures(&self.version_string) + .ok_or_else(|| eyre!(output_changed_message!("nix --version", "regex did not match")))?; + let raw_version = &captures[1]; + + debug!("Raw Nix version: {raw_version}"); + + // Nix 2.29.0 outputs "2.29" instead of "2.29.0", so we need to add that if necessary. + let corrected_raw_version = if raw_version.chars().filter(|&c| c == '.').count() == 1 { + &format!("{raw_version}.0") + } else { + raw_version + }; + + debug!("Corrected raw Nix version: {corrected_raw_version}"); + + let version = Version::parse(corrected_raw_version) + .wrap_err_with(|| output_changed_message!("nix --version", "Invalid version"))?; + + debug!("Nix version: {:?}", version); + + Ok(version) + } + + fn is_lix(&self) -> bool { + let is_lix = self.version_string.contains("Lix"); + debug!(?is_lix); + is_lix + } + + fn is_determinate_nix(&self) -> bool { + let is_determinate_nix = self.version_string.contains("Determinate Nix"); + debug!(?is_determinate_nix); + is_determinate_nix + } +} + pub fn run_nix(ctx: &ExecutionContext) -> Result<()> { let nix = require("nix")?; let nix_channel = require("nix-channel")?; @@ -447,54 +515,11 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> { ctx.execute(nix_channel).arg("--update").status_checked()?; - let mut get_version_cmd = ctx.execute(&nix); - get_version_cmd.arg("--version"); - let get_version_cmd_output = get_version_cmd.output_checked_utf8()?; - let get_version_cmd_first_line_stdout = get_version_cmd_output - .stdout - .lines() - .next() - .ok_or_else(|| eyre!("`nix --version` output is empty"))?; - - let is_lix = get_version_cmd_first_line_stdout.contains("Lix"); - - debug!( - output=%get_version_cmd_output, - ?is_lix, - "`nix --version` output" - ); - - static NIX_VERSION_REGEX: LazyLock = - LazyLock::new(|| Regex::new(r"^nix \([^)]*\) ([0-9.]+)").expect("Nix version regex always compiles")); - - if get_version_cmd_first_line_stdout.is_empty() { - return Err(eyre!("`nix --version` output was empty")); - } - - let captures = NIX_VERSION_REGEX - .captures(get_version_cmd_first_line_stdout) - .ok_or_else(|| eyre!(output_changed_message!("nix --version", "regex did not match")))?; - let raw_version = &captures[1]; - - debug!("Raw Nix version: {raw_version}"); - - // Nix 2.29.0 outputs "2.29" instead of "2.29.0", so we need to add that if necessary. - let corrected_raw_version = if raw_version.chars().filter(|&c| c == '.').count() == 1 { - &format!("{raw_version}.0") - } else { - raw_version - }; - - debug!("Corrected raw Nix version: {corrected_raw_version}"); - - let version = Version::parse(corrected_raw_version) - .wrap_err_with(|| output_changed_message!("nix --version", "Invalid version"))?; - - debug!("Nix version: {:?}", version); + let nix_version = NixVersion::new(ctx, &nix)?; // Nix since 2.21.0 uses `--all --impure` rather than `.*` to upgrade all packages. // Lix is based on Nix 2.18, so it doesn't! - let packages = if version >= Version::new(2, 21, 0) && !is_lix { + let packages = if nix_version.version()? >= Version::new(2, 21, 0) && !nix_version.is_lix() { vec!["--all", "--impure"] } else { vec![".*"] @@ -545,22 +570,9 @@ pub fn run_nix_self_upgrade(ctx: &ExecutionContext) -> Result<()> { print_separator(t!("Nix (self-upgrade)")); - let version_output = ctx.execute(&nix).arg("--version").output_checked_utf8()?; - let version = version_output - .stdout - .lines() - .next() - .ok_or_else(|| eyre!("`nix --version` output is empty"))?; + let nix_version = NixVersion::new(ctx, &nix)?; - let is_determinate_nix = version.contains("Determinate Nix"); - - debug!( - output=%version_output, - ?is_determinate_nix, - "`nix --version` output" - ); - - if is_determinate_nix { + if nix_version.is_determinate_nix() { let nixd = require("determinate-nixd"); let nixd = match nixd { Err(_) => {