mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-12-25 15:13:46 +00:00
4f0dadbf38
After final improvements to the official formatter implementation, this commit now performs the first treewide reformat of Nix files using it. This is part of the implementation of RFC 166. Only "inactive" files are reformatted, meaning only files that aren't being touched by any PR with activity in the past 2 months. This is to avoid conflicts for PRs that might soon be merged. Later we can do a full treewide reformat to get the rest, which should not cause as many conflicts. A CI check has already been running for some time to ensure that new and already-formatted files are formatted, so the files being reformatted here should also stay formatted. This commit was automatically created and can be verified using nix-builda08b3a4d19
.tar.gz \ --argstr baseRevb32a094368
result/bin/apply-formatting $NIXPKGS_PATH
440 lines
13 KiB
Nix
440 lines
13 KiB
Nix
{
|
|
lib,
|
|
config,
|
|
pkgs,
|
|
}:
|
|
|
|
let
|
|
inherit (lib)
|
|
any
|
|
attrNames
|
|
concatMapStringsSep
|
|
concatStringsSep
|
|
elem
|
|
escapeShellArg
|
|
filter
|
|
flatten
|
|
getName
|
|
hasPrefix
|
|
hasSuffix
|
|
imap0
|
|
imap1
|
|
isAttrs
|
|
isDerivation
|
|
isFloat
|
|
isInt
|
|
isList
|
|
isPath
|
|
isString
|
|
listToAttrs
|
|
mapAttrs
|
|
nameValuePair
|
|
optionalString
|
|
removePrefix
|
|
removeSuffix
|
|
replaceStrings
|
|
stringToCharacters
|
|
types
|
|
;
|
|
|
|
inherit (lib.strings) toJSON normalizePath escapeC;
|
|
in
|
|
|
|
let
|
|
utils = rec {
|
|
|
|
# Copy configuration files to avoid having the entire sources in the system closure
|
|
copyFile =
|
|
filePath:
|
|
pkgs.runCommand (builtins.unsafeDiscardStringContext (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. FIXME: slow
|
|
# The rules are described in systemd.unit(5) as follows:
|
|
# The escaping algorithm operates as follows: given a string, any "/" character is replaced by "-", and all other characters which are not ASCII alphanumerics, ":", "_" or "." are replaced by C-style "\x2d" escapes. In addition, "." is replaced with such a C-style escape when it would appear as the first character in the escaped string.
|
|
# When the input qualifies as absolute file system path, this algorithm is extended slightly: the path to the root directory "/" is encoded as single dash "-". In addition, any leading, trailing or duplicate "/" characters are removed from the string before transformation. Example: /foo//bar/baz/ becomes "foo-bar-baz".
|
|
escapeSystemdPath =
|
|
s:
|
|
let
|
|
replacePrefix =
|
|
p: r: s:
|
|
(if (hasPrefix p s) then r + (removePrefix p s) else s);
|
|
trim = s: removeSuffix "/" (removePrefix "/" s);
|
|
normalizedPath = normalizePath s;
|
|
in
|
|
replaceStrings [ "/" ] [ "-" ] (
|
|
replacePrefix "." (escapeC [ "." ] ".") (
|
|
escapeC (stringToCharacters " !\"#$%&'()*+,;<=>=@[\\]^`{|}~-") (
|
|
if normalizedPath == "/" then normalizedPath else trim normalizedPath
|
|
)
|
|
)
|
|
);
|
|
|
|
# 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 isPath arg then
|
|
"${arg}"
|
|
else if isString arg then
|
|
arg
|
|
else if isInt arg || isFloat arg || isDerivation arg then
|
|
toString arg
|
|
else
|
|
throw "escapeSystemdExecArg only allows strings, paths, numbers and derivations";
|
|
in
|
|
replaceStrings [ "%" "$" ] [ "%%" "$$" ] (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: mapAttrs (_name: set: set.${attr}) (recursiveGetAttrsetWithJqPrefix item attr);
|
|
|
|
/*
|
|
Similar to `recursiveGetAttrWithJqPrefix`, but returns the whole
|
|
attribute set containing `attr` instead of the value of `attr` in
|
|
the set.
|
|
|
|
Example:
|
|
recursiveGetAttrsetWithJqPrefix {
|
|
example = [
|
|
{
|
|
irrelevant = "not interesting";
|
|
}
|
|
{
|
|
ignored = "ignored attr";
|
|
relevant = {
|
|
secret = {
|
|
_secret = "/path/to/secret";
|
|
quote = true;
|
|
};
|
|
};
|
|
}
|
|
];
|
|
} "_secret" -> { ".example[1].relevant.secret" = { _secret = "/path/to/secret"; quote = true; }; }
|
|
*/
|
|
recursiveGetAttrsetWithJqPrefix =
|
|
item: attr:
|
|
let
|
|
recurse =
|
|
prefix: item:
|
|
if item ? ${attr} then
|
|
nameValuePair prefix item
|
|
else if isDerivation item then
|
|
[ ]
|
|
else if isAttrs item then
|
|
map (
|
|
name:
|
|
let
|
|
escapedName = ''"${replaceStrings [ ''"'' "\\" ] [ ''\"'' "\\\\" ] name}"'';
|
|
in
|
|
recurse (prefix + "." + escapedName) 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"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
|
|
The attribute set { _secret = "/path/to/secret"; } can contain extra
|
|
options, currently it accepts the `quote = true|false` option.
|
|
|
|
If `quote = true` (default behavior), the content of the secret file will
|
|
be quoted as a string and embedded. Otherwise, if `quote = false`, the
|
|
content of the secret file will be parsed to JSON and then embedded.
|
|
|
|
Example:
|
|
If the file "/path/to/secret" contains the JSON document:
|
|
|
|
[
|
|
{ "a": "topsecretpassword1234" },
|
|
{ "b": "topsecretpassword5678" }
|
|
]
|
|
|
|
genJqSecretsReplacementSnippet {
|
|
example = [
|
|
{
|
|
irrelevant = "not interesting";
|
|
}
|
|
{
|
|
ignored = "ignored attr";
|
|
relevant = {
|
|
secret = {
|
|
_secret = "/path/to/secret";
|
|
quote = false;
|
|
};
|
|
};
|
|
}
|
|
];
|
|
} "/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": [
|
|
{ "a": "topsecretpassword1234" },
|
|
{ "b": "topsecretpassword5678" }
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
*/
|
|
genJqSecretsReplacementSnippet = genJqSecretsReplacementSnippet' "_secret";
|
|
|
|
# Like genJqSecretsReplacementSnippet, but allows the name of the
|
|
# attr which identifies the secret to be changed.
|
|
genJqSecretsReplacementSnippet' =
|
|
attr: set: output:
|
|
let
|
|
secretsRaw = recursiveGetAttrsetWithJqPrefix set attr;
|
|
# Set default option values
|
|
secrets = mapAttrs (
|
|
_name: set:
|
|
{
|
|
quote = true;
|
|
}
|
|
// set
|
|
) secretsRaw;
|
|
stringOrDefault = str: def: if str == "" then def else str;
|
|
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}.${attr}}')
|
|
export secret${toString index}
|
|
'') (attrNames secrets)
|
|
)
|
|
+ "\n"
|
|
+ "${pkgs.jq}/bin/jq >'${output}' "
|
|
+ escapeShellArg (
|
|
stringOrDefault (concatStringsSep " | " (
|
|
imap1 (
|
|
index: name:
|
|
''${name} = ($ENV.secret${toString index}${optionalString (!secrets.${name}.quote) " | fromjson"})''
|
|
) (attrNames secrets)
|
|
)) "."
|
|
)
|
|
+ ''
|
|
<<'EOF'
|
|
${toJSON set}
|
|
EOF
|
|
(( ! $inherit_errexit_enabled )) && shopt -u inherit_errexit
|
|
'';
|
|
|
|
/*
|
|
Remove packages of packagesToRemove from packages, based on their names.
|
|
Relies on package names and has quadratic complexity so use with caution!
|
|
|
|
Type:
|
|
removePackagesByName :: [package] -> [package] -> [package]
|
|
|
|
Example:
|
|
removePackagesByName [ nautilus file-roller ] [ file-roller totem ]
|
|
=> [ nautilus ]
|
|
*/
|
|
removePackagesByName =
|
|
packages: packagesToRemove:
|
|
let
|
|
namesToRemove = map getName packagesToRemove;
|
|
in
|
|
filter (x: !(elem (getName x) namesToRemove)) packages;
|
|
|
|
/*
|
|
Returns false if a package with the same name as the `package` is present in `packagesToDisable`.
|
|
|
|
Type:
|
|
disablePackageByName :: package -> [package] -> bool
|
|
|
|
Example:
|
|
disablePackageByName file-roller [ file-roller totem ]
|
|
=> false
|
|
|
|
Example:
|
|
disablePackageByName nautilus [ file-roller totem ]
|
|
=> true
|
|
*/
|
|
disablePackageByName =
|
|
package: packagesToDisable:
|
|
let
|
|
namesToDisable = map getName packagesToDisable;
|
|
in
|
|
!elem (getName package) namesToDisable;
|
|
|
|
systemdUtils = {
|
|
lib = import ./systemd-lib.nix {
|
|
inherit
|
|
lib
|
|
config
|
|
pkgs
|
|
utils
|
|
;
|
|
};
|
|
unitOptions = import ./systemd-unit-options.nix { inherit lib systemdUtils; };
|
|
types = import ./systemd-types.nix { inherit lib systemdUtils pkgs; };
|
|
network = {
|
|
units = import ./systemd-network-units.nix { inherit lib systemdUtils; };
|
|
};
|
|
};
|
|
};
|
|
in
|
|
utils
|