diff options
author | Alyssa Ross <hi@alyssa.is> | 2022-05-31 09:59:33 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2022-05-31 09:59:57 +0000 |
commit | 9ff36293d1e428cd7bf03e8d4b03611b6d361c28 (patch) | |
tree | 1ab51a42b868c55b83f6ccdb80371b9888739dd9 /nixos/lib/utils.nix | |
parent | 1c4fcd0d4b0541e674ee56ace1053e23e562cc80 (diff) | |
parent | ddc3c396a51918043bb0faa6f676abd9562be62c (diff) | |
download | nixpkgs-9ff36293d1e428cd7bf03e8d4b03611b6d361c28.tar nixpkgs-9ff36293d1e428cd7bf03e8d4b03611b6d361c28.tar.gz nixpkgs-9ff36293d1e428cd7bf03e8d4b03611b6d361c28.tar.bz2 nixpkgs-9ff36293d1e428cd7bf03e8d4b03611b6d361c28.tar.lz nixpkgs-9ff36293d1e428cd7bf03e8d4b03611b6d361c28.tar.xz nixpkgs-9ff36293d1e428cd7bf03e8d4b03611b6d361c28.tar.zst nixpkgs-9ff36293d1e428cd7bf03e8d4b03611b6d361c28.zip |
Last good Nixpkgs for Weston+nouveau? archive
I came this commit hash to terwiz[m] on IRC, who is trying to figure out what the last version of Spectrum that worked on their NUC with Nvidia graphics is.
Diffstat (limited to 'nixos/lib/utils.nix')
-rw-r--r-- | nixos/lib/utils.nix | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/nixos/lib/utils.nix b/nixos/lib/utils.nix new file mode 100644 index 00000000000..ae68c3920c5 --- /dev/null +++ b/nixos/lib/utils.nix @@ -0,0 +1,201 @@ +{ lib, config, pkgs }: with lib; + +rec { + + # Copy configuration files to avoid having the entire sources in the system closure + copyFile = filePath: pkgs.runCommand (builtins.unsafeDiscardStringContext (builtins.baseNameOf filePath)) {} '' + cp ${filePath} $out + ''; + + # Check whenever fileSystem is needed for boot. NOTE: Make sure + # pathsNeededForBoot is closed under the parent relationship, i.e. if /a/b/c + # is in the list, put /a and /a/b in as well. + pathsNeededForBoot = [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/var/lib/nixos" "/etc" "/usr" ]; + fsNeededForBoot = fs: fs.neededForBoot || elem fs.mountPoint pathsNeededForBoot; + + # Check whenever `b` depends on `a` as a fileSystem + fsBefore = a: b: + let + # normalisePath adds a slash at the end of the path if it didn't already + # have one. + # + # The reason slashes are added at the end of each path is to prevent `b` + # from accidentally depending on `a` in cases like + # a = { mountPoint = "/aaa"; ... } + # b = { device = "/aaaa"; ... } + # Here a.mountPoint *is* a prefix of b.device even though a.mountPoint is + # *not* a parent of b.device. If we add a slash at the end of each string, + # though, this is not a problem: "/aaa/" is not a prefix of "/aaaa/". + normalisePath = path: "${path}${optionalString (!(hasSuffix "/" path)) "/"}"; + normalise = mount: mount // { device = normalisePath (toString mount.device); + mountPoint = normalisePath mount.mountPoint; + depends = map normalisePath mount.depends; + }; + + a' = normalise a; + b' = normalise b; + + in hasPrefix a'.mountPoint b'.device + || hasPrefix a'.mountPoint b'.mountPoint + || any (hasPrefix a'.mountPoint) b'.depends; + + # Escape a path according to the systemd rules, e.g. /dev/xyzzy + # becomes dev-xyzzy. FIXME: slow. + escapeSystemdPath = s: + replaceChars ["/" "-" " "] ["-" "\\x2d" "\\x20"] + (removePrefix "/" s); + + # Quotes an argument for use in Exec* service lines. + # systemd accepts "-quoted strings with escape sequences, toJSON produces + # a subset of these. + # Additionally we escape % to disallow expansion of % specifiers. Any lone ; + # in the input will be turned it ";" and thus lose its special meaning. + # Every $ is escaped to $$, this makes it unnecessary to disable environment + # substitution for the directive. + escapeSystemdExecArg = arg: + let + s = if builtins.isPath arg then "${arg}" + else if builtins.isString arg then arg + else if builtins.isInt arg || builtins.isFloat arg then toString arg + else throw "escapeSystemdExecArg only allows strings, paths and numbers"; + in + replaceChars [ "%" "$" ] [ "%%" "$$" ] (builtins.toJSON s); + + # Quotes a list of arguments into a single string for use in a Exec* + # line. + escapeSystemdExecArgs = concatMapStringsSep " " escapeSystemdExecArg; + + # Returns a system path for a given shell package + toShellPath = shell: + if types.shellPackage.check shell then + "/run/current-system/sw${shell.shellPath}" + else if types.package.check shell then + throw "${shell} is not a shell package" + else + shell; + + /* Recurse into a list or an attrset, searching for attrs named like + the value of the "attr" parameter, and return an attrset where the + names are the corresponding jq path where the attrs were found and + the values are the values of the attrs. + + Example: + recursiveGetAttrWithJqPrefix { + example = [ + { + irrelevant = "not interesting"; + } + { + ignored = "ignored attr"; + relevant = { + secret = { + _secret = "/path/to/secret"; + }; + }; + } + ]; + } "_secret" -> { ".example[1].relevant.secret" = "/path/to/secret"; } + */ + recursiveGetAttrWithJqPrefix = item: attr: + let + recurse = prefix: item: + if item ? ${attr} then + nameValuePair prefix item.${attr} + else if isAttrs item then + map (name: recurse (prefix + "." + name) item.${name}) (attrNames item) + else if isList item then + imap0 (index: item: recurse (prefix + "[${toString index}]") item) item + else + []; + in listToAttrs (flatten (recurse "" item)); + + /* Takes an attrset and a file path and generates a bash snippet that + outputs a JSON file at the file path with all instances of + + { _secret = "/path/to/secret" } + + in the attrset replaced with the contents of the file + "/path/to/secret" in the output JSON. + + When a configuration option accepts an attrset that is finally + converted to JSON, this makes it possible to let the user define + arbitrary secret values. + + Example: + If the file "/path/to/secret" contains the string + "topsecretpassword1234", + + genJqSecretsReplacementSnippet { + example = [ + { + irrelevant = "not interesting"; + } + { + ignored = "ignored attr"; + relevant = { + secret = { + _secret = "/path/to/secret"; + }; + }; + } + ]; + } "/path/to/output.json" + + would generate a snippet that, when run, outputs the following + JSON file at "/path/to/output.json": + + { + "example": [ + { + "irrelevant": "not interesting" + }, + { + "ignored": "ignored attr", + "relevant": { + "secret": "topsecretpassword1234" + } + } + ] + } + */ + genJqSecretsReplacementSnippet = genJqSecretsReplacementSnippet' "_secret"; + + # Like genJqSecretsReplacementSnippet, but allows the name of the + # attr which identifies the secret to be changed. + genJqSecretsReplacementSnippet' = attr: set: output: + let + secrets = recursiveGetAttrWithJqPrefix set attr; + in '' + if [[ -h '${output}' ]]; then + rm '${output}' + fi + + inherit_errexit_enabled=0 + shopt -pq inherit_errexit && inherit_errexit_enabled=1 + shopt -s inherit_errexit + '' + + concatStringsSep + "\n" + (imap1 (index: name: '' + secret${toString index}=$(<'${secrets.${name}}') + export secret${toString index} + '') + (attrNames secrets)) + + "\n" + + "${pkgs.jq}/bin/jq >'${output}' '" + + concatStringsSep + " | " + (imap1 (index: name: ''${name} = $ENV.secret${toString index}'') + (attrNames secrets)) + + '' + ' <<'EOF' + ${builtins.toJSON set} + EOF + (( ! $inherit_errexit_enabled )) && shopt -u inherit_errexit + ''; + + systemdUtils = { + lib = import ./systemd-lib.nix { inherit lib config pkgs; }; + unitOptions = import ./systemd-unit-options.nix { inherit lib systemdUtils; }; + }; +} |