refactor(nixopts): use typed option keys for arg parsing/serialization#176
Conversation
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
📝 WalkthroughWalkthroughThis PR refactors Nix option handling from a reflection-based, category-filtered system to a command-aware interface-based design. Options are now applied per-command rather than globally, each option declares supported commands, field naming is unified (Includes → Include, NixPathIncludes → Include), and direct Bind() calls replace helper function wiring. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes 🚥 Pre-merge checks | ✅ 5 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.5.0)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@internal/cmd/nixopts/nixopts.go`:
- Around line 588-592: The deprecated flag message is currently just the
replacement flag name; update the Deprecated field to a human-readable sentence.
In SubstituteOnDestination.Bind change
cmd.Flags().Lookup("use-substitutes").Deprecated from
"substitute-on-destination" to something like "use --substitute-on-destination
instead" so cobra prints a full sentence; likewise find the other occurrence for
the no-registries flag and set its Deprecated to "use --no-registries instead".
Ensure you reference the exact flag names ("use-substitutes",
"substitute-on-destination", "no-registries") and modify the Deprecated string
assignments accordingly in the Bind methods.
In `@internal/cmd/opts/opts.go`:
- Around line 179-213: InstallNixOpts is missing the nixopts.Builders embed so
the install workflow cannot accept the --builders flag used by CmdLegacyBuild;
update the InstallNixOpts struct to embed nixopts.Builders (matching
ApplyNixOpts), then ensure Flags() and ArgsForCommand() continue to use
nixopts.CollectFlags(o) and nixopts.ArgsForOptionsSet(o.Flags(), cmd) so the new
Builders options are collected and turned into CLI args for InstallNixOpts.
🧹 Nitpick comments (5)
internal/cmd/nixopts/nixopts.go (3)
22-30: Remove commented-out code.Dead code should be removed rather than left commented out. It's tracked in version control if needed later.
785-818:CollectFlagssilently drops fields when two fields share the same type.The doc comment warns about this, but a silent overwrite in a
map[typeName]is easy to miss during future maintenance. Consider returning an error or panicking (consistent with the other precondition checks in this function) when a duplicate type name is detected, so misuse is caught immediately rather than producing subtly wrong argument lists.Proposed defensive check
for i := 0; i < rv.NumField(); i++ { f := rv.Field(i) if flag, ok := f.Addr().Interface().(NixOption); ok { name := f.Type().Name() + if _, exists := fieldMap[name]; exists { + panic("CollectFlags: duplicate NixOption type " + name) + } fieldMap[name] = flag } }
524-530:Args()for slice/map-based options returns an empty slice instead ofnilwhen unset.Bool/int/string options return
nilwhen unset, butInclude,Option,UpdateInput, andOverrideInputreturn[]string{}. This is functionally harmless (appending an empty slice is a no-op), but the inconsistency could cause surprises in tests usingreflect.DeepEqual. Consider guarding with an earlynil/length check:Example for Include
func (i Include) Args() []string { + if len(i) == 0 { + return nil + } args := []string{} for _, include := range i { args = append(args, "--include", include) } return args }Same pattern applies to
Option.Args(),UpdateInput.Args(), andOverrideInput.Args().cmd/apply/apply.go (1)
187-187: Completion closure capturesIncludebefore flags are parsed.
opts.NixOptions.Includeisnilat command construction time. SinceCompleteSpecialisationFlagFromConfigreceives the slice by value, the completion function will always see anilincludes list regardless of what the user passes via--include. The same issue likely existed with the oldIncludesfield, but worth noting if accurate completions depend on user-supplied includes.If completions need runtime include values, consider passing a closure or pointer that defers the read until completion time.
internal/configuration/flake.go (1)
184-190: Remove dead code block that attempts to move--impureflag fromrealiseArgstoevalArgs.Since
Impure.Supports(CmdStoreRealise)returnsfalse(perinternal/cmd/nixopts/nixopts.go), the--impureflag is never added torealiseArgsin the first place. This makesslices.Index(realiseArgs, "--impure")always return-1, rendering the entire conditional block unreachable. The flag is already correctly included inevalArgsviaArgsForCommand(CmdEval)sinceImpure.Supports(CmdEval)returnstrue.♻️ Proposed fix
- // --impure must be part of the eval arguments, rather than the - // realisation arguments here, since that is where environment - // variables are accessed. - if i := slices.Index(realiseArgs, "--impure"); i >= 0 { - evalArgs = append(evalArgs, "--impure") - realiseArgs = slices.Delete(realiseArgs, i, i+1) - }
9c0bd50 to
56cfe37
Compare
Command categories were a bit too imprecise and resulted in flags like
--refreshgetting passed to commands that do not support that flag. This would render some operations impossible with those flags passed.Instead, each Nix option must now explicitly enumerate which commands it can be passed to; since there are only a handful of commands that are available, we can easily enumerate this ourselves and make this inherent to the option itself in the form of a type and corresponding interface.
This PR refactors the entire Nix passthrough options system to follow this pattern.
Closes #173.
Summary by CodeRabbit
Release Notes