Skip to content

fix(install): resolve longstanding bugs with installation process#128

Merged
water-sucks merged 3 commits intonix-community:mainfrom
water-sucks:fix-install-bugs
Nov 9, 2025
Merged

fix(install): resolve longstanding bugs with installation process#128
water-sucks merged 3 commits intonix-community:mainfrom
water-sucks:fix-install-bugs

Conversation

@water-sucks
Copy link
Copy Markdown
Collaborator

@water-sucks water-sucks commented Nov 9, 2025

There were three bugs with the nixos install command:

  • The --system command-line flag was not being used at all (probably a bug from the Zig -> Go port), and was missing some extra validation.
  • The $mountpoint/nix/var/nix/profiles/per-user/root/channels directory was getting created directly, when it was supposed to be a symlink created by Nix. This caused Nix to fail when copying the initial channel. This creates only the per-user/root directory for Nix to place the channel links in.
  • The nixos enter command did not bind-mount /sys, which lead to failures with installing GRUB and systemd-boot on UEFI systems since it didn't know where the EFI variables were.

Summary by CodeRabbit

  • Bug Fixes

    • Corrected wording in system setup instructions.
  • Improvements

    • Mounts system metadata (/sys) during startup with logging and error handling for more reliable initialization.
    • Strengthened validation for installation options (mutual-exclusion and absolute-path/existence checks).
    • Ensure channel destination directories are created before copying.
    • Skip rebuilding when a pre-built system closure is provided; improved build flow and error reporting.
    • Clarified and corrected the root-password hint messaging.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 9, 2025

Walkthrough

Bind-mount /sys into the new root during the enter flow with logging and error handling; refactor the install command to validate an optional system closure (absolute, exists, mutually exclusive with FlakeRef), ensure channel parent dirs, and conditionally either build the system or use the provided closure as the result location.

Changes

Cohort / File(s) Summary
Sandbox mounts
cmd/enter/run.go
Added a bind-mount of /sys into the new root after mounting /dev and before /proc; included logging and immediate error-return handling on failure.
Install validation & build flow
cmd/install/install.go
Replaced len(opts.Root) > 0 with opts.Root != ""; introduced optional SystemClosure validation (must be absolute, must exist, mutually exclusive with FlakeRef); ensure parent directory exists before channel copy (MkdirAll); reuse error variable for channel copy; introduce resultLocation and branch: build system when no SystemClosure, otherwise use provided closure; fix manualHint messaging.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as install CLI
  participant FS as filesystem
  participant Builder as system builder
  participant Channel as channel copy

  CLI->>FS: validate flags (root != "", systemClosure?, flakeRef?)
  alt systemClosure provided
    CLI->>FS: check absolute path
    CLI->>FS: os.Stat(systemClosure)
    FS-->>CLI: exists / error
    CLI-->>CLI: set resultLocation = systemClosure
  else no systemClosure
    CLI->>Builder: run system build
    Builder-->>CLI: return build result path
    CLI-->>CLI: set resultLocation = build result
  end
  CLI->>FS: ensure parent dir for channel mountpoint (MkdirAll)
  CLI->>Channel: copy channel -> mountpoint
  Channel-->>CLI: success / error
  CLI->>FS: create initial generation using resultLocation
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Inspect cmd/install/install.go for correct mutual-exclusion logic between SystemClosure and FlakeRef.
  • Verify absolute-path check and os.Stat error handling for SystemClosure.
  • Confirm MkdirAll is applied to the correct parent directory and errors propagate.
  • Ensure resultLocation is assigned and used on all code paths.
  • Quick check of cmd/enter/run.go mount ordering and cleanup/error paths around the new /sys bind-mount.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and clearly summarizes the main purpose of the pull request: fixing longstanding bugs in the installation process.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
cmd/install/install.go (2)

199-202: Clarify the error message to reflect parent directory creation.

