-
-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
nixos-option: rewrite as a nix script, 2nd try (#369151)
- Loading branch information
Showing
13 changed files
with
488 additions
and
845 deletions.
There are no files selected for viewing
This file contains 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 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,133 @@ | ||
.Dd January 1, 1980 | ||
.Dt nixos-option 8 | ||
.Os | ||
.Sh NAME | ||
.Nm nixos-option | ||
.Nd inspect a NixOS configuration | ||
. | ||
. | ||
. | ||
.Sh SYNOPSIS | ||
.Nm | ||
.Op Fl r | -recursive | ||
.Op Fl I Ar path | ||
.Op Fl F | -flake Ar flake-uri | ||
.br | ||
.Op Fl -no-flake | ||
.Op Fl -show-trace | ||
.Ar option.name | ||
. | ||
. | ||
. | ||
.Sh DESCRIPTION | ||
This command evaluates the configuration specified in | ||
.Ev NIXOS_CONFIG Ns | ||
, | ||
.Pa nixos-config | ||
in | ||
.Ev NIX_PATH | ||
(which by default is | ||
.Pa /etc/nixos/configuration.nix Ns | ||
), | ||
.Pa /etc/nixos/flake.nix | ||
or the file and attribute specified by the | ||
.Fl I | ||
or | ||
.Fl -flake | ||
parameter, and returns the properties of the option name given as argument. | ||
. | ||
.Pp | ||
When the option name is not an option but an attribute set, the command prints | ||
the list of attributes contained in it. When no option name is given, the | ||
command prints all top-level attributes in given NixOS configuration. | ||
. | ||
. | ||
. | ||
.Sh OPTIONS | ||
.Bl -tag -width indent | ||
.It Fl r , -recursive | ||
Print all the values at or below the specified path recursively. | ||
. | ||
.It Fl I Ar path | ||
Add an entry to the Nix expression search path. This option is passed to the | ||
underlying | ||
.Xr nix-instantiate 1 | ||
invocation. | ||
. | ||
.It Fl -show-trace | ||
Print eval trace. This option is passed to the underlying | ||
.Xr nix-instantiate 1 | ||
invocation. | ||
. | ||
.It Fl F , -flake Ar flake-uri | ||
Specify the flake containing NixOS configuration. It defaults to | ||
.Pa /etc/nixos/flake.nix Ns | ||
, if the flake exists, it must contain an output named | ||
.Ql nixosConfigurations. Ns Va name Ns | ||
\&. If | ||
.Va name | ||
is omitted, it defaults to the current host name. | ||
. | ||
.It Fl -no-flake | ||
Do not imply | ||
.Fl -flake | ||
if | ||
.Pa /etc/nixos/flake.nix | ||
exists. With this option, it is possible to show options in non-flake NixOS | ||
configurations even if the current NixOS systems uses flakes. | ||
. | ||
.El | ||
. | ||
. | ||
. | ||
.Sh Ev ENVIRONMENT | ||
.Bl -tag -width indent | ||
.It Ev NIXOS_CONFIG | ||
Path to the main NixOS configuration module. Defaults to | ||
.Pa /etc/nixos/configuration.nix Ns | ||
\&. | ||
.El | ||
. | ||
. | ||
. | ||
.Sh EXAMPLES | ||
Investigate option values: | ||
.Bd -literal -offset indent | ||
$ nixos-option boot.loader | ||
This attribute set contains: | ||
generationsDir | ||
grub | ||
initScript | ||
|
||
$ nixos-option boot.loader.grub.enable | ||
Value: | ||
true | ||
|
||
Default: | ||
true | ||
|
||
Type: | ||
boolean | ||
|
||
Description: | ||
Whether to enable the GNU GRUB boot loader. | ||
|
||
Declared by: | ||
/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix | ||
|
||
Defined by: | ||
/nix/var/nix/profiles/per-user/root/channels/nixos/nixpkgs/nixos/modules/system/boot/loader/grub/grub.nix | ||
.Ed | ||
. | ||
. | ||
. | ||
.Sh SEE ALSO | ||
.Xr configuration.nix 5 | ||
. | ||
. | ||
. | ||
.Sh AUTHORS | ||
.An -nosplit | ||
.An Nicolas Pierron | ||
and | ||
.An the Nixpkgs/NixOS contributors |
This file contains 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,167 @@ | ||
{ | ||
nixos, | ||
# list representing a nixos option path (e.g. ['console' 'enable']), or a | ||
# prefix of such a path (e.g. ['console']), or a string representing the same | ||
# (e.g. 'console.enable') | ||
path, | ||
# whether to recurse down the config attrset and show each set value instead | ||
recursive, | ||
}: | ||
|
||
let | ||
inherit (nixos.pkgs) lib; | ||
|
||
path' = if lib.isString path then (if path == "" then [ ] else readOption path) else path; | ||
|
||
# helper that maps `f` on subslices starting when `predStart x` and | ||
# ending when `predEnd x` (no support for nested occurrences) | ||
flatMapSlices = | ||
predStart: predEnd: f: list: | ||
let | ||
empty = { | ||
result = [ ]; | ||
active = [ ]; | ||
}; | ||
op = | ||
{ result, active }: | ||
x: | ||
if predStart x && predEnd x then | ||
{ | ||
result = result ++ active ++ f [ x ]; | ||
active = [ ]; | ||
} | ||
else if predStart x then | ||
{ | ||
result = result ++ active; | ||
active = [ x ]; | ||
} | ||
else if predEnd x then | ||
{ | ||
result = result ++ f (active ++ [ x ]); | ||
active = [ ]; | ||
} | ||
else | ||
{ | ||
inherit result; | ||
active = active ++ [ x ]; | ||
}; | ||
in | ||
(x: x.result ++ x.active) (lib.foldl op empty list); | ||
|
||
# tries to invert showOption, taking a written-out option name and splitting | ||
# it into its parts | ||
readOption = | ||
str: | ||
let | ||
unescape = list: lib.replaceStrings (map (c: "\\${c}") list) list; | ||
unescapeNixString = lib.flip lib.pipe [ | ||
(lib.concatStringsSep ".") | ||
(unescape [ "$" ]) | ||
builtins.fromJSON | ||
]; | ||
in | ||
flatMapSlices (lib.hasPrefix "\"") (lib.hasSuffix "\"") (x: [ (unescapeNixString x) ]) ( | ||
lib.splitString "." str | ||
); | ||
|
||
# like 'mapAttrsRecursiveCond' but handling errors in the attrset tree as leaf | ||
# nodes (which means `f` is expected to handle shallow errors) | ||
safeMapAttrsRecursiveCond = | ||
cond: f: set: | ||
let | ||
recurse = | ||
path: | ||
lib.mapAttrs ( | ||
name: value: | ||
let | ||
e = builtins.tryEval value; | ||
path' = path ++ [ name ]; | ||
in | ||
if e.success && lib.isAttrs value && cond value then recurse path' value else f path' value | ||
); | ||
in | ||
recurse [ ] set; | ||
|
||
# traverse the option tree along `path` from `root`, returning the option or | ||
# attrset at the given location | ||
optionByPath = | ||
path: root: | ||
let | ||
into = | ||
opt: part: | ||
if lib.isOption opt && opt.type.descriptionClass == "composite" then | ||
opt.type.getSubOptions [ ] | ||
else if lib.isOption opt then | ||
throw "Trying to access '${part}' inside ${opt.type.name} option while traversing option path '${lib.showOption path}'" | ||
else if lib.isAttrs opt && lib.hasAttr part opt then | ||
opt.${part} | ||
else | ||
throw "Found neither an attrset nor supported option type near '${part}' while traversing option path '${lib.showOption path}'"; | ||
in | ||
lib.foldl into root path; | ||
|
||
toPretty = lib.generators.toPretty { multiline = true; }; | ||
safeToPretty = | ||
x: | ||
let | ||
e = builtins.tryEval (toPretty x); | ||
in | ||
if e.success then e.value else "[1;31m«error»[m"; | ||
|
||
indent = str: lib.concatStringsSep "\n" (map (x: " " + x) (lib.splitString "\n" str)); | ||
|
||
optionAttrNames = attrs: lib.filter (x: x != "_module") (lib.attrNames attrs); | ||
|
||
## full, non-recursive mode: print an option from `options` | ||
renderAttrs = | ||
attrs: "This attribute set contains:\n${lib.concatStringsSep "\n" (optionAttrNames attrs)}"; | ||
|
||
renderOption = | ||
option: value: | ||
let | ||
entry = | ||
cond: heading: value: | ||
lib.optional cond "${heading}:\n${indent value}"; | ||
in | ||
lib.concatStringsSep "\n\n" ( | ||
lib.concatLists [ | ||
(entry true "Value" (toPretty value)) | ||
(entry (option ? default) "Default" (toPretty option.default)) | ||
(entry (option ? type) "Type" (option.type.description)) | ||
(entry (option ? description) "Description" (lib.removeSuffix "\n" option.description)) | ||
(entry (option ? example) "Example" (toPretty option.example)) | ||
(entry (option ? declarations) "Declared by" (lib.concatStringsSep "\n" option.declarations)) | ||
(entry (option ? files) "Defined by" (lib.concatStringsSep "\n" option.files)) | ||
] | ||
); | ||
|
||
renderFull = | ||
entry: configEntry: | ||
if lib.isOption entry then | ||
renderOption entry configEntry | ||
else if lib.isAttrs entry then | ||
renderAttrs entry | ||
else | ||
throw "Found neither an attrset nor option at option path '${lib.showOption path'}'"; | ||
|
||
## recursive mode: print paths and values from `config` | ||
renderRecursive = | ||
config: | ||
let | ||
renderShort = n: v: "${lib.showOption (path' ++ n)} = ${safeToPretty v};"; | ||
mapAttrsRecursive' = safeMapAttrsRecursiveCond (x: !lib.isDerivation x); | ||
in | ||
if lib.isAttrs config then | ||
lib.concatStringsSep "\n" (lib.collect lib.isString (mapAttrsRecursive' renderShort config)) | ||
else | ||
renderShort [ ] config; | ||
|
||
in | ||
if !lib.hasAttrByPath path' nixos.config then | ||
throw "Couldn't resolve config path '${lib.showOption path'}'" | ||
else | ||
let | ||
optionEntry = optionByPath path' nixos.options; | ||
configEntry = lib.attrByPath path' null nixos.config; | ||
in | ||
if recursive then renderRecursive configEntry else renderFull optionEntry configEntry |
Oops, something went wrong.