-
Notifications
You must be signed in to change notification settings - Fork 33
lib.modules: refactor into composable layers with flag ordering #147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
ad48ea4
lib.modules: extract command base module from wrapper
Lassulus 5f5ea69
lib.modules: extract flags module with priority-based arg ordering
Lassulus fc6d9b7
lib.modules.wrapper: move "$@" into args at order 1001
Lassulus 18219d3
lib: change default flagSeparator from " " to null
Lassulus 71e85a2
wrapPackage: move "$@" from template into default args
Lassulus d889d56
default.nix: allow lib as arg
Lassulus 1255994
tests: avoid pipefail SIGPIPE in module checks
Lassulus File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # Changelog | ||
|
|
||
| ## Unreleased | ||
|
|
||
| ### Breaking changes | ||
|
|
||
| - `wrapPackage`: when passing explicit `args`, `"$@"` is no longer | ||
| appended automatically by the wrapper template. If you pass custom | ||
| `args` and want passthrough, include `"$@"` in your args list. | ||
| The default `args` (generated from `flags`) still includes `"$@"`. | ||
|
|
||
| - `flagSeparator` default changed from `" "` to `null`. The old `" "` | ||
| default was misleading: it produced separate argv entries, not a | ||
| space-joined arg. `null` now means separate argv entries. If you | ||
| were explicitly passing `flagSeparator = " "` to get separate args, | ||
| remove it (or change to `null`). | ||
|
|
||
| ### Added | ||
|
|
||
| - `lib/modules/command.nix`: base module with shared command spec | ||
| (args, env, hooks, exePath) used by both wrapper and systemd outputs. | ||
| - `lib/modules/flags.nix`: flags module with per-flag ordering via | ||
| `{ value, order }` submodules. Default order is 1000. Reading | ||
| `config.flags` returns clean values (order is transparent). | ||
| - `wrapper.nix` injects `"$@"` into args at order 1001, controllable | ||
| via the ordering system. | ||
| - `outputs.wrapper` as the canonical output path (config.wrapper is | ||
| a backward-compatible alias). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,7 +13,6 @@ let | |
| "--empty" = [ ]; | ||
| "--output" = "file.txt"; | ||
| }; | ||
| flagSeparator = " "; | ||
| }; | ||
|
|
||
| in | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,7 +15,6 @@ let | |
| "--empty" = [ ]; | ||
| "--output" = "file.txt"; | ||
| }; | ||
| flagSeparator = " "; | ||
| }; | ||
|
|
||
| in | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,7 +15,6 @@ let | |
| ]; | ||
| "--verbose" = true; | ||
| }; | ||
| flagSeparator = " "; | ||
| }; | ||
|
|
||
| wrappedWithEqualsSep = self.lib.wrapPackage { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| { | ||
| pkgs, | ||
| self, | ||
| }: | ||
|
|
||
| let | ||
| helloModule = self.lib.wrapModule ( | ||
| { config, ... }: | ||
| { | ||
| config.package = config.pkgs.hello; | ||
| config.flags = { | ||
| # default order 1000: before "$@" (which is 1001) | ||
| "--greeting" = "hello"; | ||
| # explicit early order: should come first | ||
| "--early" = { | ||
| value = true; | ||
| order = 500; | ||
| }; | ||
| # explicit late order: should come after "$@" | ||
| "--late" = { | ||
| value = true; | ||
| order = 1500; | ||
| }; | ||
| }; | ||
| } | ||
| ); | ||
|
|
||
| wrappedPackage = (helloModule.apply { inherit pkgs; }).wrapper; | ||
|
|
||
| in | ||
| pkgs.runCommand "flags-order-test" { } '' | ||
| echo "Testing flag ordering with priorities..." | ||
|
|
||
| wrapperScript="${wrappedPackage}/bin/hello" | ||
| if [ ! -f "$wrapperScript" ]; then | ||
| echo "FAIL: Wrapper script not found" | ||
| exit 1 | ||
| fi | ||
|
|
||
| cat "$wrapperScript" | ||
|
|
||
| # Flatten the script to a single line for position comparison | ||
| flat=$(cat "$wrapperScript" | tr -d '\n' | tr -s ' ') | ||
|
|
||
| # --early (500) should come before --greeting (1000) | ||
| # --greeting (1000) should come before "$@" (1001) | ||
| # "$@" (1001) should come before --late (1500) | ||
| earlyPos=$(echo "$flat" | grep -bo -- '--early' | head -1 | cut -d: -f1) | ||
| greetingPos=$(echo "$flat" | grep -bo -- '--greeting' | head -1 | cut -d: -f1) | ||
| passthruPos=$(echo "$flat" | grep -bo '"\$@"' | head -1 | cut -d: -f1) | ||
| latePos=$(echo "$flat" | grep -bo -- '--late' | head -1 | cut -d: -f1) | ||
|
|
||
| echo "Positions: early=$earlyPos greeting=$greetingPos passthru=$passthruPos late=$latePos" | ||
|
|
||
| if [ "$earlyPos" -ge "$greetingPos" ]; then | ||
| echo "FAIL: --early should come before --greeting" | ||
| exit 1 | ||
| fi | ||
| if [ "$greetingPos" -ge "$passthruPos" ]; then | ||
| echo "FAIL: --greeting should come before \"\$@\"" | ||
| exit 1 | ||
| fi | ||
| if [ "$passthruPos" -ge "$latePos" ]; then | ||
| echo "FAIL: \"\$@\" should come before --late" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "SUCCESS: Flag ordering test passed" | ||
| touch $out | ||
| '' | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,6 @@ let | |
| "--greeting" = "hi"; | ||
| "--verbose" = true; | ||
| }; | ||
| flagSeparator = " "; | ||
| }; | ||
|
|
||
| in | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| { | ||
| lib, | ||
| wlib, | ||
| config, | ||
| ... | ||
| }: | ||
| { | ||
| _file = "lib/modules/command.nix"; | ||
| imports = [ | ||
| wlib.modules.package | ||
| wlib.modules.flags | ||
| ]; | ||
| options.args = lib.mkOption { | ||
| type = lib.types.listOf lib.types.str; | ||
| default = [ ]; | ||
| description = '' | ||
| Command-line arguments to pass to the wrapper (like argv in execve). | ||
| This is a list of strings representing individual arguments. | ||
| If not specified, will be automatically generated from flags. | ||
| ''; | ||
| }; | ||
| options.extraPackages = lib.mkOption { | ||
| type = lib.types.listOf lib.types.package; | ||
| default = [ ]; | ||
| description = '' | ||
| Additional packages to add to the wrapper's runtime dependencies. | ||
| This is useful if the wrapped program needs additional libraries or tools to function correctly. | ||
| These packages will be added to the wrapper's runtime dependencies, ensuring they are available when the wrapped program is executed. | ||
| ''; | ||
| }; | ||
| options.env = lib.mkOption { | ||
| type = lib.types.attrsOf lib.types.str; | ||
| default = { }; | ||
| description = '' | ||
| Environment variables to set in the wrapper. | ||
| ''; | ||
| }; | ||
| options.preHook = lib.mkOption { | ||
| type = lib.types.str; | ||
| default = ""; | ||
| description = '' | ||
| Shell script to run before executing the command. | ||
| ''; | ||
| }; | ||
| options.postHook = lib.mkOption { | ||
| type = lib.types.str; | ||
| default = ""; | ||
| description = '' | ||
| Shell script to run after executing the command. | ||
| Removes the `exec` call in the wrapper script which will leave a bash process | ||
| in the background, therefore use with care. | ||
| ''; | ||
| }; | ||
| options.exePath = lib.mkOption { | ||
| type = lib.types.path; | ||
| description = '' | ||
| Path to the executable within the package to be wrapped. | ||
| If not specified, the main executable of the package will be used. | ||
| ''; | ||
| default = lib.getExe config.package; | ||
| defaultText = "lib.getExe config.package"; | ||
| }; | ||
| options.binName = lib.mkOption { | ||
| type = lib.types.str; | ||
| description = '' | ||
| Name of the binary in the resulting wrapper package. | ||
| If not specified, the base name of exePath will be used. | ||
| ''; | ||
| default = builtins.baseNameOf config.exePath; | ||
| defaultText = "builtins.baseNameOf config.exePath"; | ||
| }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| { | ||
| lib, | ||
| wlib, | ||
| config, | ||
| options, | ||
| ... | ||
| }: | ||
| let | ||
| flagValueType = lib.types.oneOf [ | ||
| (lib.types.uniq lib.types.str) | ||
| (lib.types.uniq lib.types.bool) | ||
| (lib.types.listOf ( | ||
| lib.types.oneOf [ | ||
| lib.types.str | ||
| (lib.types.listOf lib.types.str) | ||
| ] | ||
| )) | ||
| ]; | ||
|
|
||
| flagSubmodule = lib.types.submodule { | ||
| options.value = lib.mkOption { | ||
| type = flagValueType; | ||
| description = "The flag value."; | ||
| }; | ||
| options.order = lib.mkOption { | ||
| type = lib.types.int; | ||
| default = 1000; | ||
| description = '' | ||
| Order priority for this flag in the generated args list. | ||
| Lower numbers come first. Default is 1000. | ||
| ''; | ||
| }; | ||
| }; | ||
| in | ||
| { | ||
| _file = "lib/modules/flags.nix"; | ||
|
|
||
| options.flags = lib.mkOption { | ||
| type = lib.types.lazyAttrsOf (lib.types.coercedTo flagValueType (v: { value = v; }) flagSubmodule); | ||
| default = { }; | ||
| apply = lib.mapAttrs (_: v: v.value); | ||
| description = '' | ||
| Flags to pass to the wrapper. | ||
| The key is the flag name, the value is the flag value. | ||
| If the value is true, the flag will be passed without a value. | ||
| If the value is false, the flag will not be passed. | ||
| If the value is a list, the flag will be passed multiple times with each value. | ||
| Can also be set to { value = ...; order = N; } to control ordering in args. | ||
| ''; | ||
| }; | ||
|
|
||
| options._orderedFlags = lib.mkOption { | ||
| type = lib.types.lazyAttrsOf (lib.types.coercedTo flagValueType (v: { value = v; }) flagSubmodule); | ||
| internal = true; | ||
| default = { }; | ||
| }; | ||
|
|
||
| options.flagSeparator = lib.mkOption { | ||
| type = lib.types.nullOr lib.types.str; | ||
| default = null; | ||
| description = '' | ||
| Separator between flag names and values when generating args from flags. | ||
| null (default) for separate argv entries: "--flag" "value" | ||
| "=" for joined: "--flag=value" | ||
| ''; | ||
| }; | ||
|
|
||
| config._orderedFlags = lib.mkAliasDefinitions options.flags; | ||
|
|
||
| config.args = lib.mkMerge ( | ||
| lib.mapAttrsToList ( | ||
| name: flagDef: | ||
| lib.mkOrder flagDef.order ( | ||
| wlib.flagToArgs { | ||
| inherit name; | ||
| flag = flagDef.value; | ||
| flagSeparator = config.flagSeparator; | ||
| } | ||
| ) | ||
| ) config._orderedFlags | ||
| ); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.