The implementation correctly creates only the parent directory (as per PR objective #2), but the error message on line 201 references mountpointChannelDir while actually creating its parent directory.

Apply this diff to improve clarity:

 	err := os.MkdirAll(filepath.Dir(mountpointChannelDir), 0o755)
 	if err != nil {
-		return fmt.Errorf("failed to create %s: %s", mountpointChannelDir, err)
+		return fmt.Errorf("failed to create parent directory for %s: %s", mountpointChannelDir, err)
 	}

489-489: Typo fix is good, but the placeholder needs attention.

The correction from "them new system" to "the new system" is appropriate. However, there's an existing issue in this line: the {s} placeholder appears to be intended for the mountpoint value but is not actually replaced.

Consider replacing the placeholder with the actual mountpoint value:

-		manualHint := "you can set the root password manually by executing `nixos enter --root {s}` and then running `passwd` in the shell of the new system"
+		manualHint := fmt.Sprintf("you can set the root password manually by executing `nixos enter --root %s` and then running `passwd` in the shell of the new system", mountpoint)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eecf026 and a87fc2d.

📒 Files selected for processing (2)
  • cmd/enter/run.go (1 hunks)
  • cmd/install/install.go (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/install/install.go (2)
internal/configuration/flake.go (1)
  • FlakeRef (17-23)
internal/configuration/configuration.go (2)
  • SystemBuildOptions (13-26)
  • SystemBuild (75-77)
🔇 Additional comments (5)
cmd/enter/run.go (1)

63-68: LGTM! /sys bind-mount correctly implements UEFI support.

The addition of the /sys bind-mount follows the same pattern as existing /dev and /proc mounts and resolves the UEFI bootloader installation issue described in the PR objectives. Mounting /sys before /proc is appropriate and provides access to EFI variables needed by GRUB and systemd-boot.

cmd/install/install.go (4)

52-54: LGTM! Improved validation for --root flag.

The change from length check to direct emptiness check is more idiomatic Go, and the absolute path validation is appropriate for the --root filesystem path parameter.


56-68: LGTM! Comprehensive validation for --system flag.

The validation correctly implements all necessary checks:

  • Absolute path requirement
  • Mutual exclusivity with flake references
  • File existence verification

This addresses the lack of validation mentioned in the PR objectives and ensures the --system flag is properly constrained.


230-230: LGTM! Style consistency improvement.

The inline error assignment matches the pattern used elsewhere in the function.


434-453: LGTM! Conditional build flow correctly implements --system flag functionality.

The restructuring properly implements the --system flag usage mentioned in PR objective #1:

  • When --system is not provided, the system is built as before
  • When --system is provided, the build is skipped and the provided closure is used
  • The "Building system..." log is appropriately conditional

The logic is clear and the resultLocation variable is used consistently downstream.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
cmd/install/install.go (1)

56-68: Consider a more descriptive error message for the path existence check.

The validation logic correctly ensures the system closure path is absolute, mutually exclusive with the flake reference, and exists. However, the error returned from os.Stat on line 65-67 could be more user-friendly.

Consider wrapping the error:

 			if _, err := os.Stat(opts.SystemClosure); err != nil {
-				return err
+				return fmt.Errorf("--system path does not exist or is not accessible: %w", err)
 			}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a87fc2d and 767cccc.

📒 Files selected for processing (2)
  • cmd/enter/run.go (1 hunks)
  • cmd/install/install.go (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cmd/enter/run.go
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/install/install.go (2)
internal/configuration/flake.go (1)
  • FlakeRef (17-23)
internal/configuration/configuration.go (2)
  • SystemBuildOptions (13-26)
  • SystemBuild (75-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build/Test
🔇 Additional comments (4)
cmd/install/install.go (4)

52-54: LGTM!

The validation correctly ensures that the root path is absolute when provided.


230-230: LGTM!

The error handling standardization improves consistency with the surrounding code.


434-453: Excellent fix for the --system flag functionality.

The restructured control flow correctly implements the conditional logic:

  • When --system is not provided, the system is built and the result is used.
  • When --system is provided, the specified system closure is used directly, skipping the build.

This properly addresses the bug where the --system flag was ignored.


489-489: LGTM!

Good catch on the grammatical error. The corrected message is now clearer for users.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
cmd/install/install.go (1)

56-68: Enhance error message with context.

The validation correctly checks that the system closure path is absolute, mutually exclusive with FlakeRef, and exists. However, when os.Stat fails on line 65, the raw error is returned without indicating which path was checked.

Apply this diff to improve the error message:

 			if _, err := os.Stat(opts.SystemClosure); err != nil {
-				return err
+				return fmt.Errorf("failed to stat system closure at %s: %w", opts.SystemClosure, err)
 			}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 767cccc and ed91411.

📒 Files selected for processing (2)
  • cmd/enter/run.go (1 hunks)
  • cmd/install/install.go (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
cmd/install/install.go (2)
internal/configuration/flake.go (1)
  • FlakeRef (17-23)
internal/configuration/configuration.go (2)
  • SystemBuildOptions (13-26)
  • SystemBuild (75-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build/Test
🔇 Additional comments (4)
cmd/enter/run.go (1)

63-68: LGTM! /sys bind-mount fixes UEFI bootloader installation.

The implementation correctly adds /sys bind-mounting with appropriate logging and error handling, consistent with the existing /dev and /proc mounts. This resolves the issue where EFI variables were inaccessible during GRUB and systemd-boot installation on UEFI systems.

cmd/install/install.go (3)

198-203: Correct fix for channel directory creation.

The change properly creates only the parent directory (per-user/root) instead of the full channel path, allowing Nix to manage the channel symlinks. The error message now correctly references the directory being created.


435-454: Well-structured conditional build flow.

The refactoring correctly implements the --system flag functionality: when a system closure is provided, it's used directly; otherwise, the system is built. The "Building system..." log message appropriately appears only when a build occurs, and resultLocation is properly set in both branches.


490-490: Improved hint uses actual mountpoint.

Using the mountpoint variable instead of a hardcoded path makes the hint accurate for all installation scenarios.

@water-sucks water-sucks merged commit 41d0481 into nix-community:main Nov 9, 2025
2 checks passed
@water-sucks water-sucks deleted the fix-install-bugs branch November 9, 2025 00:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant