Merge commit bbdc2b27 into haskell-updates

This commit is contained in:
sternenseemann
2025-02-20 12:05:07 +01:00
1276 changed files with 45578 additions and 15687 deletions
+1 -1
View File
@@ -90,7 +90,7 @@ indent_style = unset
insert_final_newline = unset
trim_trailing_whitespace = unset
[pkgs/development/compilers/elm/registry.dat]
[registry.dat]
end_of_line = unset
insert_final_newline = unset
+6
View File
@@ -229,3 +229,9 @@ adb9714bd909df283c66bbd641bd631ff50a4260
# tmuxPlugins sha-to-sri.py script
516b1e74c358a9c4b06e5591f8c1a2897aad0c33
# treewide: migrate comments in lib to rfc145 style
ef85e0daa092c9eae0d32c7ce16b889728a5fbc0
d89ad6c70e0e89aaae75e9f886878ea4e103965a
e0fe216f4912dd88a021d12a44155fd2cfeb31c8
80d5b411f6397d5c3e755a0635d95742f76f3c75
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
steps:
# Use a GitHub App to create the PR so that CI gets triggered
# The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs
- uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3
- uses: actions/create-github-app-token@0d564482f06ca65fa9e77e2510873638c82206f2 # v1.11.5
id: app-token
with:
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
+2 -2
View File
@@ -63,7 +63,7 @@ jobs:
- name: Build codeowners validator
run: nix-build base/ci -A codeownersValidator
- uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3
- uses: actions/create-github-app-token@0d564482f06ca65fa9e77e2510873638c82206f2 # v1.11.5
id: app-token
with:
app-id: ${{ vars.OWNER_RO_APP_ID }}
@@ -96,7 +96,7 @@ jobs:
# This is intentional, because we need to request the review of owners as declared in the base branch.
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3
- uses: actions/create-github-app-token@0d564482f06ca65fa9e77e2510873638c82206f2 # v1.11.5
id: app-token
with:
app-id: ${{ vars.OWNER_APP_ID }}
+1 -1
View File
@@ -241,7 +241,7 @@ jobs:
steps:
# See ./codeowners-v2.yml, reuse the same App because we need the same permissions
# Can't use the token received from permissions above, because it can't get enough permissions
- uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3
- uses: actions/create-github-app-token@0d564482f06ca65fa9e77e2510873638c82206f2 # v1.11.5
id: app-token
with:
app-id: ${{ vars.OWNER_APP_ID }}
+5 -1
View File
@@ -5,7 +5,11 @@ on:
branches:
- master
paths:
- 'nixos/**'
- "nixos/**"
# Also build when the nixpkgs doc changed, since we take things like
# the release notes and some css and js files from there.
# See nixos/doc/manual/default.nix
- "doc/**"
permissions: {}
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
steps:
# Use a GitHub App to create the PR so that CI gets triggered
# The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs
- uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v1.11.3
- uses: actions/create-github-app-token@0d564482f06ca65fa9e77e2510873638c82206f2 # v1.11.5
id: app-token
with:
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
+6
View File
@@ -443,3 +443,9 @@ pkgs/by-name/lx/lxc* @adamcstephens
/pkgs/by-name/ap/apple-sdk @NixOS/darwin-core
/pkgs/os-specific/darwin/apple-source-releases @NixOS/darwin-core
/pkgs/stdenv/darwin @NixOS/darwin-core
# BEAM
pkgs/development/beam-modules/ @NixOS/beam
pkgs/development/interpreters/erlang/ @NixOS/beam
pkgs/development/interpreters/elixir/ @NixOS/beam
pkgs/development/interpreters/lfe/ @NixOS/beam
+11 -18
View File
@@ -17,11 +17,11 @@ stdenv.mkDerivation (finalAttrs: {
src = fetchFromGitLab {
owner = "pdftk-java";
repo = "pdftk";
rev = "v${finalAttrs.version}";
tag = "v${finalAttrs.version}";
hash = "sha256-ciKotTHSEcITfQYKFZ6sY2LZnXGChBJy0+eno8B3YHY=";
};
nativeBuildInputs = [ gradle ];
nativeBuildInputs = [ gradle makeWrapper ];
# if the package has dependencies, mitmCache must be set
mitmCache = gradle.fetchDeps {
@@ -44,7 +44,7 @@ stdenv.mkDerivation (finalAttrs: {
mkdir -p $out/{bin,share/pdftk}
cp build/libs/pdftk-all.jar $out/share/pdftk
makeWrapper ${jre}/bin/java $out/bin/pdftk \
makeWrapper ${lib.getExe jre} $out/bin/pdftk \
--add-flags "-jar $out/share/pdftk/pdftk-all.jar"
cp ${finalAttrs.src}/pdftk.1 $out/share/man/man1
@@ -74,6 +74,7 @@ package. Using the pdftk example above:
```nix
{ lib
, stdenv
, gradle
# ...
, pdftk
}:
@@ -87,30 +88,22 @@ stdenv.mkDerivation (finalAttrs: {
})
```
This allows you to `override` any arguments of the `pkg` used for
the update script (for example, `pkg = pdftk.override { enableSomeFlag =
true };`), so this is the preferred way.
This allows you to `override` any arguments of the `pkg` used for the update script (for example, `pkg = pdftk.override { enableSomeFlag = true };)`.
The second is to create a `let` binding for the package, like this:
The second is to use `finalAttrs.finalPackage` like this:
```nix
let self = stdenv.mkDerivation {
stdenv.mkDerivation (finalAttrs: {
# ...
mitmCache = gradle.fetchDeps {
pkg = self;
pkg = finalAttrs.finalPackage;
data = ./deps.json;
};
}; in self
})
```
The limitation of this method is that you cannot override the `pkg` derivations's arguments.
This is useful if you can't easily pass the derivation as its own
argument, or if your `mkDerivation` call is responsible for building
multiple packages.
In the former case, the update script will stay the same even if the
derivation is called with different arguments. In the latter case, the
update script will change depending on the derivation arguments. It's up
to you to decide which one would work best for your derivation.
In the former case, the update script will stay the same even if the derivation is called with different arguments. In the latter case, the update script will change depending on the derivation arguments. It's up to you to decide which one would work best for your derivation.
## Update Script {#gradle-update-script}
+10
View File
@@ -8,10 +8,20 @@
- `services.rippleDataApi` has been removed, as `ripple-data-api` was broken and had not been updated since 2022.
- The [`no-broken-symlinks` hook](https://nixos.org/manual/nixpkgs/unstable/#no-broken-symlinks.sh) was added to catch builds containing dangling or reflexive symlinks, as these are indicative of problems with packaging.
The hook can be disabled by providing `dontCheckForBrokenSymlinks = true;` as an argument to `mkDerivation`.
For more information, [check the docs](https://nixos.org/manual/nixpkgs/unstable/#no-broken-symlinks.sh) or [see this PR](https://github.com/NixOS/nixpkgs/pull/370750).
- The `nixLog*` family of functions made available through the standard environment have been rewritten to prefix messages with both the debug level and the function name of the caller.
The `nixLog` function, which logs unconditionally, was also re-introduced and modified to prefix messages with the function name of the caller.
For more information, [see this PR](https://github.com/NixOS/nixpkgs/pull/370742).
- The `rustPlatform.fetchCargoTarball` function is deprecated, because it relied on `cargo vendor` not changing its output format to keep fixed-output derivation hashes the same, which is a Nix invariant, and Cargo 1.84.0 changed `cargo vendor`'s output format.
It should generally be replaced with `rustPlatform.fetchCargoVendor`, but `rustPlatform.importCargoLock` may also be appropriate in some circumstances.
`rustPlatform.buildRustPackage` users must set `useFetchCargoVendor` to `true` and regenerate the `cargoHash`.
- Default ICU version updated from 74 to 76
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
### Titanium removed {#sec-nixpkgs-release-25.05-incompatibilities-titanium-removed}
+4 -4
View File
@@ -1560,6 +1560,10 @@ intel_drv.so: undefined symbol: vgaHWFreeHWRec
Adds the `-fzero-call-used-regs=used-gpr` compiler option. This causes the general-purpose registers that an architecture's calling convention considers "call-used" to be zeroed on return from the function. This can make it harder for attackers to construct useful ROP gadgets and also reduces the chance of data leakage from a function call.
#### `stackclashprotection` {#stackclashprotection}
This flag adds the `-fstack-clash-protection` compiler option, which causes growth of a program's stack to access each successive page in order. This should force the guard page to be accessed and cause an attempt to "jump over" this guard page to crash.
### Hardening flags disabled by default {#sec-hardening-flags-disabled-by-default}
The following flags are disabled by default and should be enabled with `hardeningEnable` for packages that take untrusted input like network services.
@@ -1599,10 +1603,6 @@ This should be turned off or fixed for build errors such as:
sorry, unimplemented: __builtin_clear_padding not supported for variable length aggregates
```
#### `stackclashprotection` {#stackclashprotection}
This flag adds the `-fstack-clash-protection` compiler option, which causes growth of a program's stack to access each successive page in order. This should force the guard page to be accessed and cause an attempt to "jump over" this guard page to crash.
#### `pacret` {#pacret}
This flag adds the `-mbranch-protection=pac-ret` compiler option on aarch64-linux targets. This uses ARM v8.3's Pointer Authentication feature to sign function return pointers before adding them to the stack. The pointer's authenticity is then validated before returning to its destination. This dramatically increases the difficulty of ROP exploitation techniques.
+6 -6
View File
@@ -193,7 +193,7 @@ source: ../config-options.json
### Build an environment {#sec-building-environment}
Using `packageOverrides`, it is possible to manage packages declaratively. This means that we can list all of our desired packages within a declarative Nix expression. For example, to have `aspell`, `bc`, `ffmpeg`, `coreutils`, `gdb`, `nixUnstable`, `emscripten`, `jq`, `nox`, and `silver-searcher`, we could use the following in `~/.config/nixpkgs/config.nix`:
Using `packageOverrides`, it is possible to manage packages declaratively. This means that we can list all of our desired packages within a declarative Nix expression. For example, to have `aspell`, `bc`, `ffmpeg`, `coreutils`, `gdb`, `nix`, `emscripten`, `jq`, `nox`, and `silver-searcher`, we could use the following in `~/.config/nixpkgs/config.nix`:
```nix
{
@@ -206,7 +206,7 @@ Using `packageOverrides`, it is possible to manage packages declaratively. This
coreutils
gdb
ffmpeg
nixUnstable
nix
emscripten
jq
nox
@@ -230,7 +230,7 @@ To install it into our environment, you can just run `nix-env -iA nixpkgs.myPack
coreutils
gdb
ffmpeg
nixUnstable
nix
emscripten
jq
nox
@@ -258,7 +258,7 @@ After building that new environment, look through `~/.nix-profile` to make sure
bc
coreutils
ffmpeg
nixUnstable
nix
emscripten
jq
nox
@@ -292,7 +292,7 @@ This provides us with some useful documentation for using our packages. However
coreutils
ffmpeg
man
nixUnstable
nix
emscripten
jq
nox
@@ -344,7 +344,7 @@ Configuring GNU info is a little bit trickier than man pages. To work correctly,
coreutils
ffmpeg
man
nixUnstable
nix
emscripten
jq
nox
+1 -1
View File
@@ -141,7 +141,7 @@ let
isStorePath isStringLike
isValidPosixName toShellVar toShellVars trim trimWith
escapeRegex escapeURL escapeXML replaceChars lowerChars
upperChars toLower toUpper addContextFrom splitString
upperChars toLower toUpper toSentenceCase addContextFrom splitString
removePrefix removeSuffix versionOlder versionAtLeast
getName getVersion match split
cmakeOptionType cmakeBool cmakeFeature
+32 -4
View File
@@ -267,7 +267,7 @@ rec {
# Set all entries not present to null
mapAttrs (name: value: null) (readDir path) // value;
/*
/**
A normalisation of a filesetTree suitable filtering with `builtins.path`:
- Replace all directories that have no files with `null`.
This removes directories that would be empty
@@ -276,7 +276,21 @@ rec {
Note that this function is strict, it evaluates the entire tree
Type: Path -> filesetTree -> filesetTree
# Inputs
`path`
: 1\. Function argument
`tree`
: 2\. Function argument
# Type
```
Path -> filesetTree -> filesetTree
```
*/
_normaliseTreeFilter =
path: tree:
@@ -298,7 +312,7 @@ rec {
else
tree;
/*
/**
A minimal normalisation of a filesetTree, intended for pretty-printing:
- If all children of a path are recursively included or empty directories, the path itself is also recursively included
- If all children of a path are fully excluded or empty directories, the path itself is an empty directory
@@ -307,7 +321,21 @@ rec {
Note that this function is partially lazy.
Type: Path -> filesetTree -> filesetTree (with "emptyDir"'s)
# Inputs
`path`
: 1\. Function argument
`tree`
: 2\. Function argument
# Type
```
Path -> filesetTree -> filesetTree (with "emptyDir"'s)
```
*/
_normaliseTreeMinimal =
path: tree:
+8 -5
View File
@@ -24,10 +24,11 @@ let
in
lib.mapAttrs mkLicense ({
/* License identifiers from spdx.org where possible.
* If you cannot find your license here, then look for a similar license or
* add it to this list. The URL mentioned above is a good source for inspiration.
*/
/**
License identifiers from spdx.org where possible.
If you cannot find your license here, then look for a similar license or
add it to this list. The URL mentioned above is a good source for inspiration.
*/
abstyles = {
spdxId = "Abstyles";
@@ -37,7 +38,9 @@ lib.mapAttrs mkLicense ({
acsl14 = {
fullName = "Anti-Capitalist Software License v1.4";
url = "https://anticapitalist.software/";
/* restrictions on corporations apply for both use and redistribution */
/**
restrictions on corporations apply for both use and redistribution
*/
free = false;
redistributable = false;
};
+418 -173
View File
@@ -74,14 +74,16 @@ let
decls
));
/* See https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules
or file://./../doc/module-system/module-system.chapter.md
/**
See https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules
or file://./../doc/module-system/module-system.chapter.md
!!! Please think twice before adding to this argument list! The more
that is specified here instead of in the modules themselves the harder
it is to transparently move a set of modules to be a submodule of another
config (as the proper arguments need to be replicated at each call to
evalModules) and the less declarative the module set is. */
!!! Please think twice before adding to this argument list! The more
that is specified here instead of in the modules themselves the harder
it is to transparently move a set of modules to be a submodule of another
config (as the proper arguments need to be replicated at each call to
evalModules) and the less declarative the module set is.
*/
evalModules = evalModulesArgs@
{ modules
, prefix ? []
@@ -378,30 +380,30 @@ let
else
m: m;
/*
Collects all modules recursively into the form
/**
Collects all modules recursively into the form
{
disabled = [ <list of disabled modules> ];
# All modules of the main module list
modules = [
{
key = <key1>;
module = <module for key1>;
# All modules imported by the module for key1
modules = [
{
key = <key1-1>;
module = <module for key1-1>;
# All modules imported by the module for key1-1
modules = [ ... ];
}
...
];
}
...
];
}
{
disabled = [ <list of disabled modules> ];
# All modules of the main module list
modules = [
{
key = <key1>;
module = <module for key1>;
# All modules imported by the module for key1
modules = [
{
key = <key1-1>;
module = <module for key1-1>;
# All modules imported by the module for key1-1
modules = [ ... ];
}
...
];
}
...
];
}
*/
collectStructuredModules =
let
@@ -459,12 +461,42 @@ let
in modulesPath: initialModules: args:
filterModules modulesPath (collectStructuredModules unknownModule "" initialModules args);
/* Wrap a module with a default location for reporting errors. */
/**
Wrap a module with a default location for reporting errors.
# Inputs
`file`
: 1\. Function argument
`m`
: 2\. Function argument
*/
setDefaultModuleLocation = file: m:
{ _file = file; imports = [ m ]; };
/* Massage a module into canonical form, that is, a set consisting
of options, config and imports attributes. */
/**
Massage a module into canonical form, that is, a set consisting
of options, config and imports attributes.
# Inputs
`file`
: 1\. Function argument
`key`
: 2\. Function argument
`m`
: 3\. Function argument
*/
unifyModuleSyntax = file: key: m:
let
addMeta = config: if m ? meta
@@ -528,26 +560,38 @@ let
# works.
in f (args // extraArgs);
/* Merge a list of modules. This will recurse over the option
declarations in all modules, combining them into a single set.
At the same time, for each option declaration, it will merge the
corresponding option definitions in all machines, returning them
in the value attribute of each option.
/**
Merge a list of modules. This will recurse over the option
declarations in all modules, combining them into a single set.
At the same time, for each option declaration, it will merge the
corresponding option definitions in all machines, returning them
in the value attribute of each option.
This returns a set like
{
# A recursive set of options along with their final values
matchedOptions = {
foo = { _type = "option"; value = "option value of foo"; ... };
bar.baz = { _type = "option"; value = "option value of bar.baz"; ... };
...
};
# A list of definitions that weren't matched by any option
unmatchedDefns = [
{ file = "file.nix"; prefix = [ "qux" ]; value = "qux"; }
...
];
}
This returns a set like
{
# A recursive set of options along with their final values
matchedOptions = {
foo = { _type = "option"; value = "option value of foo"; ... };
bar.baz = { _type = "option"; value = "option value of bar.baz"; ... };
...
};
# A list of definitions that weren't matched by any option
unmatchedDefns = [
{ file = "file.nix"; prefix = [ "qux" ]; value = "qux"; }
...
];
}
# Inputs
`prefix`
: 1\. Function argument
`modules`
: 2\. Function argument
*/
mergeModules = prefix: modules:
mergeModules' prefix modules
@@ -740,17 +784,30 @@ let
in
throw (concatStringsSep "\n\n" paragraphs);
/* Merge multiple option declarations into a single declaration. In
general, there should be only one declaration of each option.
The exception is the options attribute, which specifies
sub-options. These can be specified multiple times to allow one
module to add sub-options to an option declared somewhere else
(e.g. multiple modules define sub-options for fileSystems).
/**
Merge multiple option declarations into a single declaration. In
general, there should be only one declaration of each option.
The exception is the options attribute, which specifies
sub-options. These can be specified multiple times to allow one
module to add sub-options to an option declared somewhere else
(e.g. multiple modules define sub-options for fileSystems).
'loc' is the list of attribute names where the option is located.
'loc' is the list of attribute names where the option is located.
'opts' is a list of modules. Each module has an options attribute which
correspond to the definition of 'loc' in 'opt.file'. */
'opts' is a list of modules. Each module has an options attribute which
correspond to the definition of 'loc' in 'opt.file'.
# Inputs
`loc`
: 1\. Function argument
`opts`
: 2\. Function argument
*/
mergeOptionDecls =
loc: opts:
foldl' (res: opt:
@@ -819,8 +876,25 @@ let
} // typeSet
) { inherit loc; declarations = []; declarationPositions = []; options = []; } opts;
/* Merge all the definitions of an option to produce the final
config value. */
/**
Merge all the definitions of an option to produce the final
config value.
# Inputs
`loc`
: 1\. Function argument
`opt`
: 2\. Function argument
`defs`
: 3\. Function argument
*/
evalOptionValue = loc: opt: defs:
let
# Add in the default value for this option, if any.
@@ -902,20 +976,28 @@ let
else {};
};
/* Given a config set, expand mkMerge properties, and push down the
other properties into the children. The result is a list of
config sets that do not have properties at top-level. For
example,
/**
Given a config set, expand mkMerge properties, and push down the
other properties into the children. The result is a list of
config sets that do not have properties at top-level. For
example,
mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
mkMerge [ { boot = set1; } (mkIf cond { boot = set2; services = set3; }) ]
is transformed into
is transformed into
[ { boot = set1; } { boot = mkIf cond set2; services = mkIf cond set3; } ].
[ { boot = set1; } { boot = mkIf cond set2; services = mkIf cond set3; } ].
This transform is the critical step that allows mkIf conditions
to refer to the full configuration without creating an infinite
recursion.
This transform is the critical step that allows mkIf conditions
to refer to the full configuration without creating an infinite
recursion.
# Inputs
`cfg`
: 1\. Function argument
*/
pushDownProperties = cfg:
if cfg._type or "" == "merge" then
@@ -927,15 +1009,23 @@ let
else # FIXME: handle mkOrder?
[ cfg ];
/* Given a config value, expand mkMerge properties, and discharge
any mkIf conditions. That is, this is the place where mkIf
conditions are actually evaluated. The result is a list of
config values. For example, mkIf false x yields [],
mkIf true x yields [x], and
/**
Given a config value, expand mkMerge properties, and discharge
any mkIf conditions. That is, this is the place where mkIf
conditions are actually evaluated. The result is a list of
config values. For example, mkIf false x yields [],
mkIf true x yields [x], and
mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ]
mkMerge [ 1 (mkIf true 2) (mkIf true (mkIf false 3)) ]
yields [ 1 2 ].
yields [ 1 2 ].
# Inputs
`def`
: 1\. Function argument
*/
dischargeProperties = def:
if def._type or "" == "merge" then
@@ -951,24 +1041,32 @@ let
else
[ def ];
/* Given a list of config values, process the mkOverride properties,
that is, return the values that have the highest (that is,
numerically lowest) priority, and strip the mkOverride
properties. For example,
/**
Given a list of config values, process the mkOverride properties,
that is, return the values that have the highest (that is,
numerically lowest) priority, and strip the mkOverride
properties. For example,
[ { file = "/1"; value = mkOverride 10 "a"; }
{ file = "/2"; value = mkOverride 20 "b"; }
{ file = "/3"; value = "z"; }
{ file = "/4"; value = mkOverride 10 "d"; }
]
[ { file = "/1"; value = mkOverride 10 "a"; }
{ file = "/2"; value = mkOverride 20 "b"; }
{ file = "/3"; value = "z"; }
{ file = "/4"; value = mkOverride 10 "d"; }
]
yields
yields
[ { file = "/1"; value = "a"; }
{ file = "/4"; value = "d"; }
]
[ { file = "/1"; value = "a"; }
{ file = "/4"; value = "d"; }
]
Note that "z" has the default priority 100.
Note that "z" has the default priority 100.
# Inputs
`defs`
: 1\. Function argument
*/
filterOverrides = defs: (filterOverrides' defs).values;
@@ -982,9 +1080,18 @@ let
inherit highestPrio;
};
/* Sort a list of properties. The sort priority of a property is
defaultOrderPriority by default, but can be overridden by wrapping the property
using mkOrder. */
/**
Sort a list of properties. The sort priority of a property is
defaultOrderPriority by default, but can be overridden by wrapping the property
using mkOrder.
# Inputs
`defs`
: 1\. Function argument
*/
sortProperties = defs:
let
strip = def:
@@ -1004,14 +1111,24 @@ let
else opt // { type = opt.type.substSubModules opt.options; options = []; };
/*
/**
Merge an option's definitions in a way that preserves the priority of the
individual attributes in the option value.
This does not account for all option semantics, such as readOnly.
Type:
option -> attrsOf { highestPrio, value }
# Inputs
`opt`
: 1\. Function argument
# Type
```
option -> attrsOf { highestPrio, value }
```
*/
mergeAttrDefinitionsWithPrio = opt:
let
@@ -1038,7 +1155,20 @@ let
})
defsByAttr;
/* Properties. */
/**
Properties.
# Inputs
`condition`
: 1\. Function argument
`content`
: 2\. Function argument
*/
mkIf = condition: content:
{ _type = "if";
@@ -1116,21 +1246,46 @@ let
mkAliasIfDef = option:
mkIf (isOption option && option.isDefined);
/* Compatibility. */
/**
Compatibility.
# Inputs
`modules`
: 1\. Function argument
`args`
: 2\. Function argument
*/
fixMergeModules = modules: args: evalModules { inherit modules args; check = false; };
/* Return a module that causes a warning to be shown if the
specified option is defined. For example,
/**
Return a module that causes a warning to be shown if the
specified option is defined. For example,
mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ] "<replacement instructions>"
mkRemovedOptionModule [ "boot" "loader" "grub" "bootDevice" ] "<replacement instructions>"
causes a assertion if the user defines boot.loader.grub.bootDevice.
causes a assertion if the user defines boot.loader.grub.bootDevice.
replacementInstructions is a string that provides instructions on
how to achieve the same functionality without the removed option,
or alternatively a reasoning why the functionality is not needed.
replacementInstructions SHOULD be provided!
replacementInstructions is a string that provides instructions on
how to achieve the same functionality without the removed option,
or alternatively a reasoning why the functionality is not needed.
replacementInstructions SHOULD be provided!
# Inputs
`optionName`
: 1\. Function argument
`replacementInstructions`
: 2\. Function argument
*/
mkRemovedOptionModule = optionName: replacementInstructions:
{ options, ... }:
@@ -1148,18 +1303,30 @@ let
}];
};
/* Return a module that causes a warning to be shown if the
specified "from" option is defined; the defined value is however
forwarded to the "to" option. This can be used to rename options
while providing backward compatibility. For example,
/**
Return a module that causes a warning to be shown if the
specified "from" option is defined; the defined value is however
forwarded to the "to" option. This can be used to rename options
while providing backward compatibility. For example,
mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ]
mkRenamedOptionModule [ "boot" "copyKernels" ] [ "boot" "loader" "grub" "copyKernels" ]
forwards any definitions of boot.copyKernels to
boot.loader.grub.copyKernels while printing a warning.
forwards any definitions of boot.copyKernels to
boot.loader.grub.copyKernels while printing a warning.
This also copies over the priority from the aliased option to the
non-aliased option.
This also copies over the priority from the aliased option to the
non-aliased option.
# Inputs
`from`
: 1\. Function argument
`to`
: 2\. Function argument
*/
mkRenamedOptionModule = from: to: doRename {
inherit from to;
@@ -1169,12 +1336,16 @@ let
};
mkRenamedOptionModuleWith = {
/* Old option path as list of strings. */
/**
Old option path as list of strings.
*/
from,
/* New option path as list of strings. */
/**
New option path as list of strings.
*/
to,
/*
/**
Release number of the first release that contains the rename, ignoring backports.
Set it to the upcoming release, matching the nixpkgs/.version file.
*/
@@ -1188,33 +1359,49 @@ let
"Obsolete option `${showOption from}' is used. It was renamed to `${showOption to}'.";
};
/* Return a module that causes a warning to be shown if any of the "from"
option is defined; the defined values can be used in the "mergeFn" to set
the "to" value.
This function can be used to merge multiple options into one that has a
different type.
/**
Return a module that causes a warning to be shown if any of the "from"
option is defined; the defined values can be used in the "mergeFn" to set
the "to" value.
This function can be used to merge multiple options into one that has a
different type.
"mergeFn" takes the module "config" as a parameter and must return a value
of "to" option type.
"mergeFn" takes the module "config" as a parameter and must return a value
of "to" option type.
mkMergedOptionModule
[ [ "a" "b" "c" ]
[ "d" "e" "f" ] ]
[ "x" "y" "z" ]
(config:
let value = p: getAttrFromPath p config;
in
if (value [ "a" "b" "c" ]) == true then "foo"
else if (value [ "d" "e" "f" ]) == true then "bar"
else "baz")
mkMergedOptionModule
[ [ "a" "b" "c" ]
[ "d" "e" "f" ] ]
[ "x" "y" "z" ]
(config:
let value = p: getAttrFromPath p config;
in
if (value [ "a" "b" "c" ]) == true then "foo"
else if (value [ "d" "e" "f" ]) == true then "bar"
else "baz")
- options.a.b.c is a removed boolean option
- options.d.e.f is a removed boolean option
- options.x.y.z is a new str option that combines a.b.c and d.e.f
functionality
- options.a.b.c is a removed boolean option
- options.d.e.f is a removed boolean option
- options.x.y.z is a new str option that combines a.b.c and d.e.f
functionality
This show a warning if any a.b.c or d.e.f is set, and set the value of
x.y.z to the result of the merge function
This show a warning if any a.b.c or d.e.f is set, and set the value of
x.y.z to the result of the merge function
# Inputs
`from`
: 1\. Function argument
`to`
: 2\. Function argument
`mergeFn`
: 3\. Function argument
*/
mkMergedOptionModule = from: to: mergeFn:
{ config, options, ... }:
@@ -1240,33 +1427,62 @@ let
(mergeFn config)));
};
/* Single "from" version of mkMergedOptionModule.
Return a module that causes a warning to be shown if the "from" option is
defined; the defined value can be used in the "mergeFn" to set the "to"
value.
This function can be used to change an option into another that has a
different type.
/**
Single "from" version of mkMergedOptionModule.
Return a module that causes a warning to be shown if the "from" option is
defined; the defined value can be used in the "mergeFn" to set the "to"
value.
This function can be used to change an option into another that has a
different type.
"mergeFn" takes the module "config" as a parameter and must return a value of
"to" option type.
"mergeFn" takes the module "config" as a parameter and must return a value of
"to" option type.
mkChangedOptionModule [ "a" "b" "c" ] [ "x" "y" "z" ]
(config:
let value = getAttrFromPath [ "a" "b" "c" ] config;
in
if value > 100 then "high"
else "normal")
mkChangedOptionModule [ "a" "b" "c" ] [ "x" "y" "z" ]
(config:
let value = getAttrFromPath [ "a" "b" "c" ] config;
in
if value > 100 then "high"
else "normal")
- options.a.b.c is a removed int option
- options.x.y.z is a new str option that supersedes a.b.c
- options.a.b.c is a removed int option
- options.x.y.z is a new str option that supersedes a.b.c
This show a warning if a.b.c is set, and set the value of x.y.z to the
result of the change function
This show a warning if a.b.c is set, and set the value of x.y.z to the
result of the change function
# Inputs
`from`
: 1\. Function argument
`to`
: 2\. Function argument
`changeFn`
: 3\. Function argument
*/
mkChangedOptionModule = from: to: changeFn:
mkMergedOptionModule [ from ] to changeFn;
/* Like mkRenamedOptionModule, but doesn't show a warning. */
/**
Like mkRenamedOptionModule, but doesn't show a warning.
# Inputs
`from`
: 1\. Function argument
`to`
: 2\. Function argument
*/
mkAliasOptionModule = from: to: doRename {
inherit from to;
visible = true;
@@ -1274,13 +1490,15 @@ let
use = id;
};
/* Transitional version of mkAliasOptionModule that uses MD docs.
/**
Transitional version of mkAliasOptionModule that uses MD docs.
This function is no longer necessary and merely an alias of `mkAliasOptionModule`.
This function is no longer necessary and merely an alias of `mkAliasOptionModule`.
*/
mkAliasOptionModuleMD = mkAliasOptionModule;
/* mkDerivedConfig : Option a -> (a -> Definition b) -> Definition b
/**
mkDerivedConfig : Option a -> (a -> Definition b) -> Definition b
Create config definitions with the same priority as the definition of another option.
This should be used for option definitions where one option sets the value of another as a convenience.
@@ -1288,6 +1506,17 @@ let
value using `mkDerivedConfig options.text (pkgs.writeText "filename.conf")`.
It takes care of setting the right priority using `mkOverride`.
# Inputs
`opt`
: 1\. Function argument
`f`
: 2\. Function argument
*/
# TODO: make the module system error message include information about `opt` in
# error messages about conflicts. E.g. introduce a variation of `mkOverride` which
@@ -1300,10 +1529,10 @@ let
(opt.highestPrio or defaultOverridePriority)
(f opt.value);
/*
/**
Return a module that help declares an option that has been renamed.
When a value is defined for the old option, it is forwarded to the `to` option.
*/
*/
doRename = {
# List of strings representing the attribute path of the old option.
from,
@@ -1450,18 +1679,34 @@ let
modulePath: staticArg:
lib.setDefaultModuleLocation modulePath (import modulePath staticArg);
/* Use this function to import a JSON file as NixOS configuration.
/**
Use this function to import a JSON file as NixOS configuration.
modules.importJSON :: path -> attrs
modules.importJSON :: path -> attrs
# Inputs
`file`
: 1\. Function argument
*/
importJSON = file: {
_file = file;
config = lib.importJSON file;
};
/* Use this function to import a TOML file as NixOS configuration.
/**
Use this function to import a TOML file as NixOS configuration.
modules.importTOML :: path -> attrs
modules.importTOML :: path -> attrs
# Inputs
`file`
: 1\. Function argument
*/
importTOML = file: {
_file = file;
+2 -2
View File
@@ -16,7 +16,7 @@ let
inherit (lib.lists) last;
/*
/**
IPv6 addresses are 128-bit identifiers. The preferred form is 'x:x:x:x:x:x:x:x',
where the 'x's are one to four hexadecimal digits of the eight 16-bit pieces of
the address. See RFC 4291.
@@ -138,7 +138,7 @@ let
parseIpv6FromString = addr: parseExpandedIpv6 (expandIpv6 addr);
in
{
/*
/**
Internally, an IPv6 address is stored as a list of 16-bit integers with 8
elements. Wherever you see `IPv6` in internal functions docs, it means that
it is a list of integers produced by one of the internal parsers, such as
+137 -41
View File
@@ -426,18 +426,29 @@ rec {
else if all isInt list && all (x: x == head list) list then head list
else throw "Cannot merge definitions of `${showOption loc}'. Definition values:${showDefs defs}";
/*
/**
Require a single definition.
WARNING: Does not perform nested checks, as this does not run the merge function!
*/
mergeOneOption = mergeUniqueOption { message = ""; };
/*
/**
Require a single definition.
NOTE: When the type is not checked completely by check, pass a merge function for further checking (of sub-attributes, etc).
*/
# Inputs
`loc`
: 2\. Function argument
`defs`
: 3\. Function argument
*/
mergeUniqueOption = args@{
message,
# WARNING: the default merge function assumes that the definition is a valid (option) value. You MUST pass a merge function if the return value needs to be
@@ -452,7 +463,20 @@ rec {
assert length defs > 1;
throw "The option `${showOption loc}' is defined multiple times while it's expected to be unique.\n${message}\nDefinition values:${showDefs defs}\n${prioritySuggestion}";
/* "Merge" option definitions by checking that they all have the same value. */
/**
"Merge" option definitions by checking that they all have the same value.
# Inputs
`loc`
: 1\. Function argument
`defs`
: 2\. Function argument
*/
mergeEqualOption = loc: defs:
if defs == [] then abort "This case should never happen."
# Return early if we only have one element
@@ -465,23 +489,47 @@ rec {
else
first) (head defs) (tail defs)).value;
/* Extracts values of all "value" keys of the given list.
/**
Extracts values of all "value" keys of the given list.
Type: getValues :: [ { value :: a; } ] -> [a]
# Type
Example:
getValues [ { value = 1; } { value = 2; } ] // => [ 1 2 ]
getValues [ ] // => [ ]
```
getValues :: [ { value :: a; } ] -> [a]
```
# Examples
:::{.example}
## `getValues` usage example
```nix
getValues [ { value = 1; } { value = 2; } ] // => [ 1 2 ]
getValues [ ] // => [ ]
```
:::
*/
getValues = map (x: x.value);
/* Extracts values of all "file" keys of the given list
/**
Extracts values of all "file" keys of the given list
Type: getFiles :: [ { file :: a; } ] -> [a]
# Type
Example:
getFiles [ { file = "file1"; } { file = "file2"; } ] // => [ "file1" "file2" ]
getFiles [ ] // => [ ]
```
getFiles :: [ { file :: a; } ] -> [a]
```
# Examples
:::{.example}
## `getFiles` usage example
```nix
getFiles [ { file = "file1"; } { file = "file2"; } ] // => [ "file1" "file2" ]
getFiles [ ] // => [ ]
```
:::
*/
getFiles = map (x: x.file);
@@ -530,16 +578,24 @@ rec {
[ docOption ] ++ optionals subOptionsVisible subOptions) (collect isOption options);
/* This function recursively removes all derivation attributes from
`x` except for the `name` attribute.
/**
This function recursively removes all derivation attributes from
`x` except for the `name` attribute.
This is to make the generation of `options.xml` much more
efficient: the XML representation of derivations is very large
(on the order of megabytes) and is not actually used by the
manual generator.
This is to make the generation of `options.xml` much more
efficient: the XML representation of derivations is very large
(on the order of megabytes) and is not actually used by the
manual generator.
This function was made obsolete by renderOptionValue and is kept for
compatibility with out-of-tree code.
This function was made obsolete by renderOptionValue and is kept for
compatibility with out-of-tree code.
# Inputs
`x`
: 1\. Function argument
*/
scrubOptionValue = x:
if isDerivation x then
@@ -549,8 +605,16 @@ rec {
else x;
/* Ensures that the given option value (default or example) is a `_type`d string
by rendering Nix values to `literalExpression`s.
/**
Ensures that the given option value (default or example) is a `_type`d string
by rendering Nix values to `literalExpression`s.
# Inputs
`v`
: 1\. Function argument
*/
renderOptionValue = v:
if v ? _type && v ? text then v
@@ -560,10 +624,18 @@ rec {
} v);
/* For use in the `defaultText` and `example` option attributes. Causes the
given string to be rendered verbatim in the documentation as Nix code. This
is necessary for complex values, e.g. functions, or values that depend on
other values or packages.
/**
For use in the `defaultText` and `example` option attributes. Causes the
given string to be rendered verbatim in the documentation as Nix code. This
is necessary for complex values, e.g. functions, or values that depend on
other values or packages.
# Inputs
`text`
: 1\. Function argument
*/
literalExpression = text:
if ! isString text then throw "literalExpression expects a string."
@@ -571,9 +643,17 @@ rec {
literalExample = lib.warn "lib.literalExample is deprecated, use lib.literalExpression instead, or use lib.literalMD for a non-Nix description." literalExpression;
/* For use in the `defaultText` and `example` option attributes. Causes the
given MD text to be inserted verbatim in the documentation, for when
a `literalExpression` would be too hard to read.
/**
For use in the `defaultText` and `example` option attributes. Causes the
given MD text to be inserted verbatim in the documentation, for when
a `literalExpression` would be too hard to read.
# Inputs
`text`
: 1\. Function argument
*/
literalMD = text:
if ! isString text then throw "literalMD expects a string."
@@ -581,18 +661,34 @@ rec {
# Helper functions.
/* Convert an option, described as a list of the option parts to a
human-readable version.
/**
Convert an option, described as a list of the option parts to a
human-readable version.
Example:
(showOption ["foo" "bar" "baz"]) == "foo.bar.baz"
(showOption ["foo" "bar.baz" "tux"]) == "foo.\"bar.baz\".tux"
(showOption ["windowManager" "2bwm" "enable"]) == "windowManager.\"2bwm\".enable"
Placeholders will not be quoted as they are not actual values:
(showOption ["foo" "*" "bar"]) == "foo.*.bar"
(showOption ["foo" "<name>" "bar"]) == "foo.<name>.bar"
(showOption ["foo" "<myPlaceholder>" "bar"]) == "foo.<myPlaceholder>.bar"
# Inputs
`parts`
: 1\. Function argument
# Examples
:::{.example}
## `showOption` usage example
```nix
(showOption ["foo" "bar" "baz"]) == "foo.bar.baz"
(showOption ["foo" "bar.baz" "tux"]) == "foo.\"bar.baz\".tux"
(showOption ["windowManager" "2bwm" "enable"]) == "windowManager.\"2bwm\".enable"
Placeholders will not be quoted as they are not actual values:
(showOption ["foo" "*" "bar"]) == "foo.*.bar"
(showOption ["foo" "<name>" "bar"]) == "foo.<name>.bar"
(showOption ["foo" "<myPlaceholder>" "bar"]) == "foo.<myPlaceholder>.bar"
```
:::
*/
showOption = parts: let
# If the part is a named placeholder of the form "<...>" don't escape it.
+315 -167
View File
@@ -165,7 +165,7 @@ in
# No rec! Add dependencies on this file at the top.
{
/*
/**
Append a subpath string to a path.
Like `path + ("/" + string)` but safer, because it errors instead of returning potentially surprising results.
@@ -178,34 +178,54 @@ in
append p s == append p (subpath.normalise s)
Type:
append :: Path -> String -> Path
# Inputs
Example:
append /foo "bar/baz"
=> /foo/bar/baz
`path`
# subpaths don't need to be normalised
append /foo "./bar//baz/./"
=> /foo/bar/baz
: The absolute path to append to
# can append to root directory
append /. "foo/bar"
=> /foo/bar
`subpath`
# first argument needs to be a path value type
append "/foo" "bar"
=> <error>
: The subpath string to append
# second argument needs to be a valid subpath string
append /foo /bar
=> <error>
append /foo ""
=> <error>
append /foo "/bar"
=> <error>
append /foo "../bar"
=> <error>
# Type
```
append :: Path -> String -> Path
```
# Examples
:::{.example}
## `append` usage example
```nix
append /foo "bar/baz"
=> /foo/bar/baz
# subpaths don't need to be normalised
append /foo "./bar//baz/./"
=> /foo/bar/baz
# can append to root directory
append /. "foo/bar"
=> /foo/bar
# first argument needs to be a path value type
append "/foo" "bar"
=> <error>
# second argument needs to be a valid subpath string
append /foo /bar
=> <error>
append /foo ""
=> <error>
append /foo "/bar"
=> <error>
append /foo "../bar"
=> <error>
```
:::
*/
append =
# The absolute path to append to
@@ -219,7 +239,7 @@ in
${subpathInvalidReason subpath}'';
path + ("/" + subpath);
/*
/**
Whether the first path is a component-wise prefix of the second path.
Laws:
@@ -228,18 +248,34 @@ in
- `hasPrefix` is a [non-strict partial order](https://en.wikipedia.org/wiki/Partially_ordered_set#Non-strict_partial_order) over the set of all path values.
Type:
hasPrefix :: Path -> Path -> Bool
# Inputs
Example:
hasPrefix /foo /foo/bar
=> true
hasPrefix /foo /foo
=> true
hasPrefix /foo/bar /foo
=> false
hasPrefix /. /foo
=> true
`path1`
: 1\. Function argument
# Type
```
hasPrefix :: Path -> Path -> Bool
```
# Examples
:::{.example}
## `hasPrefix` usage example
```nix
hasPrefix /foo /foo/bar
=> true
hasPrefix /foo /foo
=> true
hasPrefix /foo/bar /foo
=> false
hasPrefix /. /foo
=> true
```
:::
*/
hasPrefix =
path1:
@@ -261,7 +297,7 @@ in
take (length path1Deconstructed.components) path2Deconstructed.components
== path1Deconstructed.components;
/*
/**
Remove the first path as a component-wise prefix from the second path.
The result is a [normalised subpath string](#function-library-lib.path.subpath.normalise).
@@ -271,18 +307,34 @@ in
removePrefix p (append p s) == subpath.normalise s
Type:
removePrefix :: Path -> Path -> String
# Inputs
Example:
removePrefix /foo /foo/bar/baz
=> "./bar/baz"
removePrefix /foo /foo
=> "./."
removePrefix /foo/bar /foo
=> <error>
removePrefix /. /foo
=> "./foo"
`path1`
: 1\. Function argument
# Type
```
removePrefix :: Path -> Path -> String
```
# Examples
:::{.example}
## `removePrefix` usage example
```nix
removePrefix /foo /foo/bar/baz
=> "./bar/baz"
removePrefix /foo /foo
=> "./."
removePrefix /foo/bar /foo
=> <error>
removePrefix /. /foo
=> "./foo"
```
:::
*/
removePrefix =
path1:
@@ -310,7 +362,7 @@ in
second argument: "${toString path2}" with root "${toString path2Deconstructed.root}"'';
joinRelPath components;
/*
/**
Split the filesystem root from a [path](https://nixos.org/manual/nix/stable/language/values.html#type-path).
The result is an attribute set with these attributes:
- `root`: The filesystem root of the path, meaning that this directory has no parent directory.
@@ -328,22 +380,38 @@ in
dirOf (splitRoot p).root == (splitRoot p).root
Type:
splitRoot :: Path -> { root :: Path, subpath :: String }
# Inputs
Example:
splitRoot /foo/bar
=> { root = /.; subpath = "./foo/bar"; }
`path`
splitRoot /.
=> { root = /.; subpath = "./."; }
: The path to split the root off of
# Nix neutralises `..` path components for all path values automatically
splitRoot /foo/../bar
=> { root = /.; subpath = "./bar"; }
# Type
splitRoot "/foo/bar"
=> <error>
```
splitRoot :: Path -> { root :: Path, subpath :: String }
```
# Examples
:::{.example}
## `splitRoot` usage example
```nix
splitRoot /foo/bar
=> { root = /.; subpath = "./foo/bar"; }
splitRoot /.
=> { root = /.; subpath = "./."; }
# Nix neutralises `..` path components for all path values automatically
splitRoot /foo/../bar
=> { root = /.; subpath = "./bar"; }
splitRoot "/foo/bar"
=> <error>
```
:::
*/
splitRoot =
# The path to split the root off of
@@ -358,7 +426,7 @@ in
subpath = joinRelPath deconstructed.components;
};
/*
/**
Whether a [path](https://nixos.org/manual/nix/stable/language/values.html#type-path)
has a [store path](https://nixos.org/manual/nix/stable/store/store-path.html#store-path)
as a prefix.
@@ -371,33 +439,49 @@ in
which occur when Nix files in the store use relative path expressions.
:::
Type:
hasStorePathPrefix :: Path -> Bool
# Inputs
Example:
# Subpaths of derivation outputs have a store path as a prefix
hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo/bar/baz
=> true
`path`
# The store directory itself is not a store path
hasStorePathPrefix /nix/store
=> false
: 1\. Function argument
# Derivation outputs are store paths themselves
hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo
=> true
# Type
# Paths outside the Nix store don't have a store path prefix
hasStorePathPrefix /home/user
=> false
```
hasStorePathPrefix :: Path -> Bool
```
# Not all paths under the Nix store are store paths
hasStorePathPrefix /nix/store/.links/10gg8k3rmbw8p7gszarbk7qyd9jwxhcfq9i6s5i0qikx8alkk4hq
=> false
# Examples
:::{.example}
## `hasStorePathPrefix` usage example
# Store derivations are also store paths themselves
hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo.drv
=> true
```nix
# Subpaths of derivation outputs have a store path as a prefix
hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo/bar/baz
=> true
# The store directory itself is not a store path
hasStorePathPrefix /nix/store
=> false
# Derivation outputs are store paths themselves
hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo
=> true
# Paths outside the Nix store don't have a store path prefix
hasStorePathPrefix /home/user
=> false
# Not all paths under the Nix store are store paths
hasStorePathPrefix /nix/store/.links/10gg8k3rmbw8p7gszarbk7qyd9jwxhcfq9i6s5i0qikx8alkk4hq
=> false
# Store derivations are also store paths themselves
hasStorePathPrefix /nix/store/nvl9ic0pj1fpyln3zaqrf4cclbqdfn1j-foo.drv
=> true
```
:::
*/
hasStorePathPrefix =
path:
@@ -414,7 +498,7 @@ in
"lib.path.hasStorePathPrefix: Argument has a filesystem root (${toString deconstructed.root}) that's not /, which is currently not supported.";
componentsHaveStorePathPrefix deconstructed.components;
/*
/**
Whether a value is a valid subpath string.
A subpath string points to a specific file or directory within an absolute base directory.
@@ -428,39 +512,55 @@ in
- The string doesn't contain any `..` path components.
Type:
subpath.isValid :: String -> Bool
# Inputs
Example:
# Not a string
subpath.isValid null
=> false
`value`
# Empty string
subpath.isValid ""
=> false
: The value to check
# Absolute path
subpath.isValid "/foo"
=> false
# Type
# Contains a `..` path component
subpath.isValid "../foo"
=> false
```
subpath.isValid :: String -> Bool
```
# Valid subpath
subpath.isValid "foo/bar"
=> true
# Examples
:::{.example}
## `subpath.isValid` usage example
# Doesn't need to be normalised
subpath.isValid "./foo//bar/"
=> true
```nix
# Not a string
subpath.isValid null
=> false
# Empty string
subpath.isValid ""
=> false
# Absolute path
subpath.isValid "/foo"
=> false
# Contains a `..` path component
subpath.isValid "../foo"
=> false
# Valid subpath
subpath.isValid "foo/bar"
=> true
# Doesn't need to be normalised
subpath.isValid "./foo//bar/"
=> true
```
:::
*/
subpath.isValid =
# The value to check
value: subpathInvalidReason value == null;
/*
/**
Join subpath strings together using `/`, returning a normalised subpath string.
Like `concatStringsSep "/"` but safer, specifically:
@@ -492,30 +592,46 @@ in
ps != [] -> subpath.join ps == subpath.normalise (concatStringsSep "/" ps)
Type:
subpath.join :: [ String ] -> String
# Inputs
Example:
subpath.join [ "foo" "bar/baz" ]
=> "./foo/bar/baz"
`subpaths`
# normalise the result
subpath.join [ "./foo" "." "bar//./baz/" ]
=> "./foo/bar/baz"
: The list of subpaths to join together
# passing an empty list results in the current directory
subpath.join [ ]
=> "./."
# Type
# elements must be valid subpath strings
subpath.join [ /foo ]
=> <error>
subpath.join [ "" ]
=> <error>
subpath.join [ "/foo" ]
=> <error>
subpath.join [ "../foo" ]
=> <error>
```
subpath.join :: [ String ] -> String
```
# Examples
:::{.example}
## `subpath.join` usage example
```nix
subpath.join [ "foo" "bar/baz" ]
=> "./foo/bar/baz"
# normalise the result
subpath.join [ "./foo" "." "bar//./baz/" ]
=> "./foo/bar/baz"
# passing an empty list results in the current directory
subpath.join [ ]
=> "./."
# elements must be valid subpath strings
subpath.join [ /foo ]
=> <error>
subpath.join [ "" ]
=> <error>
subpath.join [ "/foo" ]
=> <error>
subpath.join [ "../foo" ]
=> <error>
```
:::
*/
subpath.join =
# The list of subpaths to join together
@@ -537,7 +653,7 @@ in
${subpathInvalidReason path}''
) 0 subpaths;
/*
/**
Split [a subpath](#function-library-lib.path.subpath.isValid) into its path component strings.
Throw an error if the subpath isn't valid.
Note that the returned path components are also [valid subpath strings](#function-library-lib.path.subpath.isValid), though they are intentionally not [normalised](#function-library-lib.path.subpath.normalise).
@@ -548,18 +664,34 @@ in
subpath.join (subpath.components s) == subpath.normalise s
Type:
subpath.components :: String -> [ String ]
# Inputs
Example:
subpath.components "."
=> [ ]
`subpath`
subpath.components "./foo//bar/./baz/"
=> [ "foo" "bar" "baz" ]
: The subpath string to split into components
subpath.components "/foo"
=> <error>
# Type
```
subpath.components :: String -> [ String ]
```
# Examples
:::{.example}
## `subpath.components` usage example
```nix
subpath.components "."
=> [ ]
subpath.components "./foo//bar/./baz/"
=> [ "foo" "bar" "baz" ]
subpath.components "/foo"
=> <error>
```
:::
*/
subpath.components =
# The subpath string to split into components
@@ -569,7 +701,7 @@ in
${subpathInvalidReason subpath}'';
splitRelPath subpath;
/*
/**
Normalise a subpath. Throw an error if the subpath isn't [valid](#function-library-lib.path.subpath.isValid).
- Limit repeating `/` to a single one.
@@ -602,45 +734,61 @@ in
builtins.tryEval (subpath.normalise p)).success == subpath.isValid p
Type:
subpath.normalise :: String -> String
# Inputs
Example:
# limit repeating `/` to a single one
subpath.normalise "foo//bar"
=> "./foo/bar"
`subpath`
# remove redundant `.` components
subpath.normalise "foo/./bar"
=> "./foo/bar"
: The subpath string to normalise
# add leading `./`
subpath.normalise "foo/bar"
=> "./foo/bar"
# Type
# remove trailing `/`
subpath.normalise "foo/bar/"
=> "./foo/bar"
```
subpath.normalise :: String -> String
```
# remove trailing `/.`
subpath.normalise "foo/bar/."
=> "./foo/bar"
# Examples
:::{.example}
## `subpath.normalise` usage example
# Return the current directory as `./.`
subpath.normalise "."
=> "./."
```nix
# limit repeating `/` to a single one
subpath.normalise "foo//bar"
=> "./foo/bar"
# error on `..` path components
subpath.normalise "foo/../bar"
=> <error>
# remove redundant `.` components
subpath.normalise "foo/./bar"
=> "./foo/bar"
# error on empty string
subpath.normalise ""
=> <error>
# add leading `./`
subpath.normalise "foo/bar"
=> "./foo/bar"
# error on absolute path
subpath.normalise "/foo"
=> <error>
# remove trailing `/`
subpath.normalise "foo/bar/"
=> "./foo/bar"
# remove trailing `/.`
subpath.normalise "foo/bar/."
=> "./foo/bar"
# Return the current directory as `./.`
subpath.normalise "."
=> "./."
# error on `..` path components
subpath.normalise "foo/../bar"
=> <error>
# error on empty string
subpath.normalise ""
=> <error>
# error on absolute path
subpath.normalise "/foo"
=> <error>
```
:::
*/
subpath.normalise =
# The subpath string to normalise
+120 -27
View File
@@ -18,10 +18,20 @@ let
pathIsRegularFile
;
/*
/**
A basic filter for `cleanSourceWith` that removes
directories of version control system, backup files (*~)
and some generated files.
# Inputs
`name`
: 1\. Function argument
`type`
: 2\. Function argument
*/
cleanSourceFilter =
name: type:
@@ -52,11 +62,24 @@ let
(type == "unknown")
);
/*
/**
Filters a source tree removing version control files and directories using cleanSourceFilter.
Example:
cleanSource ./.
# Inputs
`src`
: 1\. Function argument
# Examples
:::{.example}
## `cleanSource` usage example
```nix
cleanSource ./.
```
:::
*/
cleanSource =
src:
@@ -65,23 +88,30 @@ let
inherit src;
};
/*
/**
Like `builtins.filterSource`, except it will compose with itself,
allowing you to chain multiple calls together without any
intermediate copies being put in the nix store.
Example:
lib.cleanSourceWith {
filter = f;
src = lib.cleanSourceWith {
filter = g;
src = ./.;
};
}
# Succeeds!
# Examples
:::{.example}
## `cleanSourceWith` usage example
builtins.filterSource f (builtins.filterSource g ./.)
# Fails!
```nix
lib.cleanSourceWith {
filter = f;
src = lib.cleanSourceWith {
filter = g;
src = ./.;
};
}
# Succeeds!
builtins.filterSource f (builtins.filterSource g ./.)
# Fails!
```
:::
*/
cleanSourceWith =
{
@@ -107,10 +137,20 @@ let
name = if name != null then name else orig.name;
};
/*
/**
Add logging to a source, for troubleshooting the filtering behavior.
Type:
sources.trace :: sourceLike -> Source
# Inputs
`src`
: Source to debug. The returned source will behave like this source, but also log its filter invocations.
# Type
```
sources.trace :: sourceLike -> Source
```
*/
trace =
# Source to debug. The returned source will behave like this source, but also log its filter invocations.
@@ -133,10 +173,28 @@ let
satisfiesSubpathInvariant = src ? satisfiesSubpathInvariant && src.satisfiesSubpathInvariant;
};
/*
/**
Filter sources by a list of regular expressions.
Example: src = sourceByRegex ./my-subproject [".*\.py$" "^database.sql$"]
# Inputs
`src`
: 1\. Function argument
`regexes`
: 2\. Function argument
# Examples
:::{.example}
## `sourceByRegex` usage example
```nix
src = sourceByRegex ./my-subproject [".*\.py$" "^database.sql$"]
```
:::
*/
sourceByRegex =
src: regexes:
@@ -155,16 +213,37 @@ let
inherit src;
};
/*
/**
Get all files ending with the specified suffices from the given
source directory or its descendants, omitting files that do not match
any suffix. The result of the example below will include files like
`./dir/module.c` and `./dir/subdir/doc.xml` if present.
Type: sourceLike -> [String] -> Source
# Inputs
Example:
sourceFilesBySuffices ./. [ ".xml" ".c" ]
`src`
: Path or source containing the files to be returned
`exts`
: A list of file suffix strings
# Type
```
sourceLike -> [String] -> Source
```
# Examples
:::{.example}
## `sourceFilesBySuffices` usage example
```nix
sourceFilesBySuffices ./. [ ".xml" ".c" ]
```
:::
*/
sourceFilesBySuffices =
# Path or source containing the files to be returned
@@ -183,10 +262,24 @@ let
pathIsGitRepo = path: (_commitIdFromGitRepoOrError path) ? value;
/*
/**
Get the commit id of a git repo.
Example: commitIdFromGitRepo <nixpkgs/.git>
# Inputs
`path`
: 1\. Function argument
# Examples
:::{.example}
## `commitIdFromGitRepo` usage example
```nix
commitIdFromGitRepo <nixpkgs/.git>
```
:::
*/
commitIdFromGitRepo =
path:
+31 -31
View File
@@ -1,44 +1,44 @@
{ lib }:
/*
Usage:
/**
Usage:
You define you custom builder script by adding all build steps to a list.
for example:
builder = writeScript "fsg-4.4-builder"
(textClosure [doUnpack addInputs preBuild doMake installPhase doForceShare]);
You define you custom builder script by adding all build steps to a list.
for example:
builder = writeScript "fsg-4.4-builder"
(textClosure [doUnpack addInputs preBuild doMake installPhase doForceShare]);
a step is defined by noDepEntry, fullDepEntry or packEntry.
To ensure that prerequisite are met those are added before the task itself by
textClosureDupList. Duplicated items are removed again.
a step is defined by noDepEntry, fullDepEntry or packEntry.
To ensure that prerequisite are met those are added before the task itself by
textClosureDupList. Duplicated items are removed again.
See trace/nixpkgs/trunk/pkgs/top-level/builder-defs.nix for some predefined build steps
See trace/nixpkgs/trunk/pkgs/top-level/builder-defs.nix for some predefined build steps
Attention:
Attention:
let
pkgs = (import <nixpkgs>) {};
in let
inherit (pkgs.stringsWithDeps) fullDepEntry packEntry noDepEntry textClosureMap;
inherit (pkgs.lib) id;
let
pkgs = (import <nixpkgs>) {};
in let
inherit (pkgs.stringsWithDeps) fullDepEntry packEntry noDepEntry textClosureMap;
inherit (pkgs.lib) id;
nameA = noDepEntry "Text a";
nameB = fullDepEntry "Text b" ["nameA"];
nameC = fullDepEntry "Text c" ["nameA"];
nameA = noDepEntry "Text a";
nameB = fullDepEntry "Text b" ["nameA"];
nameC = fullDepEntry "Text c" ["nameA"];
stages = {
nameHeader = noDepEntry "#! /bin/sh \n";
inherit nameA nameB nameC;
};
in
textClosureMap id stages
[ "nameHeader" "nameA" "nameB" "nameC"
nameC # <- added twice. add a dep entry if you know that it will be added once only [1]
"nameB" # <- this will not be added again because the attr name (reference) is used
]
stages = {
nameHeader = noDepEntry "#! /bin/sh \n";
inherit nameA nameB nameC;
};
in
textClosureMap id stages
[ "nameHeader" "nameA" "nameB" "nameC"
nameC # <- added twice. add a dep entry if you know that it will be added once only [1]
"nameB" # <- this will not be added again because the attr name (reference) is used
]
# result: Str("#! /bin/sh \n\nText a\nText b\nText c\nText c",[])
# result: Str("#! /bin/sh \n\nText a\nText b\nText c\nText c",[])
[1] maybe this behaviour should be removed to keep things simple (?)
[1] maybe this behaviour should be removed to keep things simple (?)
*/
let
+36
View File
@@ -1424,6 +1424,42 @@ rec {
*/
toUpper = replaceStrings lowerChars upperChars;
/**
Converts the first character of a string `s` to upper-case.
# Inputs
`str`
: The string to convert to sentence case.
# Type
```
toSentenceCase :: string -> string
```
# Examples
:::{.example}
## `lib.strings.toSentenceCase` usage example
```nix
toSentenceCase "home"
=> "Home"
```
:::
*/
toSentenceCase = str:
lib.throwIfNot (isString str)
"toSentenceCase does only accepts string values, but got ${typeOf str}"
(
let
firstChar = substring 0 1 str;
rest = substring 1 (stringLength str) str;
in
addContextFrom str (toUpper firstChar + toLower rest)
);
/**
Appends string context from string like object `src` to `target`.
+2
View File
@@ -29,6 +29,7 @@ rec {
alderlake = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "fma" ];
sapphirerapids = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ];
emeraldrapids = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ];
sierraforest = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "fma" ];
# x86_64 AMD
btver1 = [ "sse3" "ssse3" "sse4_1" "sse4_2" ];
btver2 = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" ];
@@ -82,6 +83,7 @@ rec {
# CX16 does not exist on alderlake, while it does on nearly all other intel CPUs
alderlake = [ ];
sierraforest = [ "alderlake" ] ++ inferiors.alderlake;
# x86_64 AMD
# TODO: fill this (need testing)
+9
View File
@@ -678,6 +678,15 @@ runTests {
("%20%3F%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%09%3A%2F%40%24%27%28%29%2A%2C%3B" == strings.escapeURL " ?&=#+%!<>#\"{}|\\^[]`\t:/@$'()*,;")
];
testToSentenceCase = {
expr = strings.toSentenceCase "hello world";
expected = "Hello world";
};
testToSentenceCasePath = testingThrow (
strings.toSentenceCase ./.
);
testToInt = testAllTrue [
# Naive
(123 == toInt "123")
+40
View File
@@ -398,6 +398,10 @@ checkConfigError 'infinite recursion encountered' config.nonLazyResult ./lazy-at
checkConfigOutput '^"mergedName.<id>.nested"$' config.result ./name-merge-attrsWith-1.nix
checkConfigError 'The option .mergedName. in .*\.nix. is already declared in .*\.nix' config.mergedName ./name-merge-attrsWith-2.nix
# Test the attrsOf functor.wrapped warning
# shellcheck disable=2016
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `type.functor.wrapped` attribute of the option `mergedLazyLazy` is accessed, use `type.nestedTypes.elemType` instead.' options.mergedLazyLazy.type.functor.wrapped ./lazy-attrsWith.nix
# Even with multiple assignments, a type error should be thrown if any of them aren't valid
checkConfigError 'A definition for option .* is not of type .*' \
config.value ./declare-int-unsigned-value.nix ./define-value-list.nix ./define-value-int-positive.nix
@@ -586,6 +590,42 @@ checkConfigOutput '^38|27$' options.submoduleLine38.declarationPositions.1.line
# nested options work
checkConfigOutput '^34$' options.nested.nestedLine34.declarationPositions.0.line ./declaration-positions.nix
# types.pathWith { inStore = true; }
checkConfigOutput '".*/store/0lz9p8xhf89kb1c1kk6jxrzskaiygnlh-bash-5.2-p15.drv"' config.pathInStore.ok1 ./pathWith.nix
checkConfigOutput '".*/store/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15"' config.pathInStore.ok2 ./pathWith.nix
checkConfigOutput '".*/store/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15/bin/bash"' config.pathInStore.ok3 ./pathWith.nix
checkConfigError 'A definition for option .* is not of type .path in the Nix store.. Definition values:\n\s*- In .*: ""' config.pathInStore.bad1 ./pathWith.nix
checkConfigError 'A definition for option .* is not of type .path in the Nix store.. Definition values:\n\s*- In .*: ".*/store"' config.pathInStore.bad2 ./pathWith.nix
checkConfigError 'A definition for option .* is not of type .path in the Nix store.. Definition values:\n\s*- In .*: ".*/store/"' config.pathInStore.bad3 ./pathWith.nix
checkConfigError 'A definition for option .* is not of type .path in the Nix store.. Definition values:\n\s*- In .*: ".*/store/.links"' config.pathInStore.bad4 ./pathWith.nix
checkConfigError 'A definition for option .* is not of type .path in the Nix store.. Definition values:\n\s*- In .*: "/foo/bar"' config.pathInStore.bad5 ./pathWith.nix
# types.pathWith { inStore = false; }
checkConfigOutput '"/foo/bar"' config.pathNotInStore.ok1 ./pathWith.nix
checkConfigOutput '".*/store"' config.pathNotInStore.ok2 ./pathWith.nix
checkConfigOutput '".*/store/"' config.pathNotInStore.ok3 ./pathWith.nix
checkConfigOutput '""' config.pathNotInStore.ok4 ./pathWith.nix
checkConfigOutput '".*/store/.links"' config.pathNotInStore.ok5 ./pathWith.nix
checkConfigError 'A definition for option .* is not of type .path not in the Nix store.. Definition values:\n\s*- In .*: ".*/0lz9p8xhf89kb1c1kk6jxrzskaiygnlh-bash-5.2-p15.drv"' config.pathNotInStore.bad1 ./pathWith.nix
checkConfigError 'A definition for option .* is not of type .path not in the Nix store.. Definition values:\n\s*- In .*: ".*/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15"' config.pathNotInStore.bad2 ./pathWith.nix
checkConfigError 'A definition for option .* is not of type .path not in the Nix store.. Definition values:\n\s*- In .*: ".*/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15/bin/bash"' config.pathNotInStore.bad3 ./pathWith.nix
checkConfigError 'A definition for option .* is not of type .path not in the Nix store.. Definition values:\n\s*- In .*: .*/pathWith.nix' config.pathNotInStore.bad4 ./pathWith.nix
# types.pathWith { }
checkConfigOutput '"/this/is/absolute"' config.anyPath.ok1 ./pathWith.nix
checkConfigOutput '"./this/is/relative"' config.anyPath.ok2 ./pathWith.nix
checkConfigError 'A definition for option .anyPath.bad1. is not of type .path.' config.anyPath.bad1 ./pathWith.nix
# types.pathWith { absolute = true; }
checkConfigOutput '"/this/is/absolute"' config.absolutePathNotInStore.ok1 ./pathWith.nix
checkConfigError 'A definition for option .absolutePathNotInStore.bad1. is not of type .absolute path not in the Nix store.' config.absolutePathNotInStore.bad1 ./pathWith.nix
checkConfigError 'A definition for option .absolutePathNotInStore.bad2. is not of type .absolute path not in the Nix store.' config.absolutePathNotInStore.bad2 ./pathWith.nix
# types.pathWith failed type merge
checkConfigError 'The option .conflictingPathOptionType. in .*/pathWith.nix. is already declared in .*/pathWith.nix' config.conflictingPathOptionType ./pathWith.nix
# types.pathWith { inStore = true; absolute = false; }
checkConfigError 'In pathWith, inStore means the path must be absolute' config.impossiblePathOptionType ./pathWith.nix
cat <<EOF
====== module tests ======
+88
View File
@@ -0,0 +1,88 @@
{ lib, ... }:
let
inherit (builtins)
storeDir
;
inherit (lib)
types
mkOption
;
in
{
imports = [
{
options = {
pathInStore = mkOption { type = types.lazyAttrsOf (types.pathWith { inStore = true; }); };
pathNotInStore = mkOption { type = types.lazyAttrsOf (types.pathWith { inStore = false; }); };
anyPath = mkOption { type = types.lazyAttrsOf (types.pathWith { }); };
absolutePathNotInStore = mkOption {
type = types.lazyAttrsOf (
types.pathWith {
inStore = false;
absolute = true;
}
);
};
# This conflicts with `conflictingPathOptionType` below.
conflictingPathOptionType = mkOption { type = types.pathWith { absolute = true; }; };
# This doesn't make sense: the only way to have something be `inStore`
# is to have an absolute path.
impossiblePathOptionType = mkOption {
type = types.pathWith {
inStore = true;
absolute = false;
};
};
};
}
{
options = {
# This should merge cleanly with `pathNotInStore` above.
pathNotInStore = mkOption {
type = types.lazyAttrsOf (
types.pathWith {
inStore = false;
absolute = null;
}
);
};
# This conflicts with `conflictingPathOptionType` above.
conflictingPathOptionType = mkOption { type = types.pathWith { absolute = false; }; };
};
}
];
pathInStore.ok1 = "${storeDir}/0lz9p8xhf89kb1c1kk6jxrzskaiygnlh-bash-5.2-p15.drv";
pathInStore.ok2 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15";
pathInStore.ok3 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15/bin/bash";
pathInStore.bad1 = "";
pathInStore.bad2 = "${storeDir}";
pathInStore.bad3 = "${storeDir}/";
pathInStore.bad4 = "${storeDir}/.links"; # technically true, but not reasonable
pathInStore.bad5 = "/foo/bar";
pathNotInStore.ok1 = "/foo/bar";
pathNotInStore.ok2 = "${storeDir}"; # strange, but consistent with `pathInStore` above
pathNotInStore.ok3 = "${storeDir}/"; # also strange, but also consistent
pathNotInStore.ok4 = "";
pathNotInStore.ok5 = "${storeDir}/.links"; # strange, but consistent with `pathInStore` above
pathNotInStore.bad1 = "${storeDir}/0lz9p8xhf89kb1c1kk6jxrzskaiygnlh-bash-5.2-p15.drv";
pathNotInStore.bad2 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15";
pathNotInStore.bad3 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15/bin/bash";
pathNotInStore.bad4 = ./pathWith.nix;
anyPath.ok1 = "/this/is/absolute";
anyPath.ok2 = "./this/is/relative";
anyPath.bad1 = 42;
absolutePathNotInStore.ok1 = "/this/is/absolute";
absolutePathNotInStore.bad1 = "./this/is/relative";
absolutePathNotInStore.bad2 = "${storeDir}/0fb3ykw9r5hpayd05sr0cizwadzq1d8q-bash-5.2-p15";
conflictingPathOptionType = "/foo/bar";
impossiblePathOptionType = "/foo/bar";
}
+38 -11
View File
@@ -566,21 +566,48 @@ rec {
})
(x: (x._type or null) == "pkgs");
path = mkOptionType {
name = "path";
descriptionClass = "noun";
check = x: isStringLike x && builtins.substring 0 1 (toString x) == "/";
merge = mergeEqualOption;
path = pathWith {
absolute = true;
};
pathInStore = mkOptionType {
name = "pathInStore";
description = "path in the Nix store";
descriptionClass = "noun";
check = x: isStringLike x && builtins.match "${builtins.storeDir}/[^.].*" (toString x) != null;
merge = mergeEqualOption;
pathInStore = pathWith {
inStore = true;
};
pathWith = {
inStore ? null,
absolute ? null,
}:
throwIf (inStore != null && absolute != null && inStore && !absolute) "In pathWith, inStore means the path must be absolute" mkOptionType {
name = "path";
description = (
(if absolute == null then "" else (if absolute then "absolute " else "relative ")) +
"path" +
(if inStore == null then "" else (if inStore then " in the Nix store" else " not in the Nix store"))
);
descriptionClass = "noun";
merge = mergeEqualOption;
functor = defaultFunctor "path" // {
type = pathWith;
payload = {inherit inStore absolute; };
binOp = lhs: rhs: if lhs == rhs then lhs else null;
};
check = x:
let
isInStore = builtins.match "${builtins.storeDir}/[^.].*" (toString x) != null;
isAbsolute = builtins.substring 0 1 (toString x) == "/";
isExpectedType = (
if inStore == null || inStore then
isStringLike x
else
isString x # Do not allow a true path, which could be copied to the store later on.
);
in
isExpectedType && (inStore == null || inStore == isInStore) && (absolute == null || absolute == isAbsolute);
};
listOf = elemType: mkOptionType rec {
name = "listOf";
description = "list of ${optionDescriptionPhrase (class: class == "noun" || class == "composite") elemType}";
+104 -28
View File
@@ -3,62 +3,138 @@
rec {
/*
/**
Break a version string into its component parts.
Example:
splitVersion "1.2.3"
=> ["1" "2" "3"]
# Examples
:::{.example}
## `splitVersion` usage example
```nix
splitVersion "1.2.3"
=> ["1" "2" "3"]
```
:::
*/
splitVersion = builtins.splitVersion;
/*
/**
Get the major version string from a string.
Example:
major "1.2.3"
=> "1"
# Inputs
`v`
: 1\. Function argument
# Examples
:::{.example}
## `major` usage example
```nix
major "1.2.3"
=> "1"
```
:::
*/
major = v: builtins.elemAt (splitVersion v) 0;
/*
/**
Get the minor version string from a string.
Example:
minor "1.2.3"
=> "2"
# Inputs
`v`
: 1\. Function argument
# Examples
:::{.example}
## `minor` usage example
```nix
minor "1.2.3"
=> "2"
```
:::
*/
minor = v: builtins.elemAt (splitVersion v) 1;
/*
/**
Get the patch version string from a string.
Example:
patch "1.2.3"
=> "3"
# Inputs
`v`
: 1\. Function argument
# Examples
:::{.example}
## `patch` usage example
```nix
patch "1.2.3"
=> "3"
```
:::
*/
patch = v: builtins.elemAt (splitVersion v) 2;
/*
/**
Get string of the first two parts (major and minor)
of a version string.
Example:
majorMinor "1.2.3"
=> "1.2"
# Inputs
`v`
: 1\. Function argument
# Examples
:::{.example}
## `majorMinor` usage example
```nix
majorMinor "1.2.3"
=> "1.2"
```
:::
*/
majorMinor = v: builtins.concatStringsSep "." (lib.take 2 (splitVersion v));
/*
/**
Pad a version string with zeros to match the given number of components.
Example:
pad 3 "1.2"
=> "1.2.0"
pad 3 "1.3-rc1"
=> "1.3.0-rc1"
pad 3 "1.2.3.4"
=> "1.2.3"
# Inputs
`n`
: 1\. Function argument
`version`
: 2\. Function argument
# Examples
:::{.example}
## `pad` usage example
```nix
pad 3 "1.2"
=> "1.2.0"
pad 3 "1.3-rc1"
=> "1.3.0-rc1"
pad 3 "1.2.3.4"
=> "1.2.3"
```
:::
*/
pad =
n: version:
+83
View File
@@ -1860,6 +1860,12 @@
githubId = 13347712;
name = "Leo Shchurov";
};
ardubev16 = {
email = "lorenzobevilacqua02@gmail.com";
github = "ardubev16";
githubId = 43483037;
name = "Lorenzo Bevilacqua";
};
ardumont = {
email = "eniotna.t@gmail.com";
github = "ardumont";
@@ -2369,6 +2375,12 @@
githubId = 97070581;
name = "averagebit";
};
averdow = {
email = "aaron@verdow.com";
github = "AaronVerDow";
githubId = 2530548;
name = "Aaron VerDow";
};
averelld = {
email = "averell+nixos@rxd4.com";
github = "averelld";
@@ -10817,6 +10829,13 @@
githubId = 42114389;
name = "Jerry Starke";
};
jervw = {
email = "jervw@pm.me";
github = "jervw";
githubId = 53620688;
name = "Jere Vuola";
keys = [ { fingerprint = "56C2 5B5B 2075 6352 B4B0 E17E F188 3717 47DA 5895"; } ];
};
jeschli = {
email = "jeschli@gmail.com";
github = "0mbi";
@@ -11477,6 +11496,12 @@
github = "josephsurin";
githubId = 14977484;
};
josh = {
name = "Joshua Peek";
email = "josh@joshpeek.com";
github = "josh";
githubId = 137;
};
joshainglis = {
name = "Josha Inglis";
email = "joshainglis@gmail.com";
@@ -11723,6 +11748,14 @@
githubId = 79042825;
name = "Jan Kremer";
};
juli0604 = {
name = "Julian Kuhn";
email = "juliankuhn06@gmail.com";
matrix = "@julian:matrix.epiccraft-mc.de";
github = "juli0604";
githubId = 62934740;
keys = [ { fingerprint = "E9C6 44C7 F6AA A865 4CB9 2723 22C8 B0CE B9AC 4AFF"; } ];
};
JulianFP = {
name = "Julian Partanen";
github = "JulianFP";
@@ -14009,6 +14042,14 @@
github = "mac-chaffee";
githubId = 7581860;
};
macronova = {
name = "Sicheng Pan";
email = "trivial@invariantspace.com";
matrix = "@macronova:invariantspace.com";
github = "Sicheng-Pan";
githubId = 60079945;
keys = [ { fingerprint = "7590 C9DD E19D 4497 9EE9 0B14 CE96 9670 FB4B 4A56"; } ];
};
madjar = {
email = "georges.dubus@compiletoi.net";
github = "madjar";
@@ -14574,6 +14615,12 @@
githubId = 279868;
name = "Matti Kariluoma";
};
mattkang = {
email = "wavy-wisdom-volley@duck.com";
github = "mattkang";
githubId = 2027430;
name = "Matthew Kang";
};
mattpolzin = {
email = "matt.polzin@gmail.com";
github = "mattpolzin";
@@ -16380,6 +16427,12 @@
githubId = 43587167;
name = "Nikita Tikhonov";
};
nekowinston = {
email = "hey@winston.sh";
github = "nekowinston";
githubId = 79978224;
name = "winston";
};
nelsonjeppesen = {
email = "nix@jeppesen.io";
github = "NelsonJeppesen";
@@ -20094,6 +20147,12 @@
githubId = 69053978;
name = "rogarb";
};
RoGreat = {
email = "roguegreat@gmail.com";
github = "RoGreat";
githubId = 64620440;
name = "RoGreat";
};
rohanssrao = {
email = "rohanssrao@gmail.com";
github = "rohanssrao";
@@ -21397,6 +21456,12 @@
github = "shikanime";
githubId = 22115108;
};
shimun = {
email = "shimun@shimun.net";
name = "shimun";
github = "shimunn";
githubId = 41011289;
};
shiphan = {
email = "timlin940511@gmail.com";
name = "Shiphan";
@@ -22563,6 +22628,12 @@
githubId = 98333944;
name = "Sven Over";
};
Svenum = {
email = "s.ziegler@holypenguin.net";
github = "Svenum";
githubId = 43136984;
name = "Sven Ziegler";
};
svrana = {
email = "shaw@vranix.com";
github = "svrana";
@@ -23466,6 +23537,12 @@
github = "tie";
githubId = 14792994;
};
tiferrei = {
name = "Tiago Ferreira";
email = "me@tiferrei.com";
github = "tiferrei";
githubId = 8849915;
};
tilcreator = {
name = "TilCreator";
email = "contact.nixos@tc-j.de";
@@ -26116,6 +26193,12 @@
github = "zmitchell";
githubId = 10246891;
};
ZMon3y = {
name = "Matt Szafir";
email = "mattszafir+nix@gmail.com";
github = "ZMon3y";
githubId = 9386488;
};
znaniye = {
email = "zn4niye@proton.me";
github = "znaniye";
+8 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages(ps: [ ps.beautifulsoup4 ps.click ps.httpx ps.jinja2 ps.pyyaml ])"
#!nix-shell -i python3 -p "python3.withPackages(ps: [ ps.beautifulsoup4 ps.click ps.httpx ps.jinja2 ps.packaging ps.pyyaml ])"
import base64
import binascii
import json
@@ -11,6 +11,7 @@ import bs4
import click
import httpx
import jinja2
import packaging.version as v
import utils
@@ -104,6 +105,12 @@ def main(set: str, version: str, nixpkgs: pathlib.Path, sources_url: Optional[st
hash = client.get(url + ".sha256").text.split(" ", maxsplit=1)[0]
assert hash
if existing := results.get(project_name):
old_version = existing["version"]
if v.parse(old_version) > v.parse(version):
print(f"{project_name} {old_version} is newer than {version}, skipping...")
continue
results[project_name] = {
"version": version,
"url": "mirror://kde" + urlparse(url).path,
@@ -23,15 +23,36 @@ merging is handled.
`types.path`
: A filesystem path is anything that starts with a slash when
coerced to a string. Even if derivations can be considered as
paths, the more specific `types.package` should be preferred.
: A filesystem path that starts with a slash. Even if derivations can be
considered as paths, the more specific `types.package` should be preferred.
`types.pathInStore`
: A path that is contained in the Nix store. This can be a top-level store
path like `pkgs.hello` or a descendant like `"${pkgs.hello}/bin/hello"`.
`types.pathWith` { *`inStore`* ? `null`, *`absolute`* ? `null` }
: A filesystem path. Either a string or something that can be coerced
to a string.
**Parameters**
`inStore` (`Boolean` or `null`, default `null`)
: Whether the path must be in the store (`true`), must not be in the store
(`false`), or it doesn't matter (`null`)
`absolute` (`Boolean` or `null`, default `null`)
: Whether the path must be absolute (`true`), must not be absolute
(`false`), or it doesn't matter (`null`)
**Behavior**
- `pathWith { inStore = true; }` is equivalent to `pathInStore`
- `pathWith { absolute = true; }` is equivalent to `path`
- `pathWith { inStore = false; absolute = true; }` requires an absolute
path that is not in the store. Useful for password files that shouldn't be
leaked into the store.
`types.package`
: A top-level store path. This can be an attribute set pointing
@@ -398,6 +398,9 @@ Use the following commands:
[](#ch-options). A minimal example is shown in
[Example: NixOS Configuration](#ex-config).
This command accepts an optional `--flake` option, to also generate a
`flake.nix` file, if you want to set up a flake-based configuration.
The command `nixos-generate-config` can generate an initial
configuration file for you:
@@ -490,6 +493,14 @@ Use the following commands:
from the NixOS binary cache), you can re-run `nixos-install` after
fixing your `configuration.nix`.
If you opted for a flake-based configuration, you will need to pass the
`--flake` here as well and specify the name of the configuration as used in
the `flake.nix` file. For the default generated flake, this is `nixos`.
```ShellSession
# nixos-install --flake 'path/to/flake.nix#nixos'
```
As the last step, `nixos-install` will ask you to set the password
for the `root` user, e.g.
@@ -33,6 +33,8 @@
- `nixos-rebuild-ng`, a full rewrite of `nixos-rebuild` in Python, is available for testing. You can enable it by setting [system.rebuild.enableNg](options.html#opt-system.rebuild.enableNg) in your configuration (this will replace the old `nixos-rebuild`), or by adding `nixos-rebuild-ng` to your `environment.systemPackages` (in this case, it will live side-by-side with `nixos-rebuild` as `nixos-rebuild-ng`). It is expected that the next major version of NixOS (25.11) will enable `system.rebuild.enableNg` by default.
- The `nixos-generate-config` command now supports a optional `--flake` option, which will generate a flake.nix file alongside the `configuration.nix` and `hardware-configuration.nix`, providing an easy instroduction into flake-based system configurations.
- A `nixos-rebuild build-image` sub-command has been added.
It allows users to build platform-specific (disk) images from their NixOS configurations. `nixos-rebuild build-image` works similar to the popular [nix-community/nixos-generators](https://github.com/nix-community/nixos-generators) project. See new [section on image building in the nixpkgs manual](https://nixos.org/manual/nixpkgs/unstable/#sec-image-nixos-rebuild-build-image). It is also available for `nixos-rebuild-ng`.
@@ -70,6 +72,8 @@
- [Homer](https://homer-demo.netlify.app/), a very simple static homepage for your server. Available as [services.homer](options.html#opt-services.homer).
- [Ghidra](https://ghidra-sre.org/), a software reverse engineering (SRE) suite of tools. Available as [programs.ghidra](options.html#opt-programs.ghidra).
- [Omnom](https://github.com/asciimoo/omnom), a webpage bookmarking and snapshotting service. Available as [services.omnom](options.html#opt-services.omnom.enable).
- [Yggdrasil-Jumper](https://github.com/one-d-wide/yggdrasil-jumper) is an independent project that aims to transparently reduce latency of a connection over Yggdrasil network, utilizing NAT traversal to automatically bypass intermediary nodes.
@@ -233,6 +237,12 @@
- `zammad` has had its support for MySQL removed, since it was never working correctly and is now deprecated upstream. Check the [migration guide](https://docs.zammad.org/en/latest/appendix/migrate-to-postgresql.html) for how to convert your database to PostgreSQL.
- `mepo` was updated to version 1.3.3. The manual page was removed,
a new JSON API was introduced to replace Mepolang for configuration,
and a few default key bindings were changed.
See the [1.3.0 changelog](https://git.sr.ht/~mil/mepo/refs/1.3.0)
for more details.
- The `earlyoom` service is now using upstream systemd service, which enables
hardening and filesystem isolation by default. If you need filesystem write
access or want to access home directory via `killHook`, hardening setting can
@@ -474,6 +484,8 @@
- `networking.wireguard` now has an optional networkd backend. It is enabled by default when `networking.useNetworkd` is enabled, and it can be enabled alongside scripted networking with `networking.wireguard.useNetworkd`. Some `networking.wireguard` options have slightly different behavior with the networkd and script-based backends, documented in each option.
- The `stackclashprotection` hardening flag has been enabled by default on compilers that support it.
- `services.rss-bridge` now has a `package` option as well as support for `caddy` as reverse proxy.
- `services.avahi.ipv6` now defaults to true.
@@ -484,6 +496,8 @@
- `services.kmonad` now creates a determinate symlink (in `/dev/input/by-id/`) to each of KMonad virtual devices.
- `services.gitea` now supports CAPTCHA usage through the `services.gitea.captcha` variable.
- `bind.cacheNetworks` now only controls access for recursive queries, where it previously controlled access for all queries.
- [`services.mongodb.enableAuth`](#opt-services.mongodb.enableAuth) now uses the newer [mongosh](https://github.com/mongodb-js/mongosh) shell instead of the legacy shell to configure the initial superuser. You can configure the mongosh package to use through the [`services.mongodb.mongoshPackage`](#opt-services.mongodb.mongoshPackage) option.
@@ -16,8 +16,7 @@
# copy the config for nixos-rebuild
system.activationScripts.config =
let
config = pkgs.substituteAll {
src = ./incus-container-image-inner.nix;
config = pkgs.replaceVars ./incus-container-image-inner.nix {
stateVersion = lib.trivial.release;
};
in
@@ -16,8 +16,7 @@
# copy the config for nixos-rebuild
system.activationScripts.config =
let
config = pkgs.substituteAll {
src = ./incus-virtual-machine-image-inner.nix;
config = pkgs.replaceVars ./incus-virtual-machine-image-inner.nix {
stateVersion = lib.trivial.release;
};
in
@@ -18,8 +18,7 @@
# copy the config for nixos-rebuild
system.activationScripts.config =
let
config = pkgs.substituteAll {
src = ./lxd-container-image-inner.nix;
config = pkgs.replaceVars ./lxd-container-image-inner.nix {
stateVersion = lib.trivial.release;
};
in
@@ -18,8 +18,7 @@
# copy the config for nixos-rebuild
system.activationScripts.config =
let
config = pkgs.substituteAll {
src = ./lxd-virtual-machine-image-inner.nix;
config = pkgs.replaceVars ./lxd-virtual-machine-image-inner.nix {
stateVersion = lib.trivial.release;
};
in
+4 -10
View File
@@ -128,16 +128,6 @@ in
'');
}
(lib.mkIf (!cfg.enable) {
systemd.services = {
"serial-getty@ttyS0".enable = false;
"serial-getty@hvc0".enable = false;
"getty@tty1".enable = false;
"autovt@".enable = false;
systemd-vconsole-setup.enable = false;
};
})
(lib.mkIf cfg.enable (lib.mkMerge [
{ environment.systemPackages = [ pkgs.kbd ];
@@ -178,6 +168,10 @@ in
"${cfg.keyMap}"
];
systemd.additionalUpstreamSystemUnits = [
"systemd-vconsole-setup.service"
];
systemd.services.reload-systemd-vconsole-setup =
{ description = "Reset console on configuration changes";
wantedBy = [ "multi-user.target" ];
+1 -1
View File
@@ -45,7 +45,7 @@ let
sd-card = {
imports =
let
module = ../. + "/installer/sd-card/sd-image-${pkgs.targetPlatform.linuxArch}.nix";
module = ../. + "/installer/sd-card/sd-image-${pkgs.targetPlatform.qemuArch}.nix";
in
if builtins.pathExists module then [ module ] else throw "The module ${module} does not exist.";
};
+1 -5
View File
@@ -832,11 +832,7 @@ in
{ source = config.isoImage.splashImage;
target = "/isolinux/background.png";
}
{ source = pkgs.substituteAll {
name = "isolinux.cfg";
src = pkgs.writeText "isolinux.cfg-in" isolinuxCfg;
bootRoot = "/boot";
};
{ source = isolinuxCfg;
target = "/isolinux/isolinux.cfg";
}
{ source = "${pkgs.syslinux}/share/syslinux";
@@ -12,6 +12,7 @@
.Op Fl -force
.Op Fl -root Ar root
.Op Fl -dir Ar dir
.Op Fl -flake
.
.
.
@@ -68,7 +69,14 @@ instead of
.It Fl -force
Overwrite
.Pa /etc/nixos/configuration.nix
if it already exists.
(and
.Pa /etc/nixos/flake.nix
if --flake is passed) if already present.
.
.It Fl -flake
Also generate
.Pa /etc/nixos/flake.nix Ns
\&.
.
.It Fl -no-filesystems
Omit everything concerning file systems and swap devices from the hardware configuration.
@@ -35,6 +35,7 @@ my $outDir = "/etc/nixos";
my $rootDir = ""; # = /
my $force = 0;
my $noFilesystems = 0;
my $flake = 0;
my $showHardwareConfig = 0;
for (my $n = 0; $n < scalar @ARGV; $n++) {
@@ -64,6 +65,9 @@ for (my $n = 0; $n < scalar @ARGV; $n++) {
elsif ($arg eq "--show-hardware-config") {
$showHardwareConfig = 1;
}
elsif ($arg eq "--flake") {
$flake = 1;
}
else {
die "$0: unrecognized argument $arg\n";
}
@@ -661,6 +665,19 @@ if ($showHardwareConfig) {
mkpath($outDir, 0, 0755);
write_file($fn, $hwConfig);
$fn = "$outDir/flake.nix";
if ($flake) {
if ($force || ! -e $fn) {
print STDERR "writing $fn...\n";
mkpath($outDir, 0, 0755);
write_file($fn, <<EOF);
@flake@
EOF
} else {
print STDERR "warning: not overwriting existing $fn\n";
}
}
# Generate a basic configuration.nix, unless one already exists.
$fn = "$outDir/configuration.nix";
if ($force || ! -e $fn) {
+39 -3
View File
@@ -1,7 +1,7 @@
# This module generates nixos-install, nixos-rebuild,
# nixos-generate-config, etc.
{ config, lib, pkgs, ... }:
{ config, lib, pkgs, options, ... }:
let
makeProg = args: pkgs.replaceVarsWith (args // {
@@ -23,7 +23,7 @@ let
hostPlatformSystem = pkgs.stdenv.hostPlatform.system;
detectvirt = "${config.systemd.package}/bin/systemd-detect-virt";
btrfs = "${pkgs.btrfs-progs}/bin/btrfs";
inherit (config.system.nixos-generate-config) configuration desktopConfiguration;
inherit (config.system.nixos-generate-config) configuration desktopConfiguration flake;
xserverEnabled = config.services.xserver.enable;
};
manPage = ./manpages/nixos-generate-config.8;
@@ -55,6 +55,24 @@ let
withReexec = true;
};
defaultFlakeTemplate = ''
{
inputs = {
# This is pointing to an unstable release.
# If you prefer a stable release instead, you can this to the latest number shown here: https://nixos.org/download
# i.e. nixos-24.11
# Use `nix flake update` to update the flake to the latest revision of the chosen release channel.
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = inputs\@{ self, nixpkgs, ... }: {
# NOTE: '${options.networking.hostName.default}' is the default hostname
nixosConfigurations.${options.networking.hostName.default} = nixpkgs.lib.nixosSystem {
modules = [ ./configuration.nix ];
};
};
}
'';
defaultConfigTemplate = ''
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page, on
@@ -176,6 +194,24 @@ let
in
{
options.system.nixos-generate-config = {
flake = lib.mkOption {
internal = true;
type = lib.types.str;
default = defaultFlakeTemplate;
description = ''
The NixOS module that `nixos-generate-config`
saves to `/etc/nixos/flake.nix` if --flake is set.
This is an internal option. No backward compatibility is guaranteed.
Use at your own risk!
Note that this string gets spliced into a Perl script. The perl
variable `$bootLoaderConfig` can be used to
splice in the boot loader configuration.
'';
};
configuration = lib.mkOption {
internal = true;
type = lib.types.str;
@@ -196,7 +232,7 @@ in
desktopConfiguration = lib.mkOption {
internal = true;
type = lib.types.listOf lib.types.lines;
default = [];
default = [ ];
description = ''
Text to preseed the desktop configuration that `nixos-generate-config`
saves to `/etc/nixos/configuration.nix`.
+4
View File
@@ -199,6 +199,7 @@
./programs/firefox.nix
./programs/firejail.nix
./programs/fish.nix
./programs/flashprog.nix
./programs/flashrom.nix
./programs/flexoptix-app.nix
./programs/foot
@@ -209,6 +210,7 @@
./programs/gamescope.nix
./programs/gdk-pixbuf.nix
./programs/geary.nix
./programs/ghidra.nix
./programs/git.nix
./programs/git-worktree-switcher.nix
./programs/gnome-disks.nix
@@ -956,6 +958,7 @@
./services/monitoring/opentelemetry-collector.nix
./services/monitoring/osquery.nix
./services/monitoring/parsedmarc.nix
./services/monitoring/prometheus/alertmanager-gotify-bridge.nix
./services/monitoring/prometheus/alertmanager-irc-relay.nix
./services/monitoring/prometheus/alertmanager-webhook-logger.nix
./services/monitoring/prometheus/alertmanager.nix
@@ -1607,6 +1610,7 @@
./services/web-servers/darkhttpd.nix
./services/web-servers/fcgiwrap.nix
./services/web-servers/garage.nix
./services/web-servers/h2o/default.nix
./services/web-servers/hitch/default.nix
./services/web-servers/jboss/default.nix
./services/web-servers/keter
+28
View File
@@ -0,0 +1,28 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.flashprog;
in
{
options.programs.flashprog = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Installs flashprog and configures udev rules for programmers
used by flashprog.
'';
};
package = lib.mkPackageOption pkgs "flashprog" { };
};
config = lib.mkIf cfg.enable {
services.udev.packages = [ cfg.package ];
environment.systemPackages = [ cfg.package ];
};
}
+47
View File
@@ -0,0 +1,47 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.ghidra;
in
{
options.programs.ghidra = {
enable = lib.mkEnableOption "Ghidra, a software reverse engineering (SRE) suite of tools";
gdb = lib.mkOption {
default = true;
type = lib.types.bool;
description = ''
Whether to add to gdbinit the python modules required to make Ghidra's debugger work.
'';
};
package = lib.mkPackageOption pkgs "ghidra" { example = "ghidra-bin"; };
};
config = lib.mkIf cfg.enable {
environment = {
systemPackages = [ cfg.package ];
etc = lib.mkIf cfg.gdb {
"gdb/gdbinit.d/ghidra-modules.gdb".text = with pkgs.python3.pkgs; ''
python
import sys
[sys.path.append(p) for p in "${
(makePythonPath [
psutil
protobuf
])
}".split(":")]
end
'';
};
};
};
meta.maintainers = with lib.maintainers; [ govanify ];
}
+6 -4
View File
@@ -1017,11 +1017,13 @@ in {
# systemd clean --what=state is used to delete the account, so long as the user
# then runs one of the cert services, there won't be any issues.
accountTargets = lib.mapAttrs' (hash: confs: let
leader = "acme-${(builtins.head confs).cert}.service";
dependantServices = map (conf: "acme-${conf.cert}.service") (builtins.tail confs);
dnsConfs = builtins.filter (conf: cfg.certs.${conf.cert}.dnsProvider != null) confs;
leaderConf = if dnsConfs != [ ] then builtins.head dnsConfs else builtins.head confs;
leader = "acme-${leaderConf.cert}.service";
followers = map (conf: "acme-${conf.cert}.service") (builtins.filter (conf: conf != leaderConf) confs);
in lib.nameValuePair "acme-account-${hash}" {
requiredBy = dependantServices;
before = dependantServices;
requiredBy = followers;
before = followers;
requires = [ leader ];
after = [ leader ];
}) (lib.groupBy (conf: conf.accountHash) (lib.attrValues certConfigs));
+2 -2
View File
@@ -345,7 +345,7 @@ in
"--what='sleep'"
"--why=${lib.escapeShellArg "Scheduled backup ${name}"} "
];
resticCmd = "${lib.optionalString backup.inhibitsSleep inhibitCmd}${backup.package}/bin/restic${extraOptions}";
resticCmd = "${lib.optionalString backup.inhibitsSleep inhibitCmd}${lib.getExe backup.package}${extraOptions}";
excludeFlags = lib.optional (
backup.exclude != [ ]
) "--exclude-file=${pkgs.writeText "exclude-patterns" (lib.concatStringsSep "\n" backup.exclude)}";
@@ -455,7 +455,7 @@ in
name: backup:
let
extraOptions = lib.concatMapStrings (arg: " -o ${arg}") backup.extraOptions;
resticCmd = "${backup.package}/bin/restic${extraOptions}";
resticCmd = "${lib.getExe backup.package}${extraOptions}";
in
pkgs.writeShellScriptBin "restic-${name}" ''
set -a # automatically export variables
@@ -727,10 +727,16 @@ in
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged @resources"
] ++ lib.optionals (any extensionInstalled [ "plv8" ]) [ "@pkey" ];
SystemCallFilter =
[
"@system-service"
"~@privileged @resources"
]
++ lib.optionals (any extensionInstalled [ "plv8" ]) [ "@pkey" ]
++ lib.optionals (any extensionInstalled [ "citus" ]) [
"getpriority"
"setpriority"
];
UMask = if groupAccessAvailable then "0027" else "0077";
}
(mkIf (cfg.dataDir != "/var/lib/postgresql/${cfg.package.psqlSchema}") {
+96 -1
View File
@@ -163,6 +163,58 @@ in
};
};
captcha = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Enables Gitea to display a CAPTCHA challenge on registration.
'';
};
secretFile = mkOption {
type = types.nullOr types.str;
default = null;
example = "/var/lib/secrets/gitea/captcha_secret";
description = "Path to a file containing the CAPTCHA secret key.";
};
siteKey = mkOption {
type = types.nullOr types.str;
default = null;
example = "my_site_key";
description = "CAPTCHA site key to use for Gitea.";
};
url = mkOption {
type = types.nullOr types.str;
default = null;
example = "https://google.com/recaptcha";
description = "CAPTCHA url to use for Gitea. Only relevant for `recaptcha` and `mcaptcha`.";
};
type = mkOption {
type = types.enum [ "image" "recaptcha" "hcaptcha" "mcaptcha" "cfturnstile" ];
default = "image";
example = "recaptcha";
description = "The type of CAPTCHA to use for Gitea.";
};
requireForLogin = mkOption {
type = types.bool;
default = false;
example = true;
description = "Displays a CAPTCHA challenge whenever a user logs in.";
};
requireForExternalRegistration = mkOption {
type = types.bool;
default = false;
example = true;
description = "Displays a CAPTCHA challenge for users that register externally.";
};
};
dump = {
enable = mkOption {
type = types.bool;
@@ -404,9 +456,30 @@ in
and `ensureDatabases` doesn't have any effect.
'';
}
{
assertion = cfg.captcha.enable -> cfg.captcha.type != "image" -> (cfg.captcha.secretFile != null && cfg.captcha.siteKey != null);
message = ''
Using a CAPTCHA service that is not `image` requires providing a CAPTCHA secret through
the `captcha.secretFile` option and a CAPTCHA site key through the `captcha.siteKey` option.
'';
}
{
assertion = cfg.captcha.url != null -> (builtins.elem cfg.captcha.type ["mcaptcha" "recaptcha"]);
message = ''
`captcha.url` is only relevant when `captcha.type` is `mcaptcha` or `recaptcha`.
'';
}
];
services.gitea.settings = {
services.gitea.settings = let
captchaPrefix = optionalString cfg.captcha.enable ({
image = "IMAGE";
recaptcha = "RECAPTCHA";
hcaptcha = "HCAPTCHA";
mcaptcha = "MCAPTCHA";
cfturnstile = "CF_TURNSTILE";
}."${cfg.captcha.type}");
in {
"cron.update_checker".ENABLED = lib.mkDefault false;
database = mkMerge [
@@ -450,6 +523,24 @@ in
INSTALL_LOCK = true;
};
service = mkIf cfg.captcha.enable (mkMerge [
{
ENABLE_CAPTCHA = true;
CAPTCHA_TYPE = cfg.captcha.type;
REQUIRE_CAPTCHA_FOR_LOGIN = cfg.captcha.requireForLogin;
REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA = cfg.captcha.requireForExternalRegistration;
}
(mkIf (cfg.captcha.secretFile != null) {
"${captchaPrefix}_SECRET" = "#captchasecret#";
})
(mkIf (cfg.captcha.siteKey != null) {
"${captchaPrefix}_SITEKEY" = cfg.captcha.siteKey;
})
(mkIf (cfg.captcha.url != null) {
"${captchaPrefix}_URL" = cfg.captcha.url;
})
]);
mailer = mkIf (cfg.mailerPasswordFile != null) {
PASSWD = "#mailerpass#";
};
@@ -592,6 +683,10 @@ in
${lib.optionalString (cfg.metricsTokenFile != null) ''
${replaceSecretBin} '#metricstoken#' '${cfg.metricsTokenFile}' '${runConfig}'
''}
${lib.optionalString (cfg.captcha.secretFile != null) ''
${replaceSecretBin} '#captchasecret#' '${cfg.captcha.secretFile}' '${runConfig}'
''}
chmod u-w '${runConfig}'
}
(umask 027; gitea_setup)
+21 -7
View File
@@ -110,6 +110,8 @@ in
for details on what clients are able to do.
'';
};
analysis.enable = lib.mkEnableOption "Runtime analysis with klipper-estimator";
};
};
@@ -170,9 +172,15 @@ in
in
format.generate "moonraker.cfg" fullConfig;
systemd.tmpfiles.rules = [
"d '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -"
] ++ lib.optional (cfg.configDir != null) "d '${cfg.configDir}' - ${cfg.user} ${cfg.group} - -";
systemd.tmpfiles.rules =
[
"d '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -"
]
++ lib.optional (cfg.configDir != null) "d '${cfg.configDir}' - ${cfg.user} ${cfg.group} - -"
++ lib.optionals cfg.analysis.enable [
"d '${cfg.stateDir}/tools/klipper_estimator' - ${cfg.user} ${cfg.group} - -"
"L+ '${cfg.stateDir}/tools/klipper_estimator/klipper_estimator_linux' - - - - ${lib.getExe pkgs.klipper-estimator}"
];
systemd.services.moonraker = {
description = "Moonraker, an API web server for Klipper";
@@ -206,10 +214,16 @@ in
};
};
# set this to false, otherwise we'll get a warning indicating that `/etc/klipper.cfg`
# is not located in the moonraker config directory.
services.moonraker.settings = lib.mkIf (!config.services.klipper.mutableConfig) {
file_manager.check_klipper_config_path = false;
services.moonraker.settings = {
# set this to false, otherwise we'll get a warning indicating that `/etc/klipper.cfg`
# is not located in the moonraker config directory.
file_manager.check_klipper_config_path = lib.mkIf (!config.services.klipper.mutableConfig) false;
# enable analysis with our own klipper-estimator, disable updating it
analysis = lib.mkIf (cfg.analysis.enable) {
platform = "linux";
enable_estimator_updates = false;
};
};
security.polkit.extraConfig = lib.optionalString cfg.allowSystemControl ''
@@ -142,8 +142,7 @@ let
src = pkgs.runCommand "nixos-taskserver-src" { preferLocalBuild = true; } ''
mkdir -p "$out"
cat "${
pkgs.substituteAll {
src = ./helper-tool.py;
pkgs.replaceVars ./helper-tool.py {
inherit taskd certtool;
inherit (cfg)
dataDir
@@ -0,0 +1,194 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.prometheus.alertmanagerGotify;
pkg = cfg.package;
inherit (lib)
mkEnableOption
mkOption
types
mkIf
mkPackageOption
optionalString
;
in
{
meta.maintainers = with lib.maintainers; [ juli0604 ];
options.services.prometheus.alertmanagerGotify = {
enable = mkEnableOption "alertmagager-gotify";
package = mkPackageOption pkgs "alertmanager-gotify-bridge" { };
bindAddress = mkOption {
type = types.str;
default = "0.0.0.0";
description = "The address the server will listen on (bind address).";
};
defaultPriority = mkOption {
type = types.int;
default = 5;
description = "The default priority for messages sent to gotify.";
};
debug = mkOption {
type = types.bool;
default = false;
description = "Enables extended logs for debugging purposes. Should be disabled in productive mode.";
};
dispatchErrors = mkOption {
type = types.bool;
default = false;
description = "When enabled, alerts will be tried to dispatch with an error message regarding faulty templating or missing fields to help debugging.";
};
extendedDetails = mkOption {
type = types.bool;
default = false;
description = "When enabled, alerts are presented in HTML format and include colorized status (FIR|RES), alert start time, and a link to the generator of the alert.";
};
messageAnnotation = mkOption {
type = types.str;
description = "Annotation holding the alert message.";
};
openFirewall = mkOption {
type = types.bool;
default = false;
description = "Opens the bridge port in the firewall.";
};
port = mkOption {
type = types.port;
default = 8080;
description = "The local port the bridge is listening on.";
};
priorityAnnotation = mkOption {
type = types.str;
default = "priority";
description = "Annotation holding the priority of the alert.";
};
timeout = mkOption {
type = types.ints.positive;
default = 5;
description = "The time between sending a message and the timeout.";
};
titleAnnotation = mkOption {
type = types.str;
default = "summary";
description = "Annotation holding the title of the alert";
};
webhookPath = mkOption {
type = types.str;
default = "/gotify_webhook";
description = "The URL path to handle requests on.";
};
environmentFile = mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = ''
File containing additional config environment variables for alertmanager-gotify-bridge.
This is especially for secrets like GOTIFY_TOKEN and AUTH_PASSWORD.
'';
};
gotifyEndpoint = {
host = mkOption {
type = types.str;
default = "127.0.0.1";
description = "The hostname or ip your gotify endpoint is running.";
};
port = mkOption {
type = types.port;
default = 443;
description = "The port your gotify endpoint is running.";
};
tls = mkOption {
type = types.bool;
default = true;
description = "If your gotify endpoint uses https, leave this option set to default";
};
};
metrics = {
username = mkOption {
type = types.str;
description = "The username used to access your metrics.";
};
namespace = mkOption {
type = types.str;
default = "alertmanager-gotify-bridge";
description = "The namescape of the metrics.";
};
path = mkOption {
type = types.str;
default = "/metrics";
description = "The path under which the metrics will be exposed.";
};
};
};
config = mkIf cfg.enable {
users = {
groups.alertmanager-gotify = { };
users.alertmanager-gotify = {
group = "alertmanager-gotify";
isSystemUser = true;
};
};
networking.firewall = mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
};
systemd.services.alertmanager-gotify-bridge = {
description = "A bridge between Prometheus AlertManager and a Gotify server";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${lib.getExe pkg} ${optionalString cfg.debug "--debug"}";
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [ cfg.environmentFile ];
User = "alertmanager-gotify";
Group = "alertmanager-gotify";
#hardening
NoNewPrivileges = true;
PrivateTmp = true;
PrivateDevices = true;
PrivateIPC = true;
DevicePolicy = "closed";
ProtectSystem = "strict";
ProtectHome = "read-only";
ProtectControlGroups = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectKernelTunables = true;
ProtectHostname = true;
ProtectProc = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
MemoryDenyWriteExecute = true;
LockPersonality = true;
ProcSubset = "pid";
SystemCallArchitectures = "native";
RemoveIPC = true;
};
environment = {
BIND_ADDRESS = cfg.bindAddress;
DEFAULT_PRIORITY = toString cfg.defaultPriority;
DISPATCH_ERRORS = toString cfg.dispatchErrors;
EXTENDED_DETAILS = toString cfg.extendedDetails;
MESSAGE_ANNOTATION = cfg.messageAnnotation;
PORT = toString cfg.port;
PRIORITY_ANNOTATION = cfg.priorityAnnotation;
TIMEOUT = "${toString cfg.timeout}s";
TITLE_ANNOTATION = cfg.titleAnnotation;
WEBHOOK_PATH = cfg.webhookPath;
GOTIFY_ENDPOINT = "${
if cfg.gotifyEndpoint.tls then "https://" else "http://"
}${toString cfg.gotifyEndpoint.host}:${toString cfg.gotifyEndpoint.port}/message";
AUTH_USERNAME = cfg.metrics.username;
};
};
};
}
@@ -415,6 +415,8 @@ in
KexAlgorithms = lib.mkOption {
type = lib.types.nullOr (lib.types.listOf lib.types.str);
default = [
"mlkem768x25519-sha256"
"sntrup761x25519-sha512"
"sntrup761x25519-sha512@openssh.com"
"curve25519-sha256"
"curve25519-sha256@libssh.org"
@@ -21,7 +21,7 @@ let
# note that the dot in front of `${path}` is the hostname, which is
# required.
then "--unix-socket ${cfg.guiAddress} http://.${path}"
# no adjustements are needed if cfg.guiAddress is a network address
# no adjustments are needed if cfg.guiAddress is a network address
else "${cfg.guiAddress}${path}"
;
@@ -68,7 +68,7 @@ let
/* Syncthing's rest API for the folders and devices is almost identical.
Hence we iterate them using lib.pipe and generate shell commands for both at
the sime time. */
the same time. */
(lib.pipe {
# The attributes below are the only ones that are different for devices /
# folders.
+2 -2
View File
@@ -91,7 +91,7 @@ in
description = ''
Whether to enable the fail2ban service.
See the documentation of {option}`services.fail2ban.jails`
See the documentation of [](#opt-services.fail2ban.jails)
for what jails are enabled by default.
'';
};
@@ -326,7 +326,7 @@ in
NixOS comes with a default `sshd` jail;
for it to work well,
{option}`services.openssh.logLevel` should be set to
[](#opt-services.openssh.settings.LogLevel) should be set to
`"VERBOSE"` or higher so that fail2ban
can observe failed login attempts.
This module sets it to `"VERBOSE"` if
+10 -6
View File
@@ -855,12 +855,16 @@ in
User = "kanidm";
Group = "kanidm";
BindPaths = [
# To create the socket
"/run/kanidmd:/run/kanidmd"
# To store backups
cfg.serverSettings.online_backup.path
];
BindPaths =
[
# To create the socket
"/run/kanidmd:/run/kanidmd"
# To store backups
cfg.serverSettings.online_backup.path
]
++ optional (
cfg.enablePam && cfg.unixSettings ? home_mount_prefix
) cfg.unixSettings.home_mount_prefix;
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
@@ -105,7 +105,7 @@ in
add_header Set-Cookie $auth_cookie;
'';
"/oauth2/auth" =
"= /oauth2/auth" =
let
maybeQueryArg =
name: value:
+10 -1
View File
@@ -120,12 +120,21 @@ in
###### implementation
config = {
config = mkIf config.console.enable {
# Note: this is set here rather than up there so that changing
# nixos.label would not rebuild manual pages
services.getty.greetingLine = mkDefault ''<<< Welcome to ${config.system.nixos.distroName} ${config.system.nixos.label} (\m) - \l >>>'';
services.getty.helpLine = mkIf (config.documentation.nixos.enable && config.documentation.doc.enable) "\nRun 'nixos-help' for the NixOS manual.";
systemd.additionalUpstreamSystemUnits = [
"getty.target"
"getty-pre.target"
"getty@.service"
"serial-getty@.service"
"console-getty.service"
"container-getty@.service"
];
systemd.services."getty@" =
{ serviceConfig.ExecStart = [
# override upstream default with an empty ExecStart
+46 -42
View File
@@ -5,9 +5,17 @@
...
}:
with lib;
let
inherit (lib)
mkEnableOption
mkPackageOption
mkOption
mkDefault
mkIf
types
literalExpression
;
cfg = config.services.mobilizon;
user = "mobilizon";
@@ -20,34 +28,29 @@ let
# Make a package containing launchers with the correct envirenment, instead of
# setting it with systemd services, so that the user can also use them without
# troubles
launchers = pkgs.stdenv.mkDerivation rec {
pname = "${cfg.package.pname}-launchers";
inherit (cfg.package) version;
launchers =
pkgs.runCommand "${cfg.package.pname}-launchers-${cfg.package.version}"
{
src = cfg.package;
nativeBuildInputs = with pkgs; [ makeWrapper ];
}
''
mkdir -p $out/bin
src = cfg.package;
makeWrapper \
$src/bin/mobilizon \
$out/bin/mobilizon \
--run '. ${secretEnvFile}' \
--set MOBILIZON_CONFIG_PATH "${configFile}" \
--set-default RELEASE_TMP "/tmp"
nativeBuildInputs = with pkgs; [ makeWrapper ];
dontBuild = true;
installPhase = ''
mkdir -p $out/bin
makeWrapper \
$src/bin/mobilizon \
$out/bin/mobilizon \
--run '. ${secretEnvFile}' \
--set MOBILIZON_CONFIG_PATH "${configFile}" \
--set-default RELEASE_TMP "/tmp"
makeWrapper \
$src/bin/mobilizon_ctl \
$out/bin/mobilizon_ctl \
--run '. ${secretEnvFile}' \
--set MOBILIZON_CONFIG_PATH "${configFile}" \
--set-default RELEASE_TMP "/tmp"
'';
};
makeWrapper \
$src/bin/mobilizon_ctl \
$out/bin/mobilizon_ctl \
--run '. ${secretEnvFile}' \
--set MOBILIZON_CONFIG_PATH "${configFile}" \
--set-default RELEASE_TMP "/tmp"
'';
repoSettings = cfg.settings.":mobilizon"."Mobilizon.Storage.Repo";
instanceSettings = cfg.settings.":mobilizon".":instance";
@@ -390,6 +393,7 @@ in
serviceConfig = {
Type = "oneshot";
User = config.services.postgresql.superUser;
Restart = "on-failure";
};
};
@@ -424,32 +428,32 @@ in
virtualHosts."${hostname}" = {
enableACME = lib.mkDefault true;
forceSSL = lib.mkDefault true;
extraConfig = ''
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
'';
locations."/" = {
inherit proxyPass;
proxyWebsockets = true;
recommendedProxySettings = lib.mkDefault true;
extraConfig = ''
expires off;
add_header Cache-Control "public, max-age=0, s-maxage=0, must-revalidate" always;
'';
};
locations."~ ^/(js|css|img)" = {
locations."~ ^/(assets|img)" = {
root = "${cfg.package}/lib/mobilizon-${cfg.package.version}/priv/static";
extraConfig = ''
etag off;
access_log off;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Cache-Control "public, max-age=31536000, s-maxage=31536000, immutable";
'';
};
locations."~ ^/(media|proxy)" = {
inherit proxyPass;
recommendedProxySettings = lib.mkDefault true;
# Combination of HTTP/1.1 and disabled request buffering is
# needed to directly forward chunked responses
extraConfig = ''
etag off;
proxy_http_version 1.1;
proxy_request_buffering off;
access_log off;
add_header Cache-Control "public, max-age=31536000, immutable";
add_header Cache-Control "public, max-age=31536000, s-maxage=31536000, immutable";
'';
};
};
@@ -0,0 +1,263 @@
{
config,
lib,
pkgs,
...
}:
# TODO: ACME
# TODO: Gems includes for Mruby
# TODO: Recommended options
let
cfg = config.services.h2o;
inherit (lib)
literalExpression
mkDefault
mkEnableOption
mkIf
mkOption
types
;
settingsFormat = pkgs.formats.yaml { };
hostsConfig = lib.concatMapAttrs (
name: value:
let
port = {
HTTP = lib.attrByPath [ "http" "port" ] cfg.defaultHTTPListenPort value;
TLS = lib.attrByPath [ "tls" "port" ] cfg.defaultTLSListenPort value;
};
serverName = if value.serverName != null then value.serverName else name;
in
# HTTP settings
lib.optionalAttrs (value.tls == null || value.tls.policy == "add") {
"${serverName}:${builtins.toString port.HTTP}" = value.settings // {
listen.port = port.HTTP;
};
}
# Redirect settings
// lib.optionalAttrs (value.tls != null && value.tls.policy == "force") {
"${serverName}:${builtins.toString port.HTTP}" = {
listen.port = port.HTTP;
paths."/" = {
redirect = {
status = value.tls.redirectCode;
url = "https://${serverName}:${builtins.toString port.TLS}";
};
};
};
}
# TLS settings
//
lib.optionalAttrs
(
value.tls != null
&& builtins.elem value.tls.policy [
"add"
"only"
"force"
]
)
{
"${serverName}:${builtins.toString port.TLS}" = value.settings // {
listen =
let
identity = value.tls.identity;
in
{
port = port.TLS;
ssl = value.tls.extraSettings or { } // {
inherit identity;
};
};
};
}
) cfg.hosts;
h2oConfig = settingsFormat.generate "h2o.yaml" (
lib.recursiveUpdate { hosts = hostsConfig; } cfg.settings
);
in
{
options = {
services.h2o = {
enable = mkEnableOption "H2O web server";
user = mkOption {
type = types.nonEmptyStr;
default = "h2o";
description = "User running H2O service";
};
group = mkOption {
type = types.nonEmptyStr;
default = "h2o";
description = "Group running H2O services";
};
package = lib.mkPackageOption pkgs "h2o" {
example = ''
pkgs.h2o.override {
withMruby = true;
};
'';
};
defaultHTTPListenPort = mkOption {
type = types.port;
default = 80;
description = ''
If hosts do not specify listen.port, use these ports for HTTP by default.
'';
example = 8080;
};
defaultTLSListenPort = mkOption {
type = types.port;
default = 443;
description = ''
If hosts do not specify listen.port, use these ports for SSL by default.
'';
example = 8443;
};
mode = mkOption {
type =
with types;
nullOr (enum [
"daemon"
"master"
"worker"
"test"
]);
default = "master";
description = "Operating mode of H2O";
};
settings = mkOption {
type = settingsFormat.type;
description = "Configuration for H2O (see <https://h2o.examp1e.net/configure.html>)";
};
hosts = mkOption {
type = types.attrsOf (
types.submodule (
import ./vhost-options.nix {
inherit config lib;
}
)
);
default = { };
description = ''
The `hosts` config to be merged with the settings.
Note that unlike YAML used for H2O, Nix will not support duplicate
keys to, for instance, have multiple listens in a host block; use the
virtual host options in like `http` & `tls` or use `$HOST:$PORT`
keys if manually specifying config.
'';
example =
literalExpression
# nix
''
{
"hydra.example.com" = {
tls = {
policy = "force";
indentity = [
{
key-file = "/path/to/key";
certificate-file = "/path/to/cert";
};
];
extraSettings = {
minimum-version = "TLSv1.3";
};
};
settings = {
paths."/" = {
"file:dir" = "/var/www/default";
};
};
};
}
'';
};
};
};
config = mkIf cfg.enable {
users = {
users.${cfg.user} =
{
group = cfg.group;
}
// lib.optionalAttrs (cfg.user == "h2o") {
isSystemUser = true;
};
groups.${cfg.group} = { };
};
systemd.services.h2o = {
description = "H2O web server service";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
serviceConfig = {
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
ExecStop = "${pkgs.coreutils}/bin/kill -s QUIT $MAINPID";
User = cfg.user;
Restart = "always";
RestartSec = "10s";
RuntimeDirectory = "h2o";
RuntimeDirectoryMode = "0750";
CacheDirectory = "h2o";
CacheDirectoryMode = "0750";
LogsDirectory = "h2o";
LogsDirectoryMode = "0750";
ProtectSystem = "strict";
ProtectHome = mkDefault true;
PrivateTmp = true;
PrivateDevices = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
LockPersonality = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
RemoveIPC = true;
PrivateMounts = true;
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
CapabilitiesBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
};
script =
let
args =
[
"--conf"
"${h2oConfig}"
]
++ lib.optionals (cfg.mode != null) [
"--mode"
cfg.mode
];
in
''
${lib.getExe cfg.package} ${lib.strings.escapeShellArgs args}
'';
};
};
}
@@ -0,0 +1,151 @@
{ config, lib, ... }:
let
inherit (lib)
literalExpression
mkOption
types
;
in
{
options = {
serverName = mkOption {
type = types.nullOr types.nonEmptyStr;
default = null;
description = ''
Server name to be used for this virtual host. Defaults to attribute
name in hosts.
'';
example = "example.org";
};
http = mkOption {
type = types.nullOr (
types.submodule {
options = {
port = mkOption {
type = types.port;
default = config.services.h2o.defaultHTTPListenPort;
defaultText = literalExpression ''
config.services.h2o.defaultHTTPListenPort
'';
description = ''
Override the default HTTP port for this virtual host.
'';
example = literalExpression "8080";
};
};
}
);
default = null;
description = "HTTP options for virtual host";
};
tls = mkOption {
type = types.nullOr (
types.submodule {
options = {
port = mkOption {
type = types.port;
default = config.services.h2o.defaultTLSListenPort;
defaultText = literalExpression ''
config.services.h2o.defaultTLSListenPort
'';
description = ''
Override the default TLS port for this virtual host.";
'';
example = 8443;
};
policy = mkOption {
type = types.enum [
"add"
"only"
"force"
];
description = ''
`add` will additionally listen for TLS connections. `only` will
disable TLS connections. `force` will redirect non-TLS traffic
to the TLS connection.
'';
example = "force";
};
redirectCode = mkOption {
type = types.ints.between 300 399;
default = 301;
example = 308;
description = ''
HTTP status used by `globalRedirect` & `forceSSL`. Possible
usecases include temporary (302, 307) redirects, keeping the
request method & body (307, 308), or explicitly resetting the
method to GET (303). See
<https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections>.
'';
};
identity = mkOption {
type = types.nonEmptyListOf (
types.submodule {
options = {
key-file = mkOption {
type = types.path;
description = "Path to key file";
};
certificate-file = mkOption {
type = types.path;
description = "Path to certificate file";
};
};
}
);
default = null;
description = ''
Key / certificate pairs for the virtual host.
'';
example =
literalExpression
# nix
''
{
indentities = [
{
key-file = "/path/to/rsa.key";
certificate-file = "/path/to/rsa.crt";
}
{
key-file = "/path/to/ecdsa.key";
certificate-file = "/path/to/ecdsa.crt";
}
];
}
'';
};
extraSettings = mkOption {
type = types.nullOr types.attrs;
default = null;
description = ''
Additional TLS/SSL-related configuration options.
'';
example =
literalExpression
# nix
''
{
minimum-version = "TLSv1.3";
}
'';
};
};
}
);
default = null;
description = "TLS options for virtual host";
};
settings = mkOption {
type = types.attrs;
description = ''
Attrset to be transformed into YAML for host config. Note that the HTTP
/ TLS configurations will override these config values.
'';
};
};
}
@@ -95,7 +95,7 @@ if (!-f "/etc/NIXOS" && (read_file("/etc/os-release", err_mode => "quiet") // ""
make_path("/run/nixos", { mode => oct(755) });
open(my $stc_lock, '>>', '/run/nixos/switch-to-configuration.lock') or die "Could not open lock - $!";
flock($stc_lock, LOCK_EX) or die "Could not acquire lock - $!";
flock($stc_lock, LOCK_EX|LOCK_NB) or die "Could not acquire lock - $!";
openlog("nixos", "", LOG_USER);
# run pre-switch checks
@@ -727,11 +727,13 @@ in
system.build.installBootLoader =
let
install-grub-pl = pkgs.substituteAll {
src = ./install-grub.pl;
install-grub-pl = pkgs.replaceVars ./install-grub.pl {
utillinux = pkgs.util-linux;
btrfsprogs = pkgs.btrfs-progs;
inherit (config.system.nixos) distroName;
# targets of a replacement in code
bootPath = null;
bootRoot = null;
};
perl = pkgs.perl.withPackages (p: with p; [
FileSlurp FileCopyRecursive
@@ -3,7 +3,7 @@ use warnings;
use Class::Struct;
use XML::LibXML;
use File::Basename;
use File::Path;
use File::Path qw(make_path rmtree);
use File::stat;
use File::Copy;
use File::Copy::Recursive qw(rcopy pathrm);
@@ -37,7 +37,8 @@ sub readFile {
my ($fn) = @_;
# enable slurp mode: read entire file in one go
local $/ = undef;
open my $fh, "<$fn" or return undef;
open my $fh, "<", $fn
or return;
my $s = <$fh>;
close $fh;
# disable slurp mode
@@ -48,7 +49,7 @@ sub readFile {
sub writeFile {
my ($fn, $s) = @_;
open my $fh, ">$fn" or die "cannot create $fn: $!\n";
open my $fh, ">", $fn or die "cannot create $fn: $!\n";
print $fh $s or die "cannot write to $fn: $!\n";
close $fh or die "cannot close $fn: $!\n";
}
@@ -98,7 +99,7 @@ $ENV{'PATH'} = get("path");
print STDERR "updating GRUB 2 menu...\n";
mkpath("$bootPath/grub", 0, 0700);
make_path("$bootPath/grub", { mode => 0700 });
# Discover whether the bootPath is on the same filesystem as / and
# /nix/store. If not, then all kernels and initrds must be copied to
@@ -438,7 +439,7 @@ $conf .= "$extraConfig\n";
$conf .= "\n";
my %copied;
mkpath("$bootPath/kernels", 0, 0755) if $copyKernels;
make_path("$bootPath/kernels", { mode => 0755 }) if $copyKernels;
sub copyToKernelsDir {
my ($path) = @_;
@@ -471,7 +472,7 @@ sub addEntry {
my $systemName = basename(Cwd::abs_path("$path"));
my $initrdSecretsPath = "$bootPath/kernels/$systemName-secrets";
mkpath(dirname($initrdSecretsPath), 0, 0755);
make_path(dirname($initrdSecretsPath), { mode => 0755 });
my $oldUmask = umask;
# Make sure initrd is not world readable (won't work if /boot is FAT)
umask 0137;
@@ -690,17 +691,17 @@ struct(GrubState => {
# because it is read line-by-line.
sub readGrubState {
my $defaultGrubState = GrubState->new(name => "", version => "", efi => "", devices => "", efiMountPoint => "", extraGrubInstallArgs => () );
open FILE, "<$bootPath/grub/state" or return $defaultGrubState;
open my $fh, "<", "$bootPath/grub/state" or return $defaultGrubState;
local $/ = "\n";
my $name = <FILE>;
my $name = <$fh>;
chomp($name);
my $version = <FILE>;
my $version = <$fh>;
chomp($version);
my $efi = <FILE>;
my $efi = <$fh>;
chomp($efi);
my $devices = <FILE>;
my $devices = <$fh>;
chomp($devices);
my $efiMountPoint = <FILE>;
my $efiMountPoint = <$fh>;
chomp($efiMountPoint);
# Historically, arguments in the state file were one per each line, but that
# gets really messy when newlines are involved, structured arguments
@@ -708,7 +709,7 @@ sub readGrubState {
# when we need to remove a setting in the future. Thus, the 6th line is a JSON
# object that can store structured data, with named keys, and all new state
# should go in there.
my $jsonStateLine = <FILE>;
my $jsonStateLine = <$fh>;
# For historical reasons we do not check the values above for un-definedness
# (that is, when the state file has too few lines and EOF is reached),
# because the above come from the first version of this logic and are thus
@@ -720,7 +721,7 @@ sub readGrubState {
}
my %jsonState = %{decode_json($jsonStateLine)};
my @extraGrubInstallArgs = exists($jsonState{'extraGrubInstallArgs'}) ? @{$jsonState{'extraGrubInstallArgs'}} : ();
close FILE;
close $fh;
my $grubState = GrubState->new(name => $name, version => $version, efi => $efi, devices => $devices, efiMountPoint => $efiMountPoint, extraGrubInstallArgs => \@extraGrubInstallArgs );
return $grubState
}
@@ -787,18 +788,18 @@ if ($requireNewInstall != 0) {
my $stateFile = "$bootPath/grub/state";
my $stateFileTmp = $stateFile . ".tmp";
open FILE, ">$stateFileTmp" or die "cannot create $stateFileTmp: $!\n";
print FILE get("fullName"), "\n" or die;
print FILE get("fullVersion"), "\n" or die;
print FILE $efiTarget, "\n" or die;
print FILE join( ",", @deviceTargets ), "\n" or die;
print FILE $efiSysMountPoint, "\n" or die;
open my $fh, ">", "$stateFileTmp" or die "cannot create $stateFileTmp: $!\n";
print $fh get("fullName"), "\n" or die;
print $fh get("fullVersion"), "\n" or die;
print $fh $efiTarget, "\n" or die;
print $fh join( ",", @deviceTargets ), "\n" or die;
print $fh $efiSysMountPoint, "\n" or die;
my %jsonState = (
extraGrubInstallArgs => \@extraGrubInstallArgs
);
my $jsonStateLine = encode_json(\%jsonState);
print FILE $jsonStateLine, "\n" or die;
close FILE or die;
print $fh $jsonStateLine, "\n" or die;
close $fh or die;
# Atomically switch to the new state file
rename $stateFileTmp, $stateFile or die "cannot rename $stateFileTmp to $stateFile: $!\n";
+1
View File
@@ -437,6 +437,7 @@ let
(assertKeyIsSystemdCredential "PresharedKey")
(assertOnlyFields [
"PublicKey"
"PublicKeyFile"
"PresharedKey"
"PresharedKeyFile"
"AllowedIPs"
-9
View File
@@ -60,15 +60,6 @@ let
# hwdb.bin is managed by NixOS
# "systemd-hwdb-update.service"
# Consoles.
"getty.target"
"getty-pre.target"
"getty@.service"
"serial-getty@.service"
"console-getty.service"
"container-getty@.service"
"systemd-vconsole-setup.service"
# Hardware (started by udev when a relevant device is plugged in).
"sound.target"
"bluetooth.target"
+3 -1
View File
@@ -538,7 +538,9 @@ in
"${cfg.package.util-linux}/bin/umount"
"${cfg.package.util-linux}/bin/sulogin"
# required for script services, and some tools like xfs still want the sh symlink
# required for services generated with writeShellScript and friends
pkgs.runtimeShell
# some tools like xfs still want the sh symlink
"${pkgs.bash}/bin"
# so NSS can look up usernames
+1 -1
View File
@@ -179,7 +179,7 @@ let
type = types.attrsOf types.path;
default = { };
description = ''
Hooks that will be placed under /var/lib/libvirt/hooks/lxc.d/
Hooks that will be placed under /var/lib/libvirt/hooks/network.d/
and called for networks begin/end events.
Please see https://libvirt.org/hooks.html for documentation.
'';
@@ -115,6 +115,16 @@ let
extraFlags+=("--private-network")
fi
NIX_BIND_OPT=""
if [ -n "$PRIVATE_USERS" ]; then
extraFlags+=("--private-users=$PRIVATE_USERS")
if [ "$PRIVATE_USERS" = "pick" ] || { [ "$PRIVATE_USERS" != "identity" ] && [ "$PRIVATE_USERS" -gt 0 ]; }; then
# when user namespacing is enabled, we use `idmap` mount option
# so that bind mounts under /nix get proper owner (and not nobody/nogroup).
NIX_BIND_OPT=":idmap"
fi
fi
if [ -n "$HOST_ADDRESS" ] || [ -n "$LOCAL_ADDRESS" ] ||
[ -n "$HOST_ADDRESS6" ] || [ -n "$LOCAL_ADDRESS6" ]; then
extraFlags+=("--network-veth")
@@ -171,13 +181,14 @@ let
$EXTRA_NSPAWN_FLAGS \
--notify-ready=yes \
--kill-signal=SIGRTMIN+3 \
--bind-ro=/nix/store \
--bind-ro=/nix/var/nix/db \
--bind-ro=/nix/var/nix/daemon-socket \
--bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles" \
--bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots" \
--bind-ro=/nix/store:/nix/store$NIX_BIND_OPT \
--bind-ro=/nix/var/nix/db:/nix/var/nix/db$NIX_BIND_OPT \
--bind-ro=/nix/var/nix/daemon-socket:/nix/var/nix/daemon-socket$NIX_BIND_OPT \
--bind="/nix/var/nix/profiles/per-container/$INSTANCE:/nix/var/nix/profiles$NIX_BIND_OPT" \
--bind="/nix/var/nix/gcroots/per-container/$INSTANCE:/nix/var/nix/gcroots$NIX_BIND_OPT" \
${optionalString (!cfg.ephemeral) "--link-journal=try-guest"} \
--setenv PRIVATE_NETWORK="$PRIVATE_NETWORK" \
--setenv PRIVATE_USERS="$PRIVATE_USERS" \
--setenv HOST_BRIDGE="$HOST_BRIDGE" \
--setenv HOST_ADDRESS="$HOST_ADDRESS" \
--setenv LOCAL_ADDRESS="$LOCAL_ADDRESS" \
@@ -650,6 +661,27 @@ in
'';
};
privateUsers = mkOption {
type = types.either types.ints.u32 (types.enum [ "no" "identity" "pick" ]);
default = "no";
description = ''
Whether to give the container its own private UIDs/GIDs space (user namespacing).
Disabled by default (`no`).
If set to a number (usually above host's UID/GID range: 65536),
user namespacing is enabled and the container UID/GIDs will start at that number.
If set to `identity`, mostly equivalent to `0`, this will only provide
process capability isolation (no UID/GID isolation, as they are the same as host).
If set to `pick`, user namespacing is enabled and the UID/GID range is automatically chosen,
so that no overlapping UID/GID ranges are assigned to multiple containers.
This is the recommanded option as it enhances container security massively and operates fully automatically in most cases.
See https://www.freedesktop.org/software/systemd/man/latest/systemd-nspawn.html#--private-users= for details.
'';
};
interfaces = mkOption {
type = types.listOf types.str;
default = [];
@@ -862,6 +894,13 @@ in
additionalCapabilities = cfg.additionalCapabilities
++ [ "CAP_NET_ADMIN" ];
}
) // (
optionalAttrs (!cfg.enableTun && cfg.privateNetwork
&& (cfg.privateUsers == "pick" || (builtins.isInt cfg.privateUsers && cfg.privateUsers > 0 )))
{
allowedDevices = cfg.allowedDevices
++ [ { node = "/dev/net/tun"; modifier = "rwm"; } ];
}
);
in
recursiveUpdate unit {
@@ -923,6 +962,7 @@ in
${optionalString (cfg.networkNamespace != null) ''
NETWORK_NAMESPACE_PATH=${cfg.networkNamespace}
''}
PRIVATE_USERS=${toString cfg.privateUsers}
INTERFACES="${toString cfg.interfaces}"
MACVLANS="${toString cfg.macvlans}"
${optionalString cfg.autoStart ''
+33
View File
@@ -0,0 +1,33 @@
{ pkgs, lib, ... }:
{
name = "age-plugin-tpm-decrypt";
meta = with lib.maintainers; {
maintainers = [
sgo
josh
];
};
nodes.machine =
{ pkgs, ... }:
{
virtualisation.tpm.enable = true;
environment.systemPackages = with pkgs; [
age
age-plugin-tpm
];
};
testScript = ''
machine.start()
machine.succeed("age-plugin-tpm --generate --output identity.txt")
machine.succeed("age-plugin-tpm --convert identity.txt --output recipient.txt")
machine.succeed("echo -n 'Hello World' >data.txt")
machine.succeed("age --encrypt --recipients-file recipient.txt --output data.age data.txt")
data = machine.succeed("age --decrypt --identity identity.txt data.age")
assert data == "Hello World"
'';
}
+4 -1
View File
@@ -112,6 +112,7 @@ in {
aesmd = runTestOn ["x86_64-linux"] ./aesmd.nix;
agate = runTest ./web-servers/agate.nix;
agda = handleTest ./agda.nix {};
age-plugin-tpm-decrypt = runTest ./age-plugin-tpm-decrypt.nix;
agorakit = runTest ./web-apps/agorakit.nix;
airsonic = handleTest ./airsonic.nix {};
akkoma = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./akkoma.nix {};
@@ -404,6 +405,7 @@ in {
gollum = handleTest ./gollum.nix {};
gonic = handleTest ./gonic.nix {};
google-oslogin = handleTest ./google-oslogin {};
gopro-tool = handleTest ./gopro-tool.nix {};
goss = handleTest ./goss.nix {};
gotenberg = handleTest ./gotenberg.nix {};
gotify-server = handleTest ./gotify-server.nix {};
@@ -419,6 +421,7 @@ in {
guacamole-server = handleTest ./guacamole-server.nix {};
guix = handleTest ./guix {};
gvisor = handleTest ./gvisor.nix {};
h2o = discoverTests (import ./web-servers/h2o { inherit handleTestOn; });
hadoop = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop; };
hadoop_3_3 = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop_3_3; };
hadoop2 = import ./hadoop { inherit handleTestOn; package=pkgs.hadoop2; };
@@ -620,7 +623,7 @@ in {
misc = handleTest ./misc.nix {};
misskey = handleTest ./misskey.nix {};
mjolnir = handleTest ./matrix/mjolnir.nix {};
mobilizon = handleTest ./mobilizon.nix {};
mobilizon = runTest ./mobilizon.nix;
mod_perl = handleTest ./mod_perl.nix {};
molly-brown = handleTest ./molly-brown.nix {};
mollysocket = handleTest ./mollysocket.nix { };
+41
View File
@@ -0,0 +1,41 @@
import ./make-test-python.nix (
{ lib, pkgs, ... }:
let
testScript = ''
start_all()
machine.wait_for_unit("multi-user.target")
# Check that gopro-tool is installed
machine.succeed("which gopro-tool")
# Check that the v4l2loopback module is available
machine.succeed("lsmod | grep v4l2loopback || echo 'Module not found'")
# Check that VLC is installed
machine.succeed("which vlc")
'';
in
{
name = "gopro-tool";
meta.maintainers = with lib.maintainers; [ ZMon3y ];
nodes.machine =
{ config, pkgs, ... }:
{
# Ensure dependencies are installed
environment.systemPackages = with pkgs; [
gopro-tool
vlc
];
# Load kernel module for testing
boot.extraModulePackages = with config.boot.kernelPackages; [ v4l2loopback ];
# Enable module loading
boot.kernelModules = [ "v4l2loopback" ];
};
testScript = testScript;
}
)
+1 -1
View File
@@ -103,9 +103,9 @@ let
}) { inherit system; });
in with pkgs; {
kafka_3_6 = makeKafkaTest "kafka_3_6" { kafkaPackage = apacheKafka_3_6; };
kafka_3_7 = makeKafkaTest "kafka_3_7" { kafkaPackage = apacheKafka_3_7; };
kafka_3_8 = makeKafkaTest "kafka_3_8" { kafkaPackage = apacheKafka_3_8; };
kafka_3_9 = makeKafkaTest "kafka_3_9" { kafkaPackage = apacheKafka_3_9; };
kafka = makeKafkaTest "kafka" { kafkaPackage = apacheKafka; };
kafka_kraft = makeKafkaTest "kafka_kraft" { kafkaPackage = apacheKafka; mode = "kraft"; };
}
+40 -42
View File
@@ -1,49 +1,47 @@
import ./make-test-python.nix (
{ lib, ... }:
let
certs = import ./common/acme/server/snakeoil-certs.nix;
mobilizonDomain = certs.domain;
port = 41395;
in
{ lib, ... }:
let
certs = import ./common/acme/server/snakeoil-certs.nix;
mobilizonDomain = certs.domain;
port = 41395;
in
{
name = "mobilizon";
meta.maintainers = with lib.maintainers; [
minijackson
erictapen
];
{
name = "mobilizon";
meta.maintainers = with lib.maintainers; [
minijackson
erictapen
];
nodes.server =
{ ... }:
{
services.mobilizon = {
enable = true;
settings = {
":mobilizon" = {
":instance" = {
name = "Test Mobilizon";
hostname = mobilizonDomain;
};
"Mobilizon.Web.Endpoint".http.port = port;
nodes.server =
{ ... }:
{
services.mobilizon = {
enable = true;
settings = {
":mobilizon" = {
":instance" = {
name = "Test Mobilizon";
hostname = mobilizonDomain;
};
"Mobilizon.Web.Endpoint".http.port = port;
};
};
security.pki.certificateFiles = [ certs.ca.cert ];
services.nginx.virtualHosts."${mobilizonDomain}" = {
enableACME = lib.mkForce false;
sslCertificate = certs.${mobilizonDomain}.cert;
sslCertificateKey = certs.${mobilizonDomain}.key;
};
networking.hosts."::1" = [ mobilizonDomain ];
};
testScript = ''
server.wait_for_unit("mobilizon.service")
server.wait_for_open_port(${toString port})
server.succeed("curl --fail https://${mobilizonDomain}/")
'';
}
)
security.pki.certificateFiles = [ certs.ca.cert ];
services.nginx.virtualHosts."${mobilizonDomain}" = {
enableACME = lib.mkForce false;
sslCertificate = certs.${mobilizonDomain}.cert;
sslCertificateKey = certs.${mobilizonDomain}.key;
};
networking.hosts."::1" = [ mobilizonDomain ];
};
testScript = ''
server.wait_for_unit("mobilizon.service")
server.wait_for_open_port(${toString port})
server.succeed("curl --fail https://${mobilizonDomain}/")
'';
}
+6
View File
@@ -26,6 +26,8 @@ import ./make-test-python.nix (
machine.wait_for_unit("multi-user.target")
machine.succeed("nixos-generate-config")
machine.succeed("nix-instantiate --parse /etc/nixos/configuration.nix /etc/nixos/hardware-configuration.nix")
# Test if the configuration really is overridden
machine.succeed("grep 'OVERRIDDEN' /etc/nixos/configuration.nix")
@@ -41,6 +43,10 @@ import ./make-test-python.nix (
machine.succeed(
"grep 'services\\.xserver\\.desktopManager\\.gnome\\.enable = true;' /etc/nixos/configuration.nix"
)
machine.succeed("rm -rf /etc/nixos")
machine.succeed("nixos-generate-config --flake")
machine.succeed("nix-instantiate --parse /etc/nixos/flake.nix /etc/nixos/configuration.nix /etc/nixos/hardware-configuration.nix")
'';
}
)
+5 -8
View File
@@ -1,6 +1,7 @@
{
pkgs,
makeTest,
genTests,
}:
let
@@ -107,11 +108,7 @@ let
'';
};
in
lib.recurseIntoAttrs (
lib.concatMapAttrs (n: p: { ${n} = makeTestFor p; }) (
lib.filterAttrs (_: p: p ? pkgs && !p.pkgs.anonymizer.meta.broken) pkgs.postgresqlVersions
)
// {
passthru.override = p: makeTestFor p;
}
)
genTests {
inherit makeTestFor;
filter = _: p: !p.pkgs.anonymizer.meta.broken;
}
+73
View File
@@ -0,0 +1,73 @@
{
pkgs,
makeTest,
genTests,
}:
let
inherit (pkgs) lib;
test-sql = pkgs.writeText "postgresql-test" ''
CREATE EXTENSION citus;
CREATE TABLE examples (
id bigserial,
shard_key int,
PRIMARY KEY (id, shard_key)
);
SELECT create_distributed_table('examples', 'shard_key');
INSERT INTO examples (shard_key) SELECT shard % 10 FROM generate_series(1,1000) shard;
'';
makeTestFor =
package:
makeTest {
name = "citus-${package.name}";
meta = with lib.maintainers; {
maintainers = [ typetetris ];
};
nodes.machine =
{ ... }:
{
services.postgresql = {
inherit package;
enable = true;
enableJIT = lib.hasInfix "-jit-" package.name;
extensions =
ps: with ps; [
citus
];
settings = {
shared_preload_libraries = "citus";
};
};
};
testScript = ''
def check_count(statement, lines):
return 'test $(sudo -u postgres psql postgres -tAc "{}") -eq {}'.format(
statement, lines
)
machine.start()
machine.wait_for_unit("postgresql")
with subtest("Postgresql with extension citus is available just after unit start"):
machine.succeed(
"sudo -u postgres psql -f ${test-sql}"
)
machine.succeed(check_count("SELECT count(*) FROM examples;", 1000))
machine.shutdown()
'';
};
in
genTests {
inherit makeTestFor;
filter = _: p: !p.pkgs.citus.meta.broken;
}
+20 -1
View File
@@ -7,7 +7,25 @@
with import ../../lib/testing-python.nix { inherit system pkgs; };
let
importWithArgs = path: import path { inherit pkgs makeTest; };
inherit (pkgs.lib)
recurseIntoAttrs
filterAttrs
mapAttrs
const
;
genTests =
{
makeTestFor,
filter ? (_: _: true),
}:
recurseIntoAttrs (
mapAttrs (const makeTestFor) (filterAttrs filter pkgs.postgresqlVersions)
// {
passthru.override = makeTestFor;
}
);
importWithArgs = path: import path { inherit pkgs makeTest genTests; };
in
{
# postgresql
@@ -18,6 +36,7 @@ in
# extensions
anonymizer = importWithArgs ./anonymizer.nix;
citus = importWithArgs ./citus.nix;
pgjwt = importWithArgs ./pgjwt.nix;
pgvecto-rs = importWithArgs ./pgvecto-rs.nix;
timescaledb = importWithArgs ./timescaledb.nix;
+5 -8
View File
@@ -1,6 +1,7 @@
{
pkgs,
makeTest,
genTests,
}:
let
@@ -48,11 +49,7 @@ let
'';
};
in
lib.recurseIntoAttrs (
lib.concatMapAttrs (n: p: { ${n} = makeTestFor p; }) (
lib.filterAttrs (_: p: p ? pkgs && !p.pkgs.pgjwt.meta.broken) pkgs.postgresqlVersions
)
// {
passthru.override = p: makeTestFor p;
}
)
genTests {
inherit makeTestFor;
filter = _: p: !p.pkgs.pgjwt.meta.broken;
}
+5 -8
View File
@@ -1,6 +1,7 @@
{
pkgs,
makeTest,
genTests,
}:
let
@@ -72,11 +73,7 @@ let
'';
};
in
lib.recurseIntoAttrs (
lib.concatMapAttrs (n: p: { ${n} = makeTestFor p; }) (
lib.filterAttrs (_: p: p ? pkgs && !p.pkgs.pgvecto-rs.meta.broken) pkgs.postgresqlVersions
)
// {
passthru.override = p: makeTestFor p;
}
)
genTests {
inherit makeTestFor;
filter = _: p: !p.pkgs.pgvecto-rs.meta.broken;
}
+5 -8
View File
@@ -1,6 +1,7 @@
{
pkgs,
makeTest,
genTests,
}:
let
@@ -48,11 +49,7 @@ let
'';
};
in
lib.recurseIntoAttrs (
lib.concatMapAttrs (n: p: { ${n} = makeTestFor p; }) (
lib.filterAttrs (n: _: lib.hasSuffix "_jit" n) pkgs.postgresqlVersions
)
// {
passthru.override = p: makeTestFor p;
}
)
genTests {
inherit makeTestFor;
filter = n: _: lib.hasSuffix "_jit" n;
}
@@ -1,6 +1,7 @@
{
pkgs,
makeTest,
genTests,
}:
let
@@ -128,11 +129,4 @@ let
'';
};
in
lib.recurseIntoAttrs (
lib.concatMapAttrs (n: p: { ${n} = makeTestFor p; }) (
lib.filterAttrs (_: p: p ? pkgs) pkgs.postgresqlVersions
)
// {
passthru.override = p: makeTestFor p;
}
)
genTests { inherit makeTestFor; }
@@ -1,6 +1,7 @@
{
pkgs,
makeTest,
genTests,
}:
let
@@ -108,11 +109,4 @@ let
'';
};
in
lib.recurseIntoAttrs (
lib.concatMapAttrs (n: p: { ${n} = makeTestFor p; }) (
lib.filterAttrs (_: p: p ? pkgs) pkgs.postgresqlVersions
)
// {
passthru.override = p: makeTestFor p;
}
)
genTests { inherit makeTestFor; }
+2 -8
View File
@@ -1,6 +1,7 @@
{
pkgs,
makeTest,
genTests,
}:
let
@@ -262,11 +263,4 @@ let
'';
};
in
lib.recurseIntoAttrs (
lib.concatMapAttrs (n: p: { ${n} = makeTestFor p; }) (
lib.filterAttrs (_: p: p ? pkgs) pkgs.postgresqlVersions
)
// {
passthru.override = p: makeTestFor p;
}
)
genTests { inherit makeTestFor; }
+5 -8
View File
@@ -1,6 +1,7 @@
{
pkgs,
makeTest,
genTests,
}:
let
@@ -91,11 +92,7 @@ in
# Not run by default, because this requires allowUnfree.
# To run these tests:
# NIXPKGS_ALLOW_UNFREE=1 nix-build -A nixosTests.postgresql.timescaledb
lib.dontRecurseIntoAttrs (
lib.concatMapAttrs (n: p: { ${n} = makeTestFor p; }) (
lib.filterAttrs (_: p: p ? pkgs && !p.pkgs.timescaledb.meta.broken) pkgs.postgresqlVersions
)
// {
passthru.override = p: makeTestFor p;
}
)
lib.dontRecurseIntoAttrs (genTests {
inherit makeTestFor;
filter = _: p: !p.pkgs.timescaledb.meta.broken;
})
+5 -8
View File
@@ -1,6 +1,7 @@
{
pkgs,
makeTest,
genTests,
}:
let
@@ -41,11 +42,7 @@ let
'';
};
in
lib.recurseIntoAttrs (
lib.concatMapAttrs (n: p: { ${n} = makeTestFor p; }) (
lib.filterAttrs (_: p: p ? pkgs && !p.pkgs.tsja.meta.broken) pkgs.postgresqlVersions
)
// {
passthru.override = p: makeTestFor p;
}
)
genTests {
inherit makeTestFor;
filter = _: p: !p.pkgs.tsja.meta.broken;
}
+5 -8
View File
@@ -1,6 +1,7 @@
{
pkgs,
makeTest,
genTests,
}:
let
@@ -43,11 +44,7 @@ let
'';
};
in
lib.recurseIntoAttrs (
lib.concatMapAttrs (n: p: { ${n} = makeTestFor p; }) (
lib.filterAttrs (_: p: p ? pkgs && !p.pkgs.wal2json.meta.broken) pkgs.postgresqlVersions
)
// {
passthru.override = p: makeTestFor p;
}
)
genTests {
inherit makeTestFor;
filter = _: p: !p.pkgs.wal2json.meta.broken;
}
+17
View File
@@ -732,6 +732,23 @@ in {
out = switch_to_specialisation("${machine}", "modifiedSystemConf")
assert_contains(out, "starting the following units: ${dbusService}\n")
with subtest("aborts on already locked lock file"):
(exitcode, _) = machine.execute(
'flock -x --nb /run/nixos/switch-to-configuration.lock -c "${otherSystem}/bin/switch-to-configuration test"',
timeout=5
)
# See man timeout, exit codes above 124 come from the timeout command
# We want to make sure that stc actually exited with an error code,
# if instead we hit the timeout, then it means that stc hangs, which is
# what we don't want
# TODO: We cannot match on the exact exit code since it's not consistent between
# stc and stc-ng, since errno/last_os_error is not a very stable interface,
# we should probably get rid of that in stc-ng once we got rid of the
# perl implementation
assert exitcode < 124, \
"switch-to-configuration did not abort as expected, " + \
f"probably it timed out instead (exit code: {exitcode}), 124 means timeout"
with subtest("fstab mounts"):
switch_to_specialisation("${machine}", "")
# add a mountpoint
+138
View File
@@ -0,0 +1,138 @@
import ../../make-test-python.nix (
{ lib, pkgs, ... }:
# Tests basics such as TLS, creating a mime-type & serving Unicode characters.
let
domain = {
HTTP = "h2o.local";
TLS = "acme.test";
};
port = {
HTTP = 8080;
TLS = 8443;
};
sawatdi_chao_lok = "";
hello_world_txt = pkgs.writeTextFile {
name = "/hello_world.txt";
text = sawatdi_chao_lok;
};
hello_world_rst = pkgs.writeTextFile {
name = "/hello_world.rst";
text = # rst
''
====================
Thaiger Sprint 2025
====================
${sawatdi_chao_lok}
'';
};
in
{
name = "h2o-basic";
meta = {
maintainers = with lib.maintainers; [ toastal ];
};
nodes = {
server =
{ pkgs, ... }:
{
services.h2o = {
enable = true;
defaultHTTPListenPort = port.HTTP;
defaultTLSListenPort = port.TLS;
hosts = {
"${domain.HTTP}" = {
settings = {
paths = {
"/hello_world.txt" = {
"file.file" = "${hello_world_txt}";
};
};
};
};
"${domain.TLS}" = {
tls = {
policy = "force";
identity = [
{
key-file = ../../common/acme/server/acme.test.key.pem;
certificate-file = ../../common/acme/server/acme.test.cert.pem;
}
];
extraSettings = {
minimum-version = "TLSv1.3";
};
};
settings = {
paths = {
"/hello_world.rst" = {
"file.file" = "${hello_world_rst}";
};
};
};
};
};
settings = {
compress = "ON";
compress-minimum-size = 32;
"file.mime.addtypes" = {
"text/x-rst" = {
extensions = [ ".rst" ];
is_compressible = "YES";
};
};
ssl-offload = "kernel";
};
};
security.pki.certificates = [
(builtins.readFile ../../common/acme/server/ca.cert.pem)
];
networking = {
firewall.allowedTCPPorts = with port; [
HTTP
TLS
];
extraHosts = ''
127.0.0.1 ${domain.HTTP}
127.0.0.1 ${domain.TLS}
'';
};
};
};
testScript = # python
''
server.wait_for_unit("h2o.service")
http_hello_world_body = server.succeed("curl --fail-with-body 'http://${domain.HTTP}:${builtins.toString port.HTTP}/hello_world.txt'")
assert "${sawatdi_chao_lok}" in http_hello_world_body
tls_hello_world_head = server.succeed("curl -v --head --compressed --http2 --tlsv1.3 --fail-with-body 'https://${domain.TLS}:${builtins.toString port.TLS}/hello_world.rst'").lower()
print(tls_hello_world_head)
assert "http/2 200" in tls_hello_world_head
assert "server: h2o" in tls_hello_world_head
assert "content-type: text/x-rst" in tls_hello_world_head
tls_hello_world_body = server.succeed("curl -v --http2 --tlsv1.3 --compressed --fail-with-body 'https://${domain.TLS}:${builtins.toString port.TLS}/hello_world.rst'")
assert "${sawatdi_chao_lok}" in tls_hello_world_body
tls_hello_world_head_redirected = server.succeed("curl -v --head --fail-with-body 'http://${domain.TLS}:${builtins.toString port.HTTP}/hello_world.rst'").lower()
assert "redirected" in tls_hello_world_head_redirected
server.fail("curl --location --max-redirs 0 'http://${domain.TLS}:${builtins.toString port.HTTP}/hello_world.rst'")
tls_hello_world_body_redirected = server.succeed("curl -v --location --fail-with-body 'http://${domain.TLS}:${builtins.toString port.HTTP}/hello_world.rst'")
assert "${sawatdi_chao_lok}" in tls_hello_world_body_redirected
'';
}
)
+16
View File
@@ -0,0 +1,16 @@
{
system ? builtins.currentSystem,
handleTestOn,
}:
let
supportedSystems = [
"x86_64-linux"
"i686-linux"
"aarch64-linux"
];
in
{
basic = handleTestOn supportedSystems ./basic.nix { inherit system; };
mruby = handleTestOn supportedSystems ./mruby.nix { inherit system; };
}
@@ -0,0 +1,3 @@
Proc.new do |env|
[200, {'content-type' => 'text/plain'}, ["FILE_HANDLER"]]
end
+64
View File
@@ -0,0 +1,64 @@
import ../../make-test-python.nix (
{ lib, pkgs, ... }:
let
domain = "h2o.local";
port = 8080;
sawatdi_chao_lok = "";
in
{
name = "h2o-mruby";
meta = {
maintainers = with lib.maintainers; [ toastal ];
};
nodes = {
server =
{ pkgs, ... }:
{
services.h2o = {
enable = true;
package = pkgs.h2o.override { withMruby = true; };
settings = {
listen = port;
hosts = {
"${domain}" = {
paths = {
"/hello_world" = {
"mruby.handler" = # ruby
''
Proc.new do |env|
[200, {'content-type' => 'text/plain'}, ["${sawatdi_chao_lok}"]]
end
'';
};
"/file_handler" = {
"mruby.handler-file" = ./file_handler.rb;
};
};
};
};
};
};
networking.extraHosts = ''
127.0.0.1 ${domain}
'';
};
};
testScript = # python
''
server.wait_for_unit("h2o.service")
hello_world = server.succeed("curl --fail-with-body http://${domain}:${builtins.toString port}/hello_world")
assert "${sawatdi_chao_lok}" in hello_world
file_handler = server.succeed("curl --fail-with-body http://${domain}:${builtins.toString port}/file_handler")
assert "FILE_HANDLER" in file_handler
'';
}
)
+2 -2
View File
@@ -44,11 +44,11 @@
stdenv.mkDerivation (finalAttrs: {
pname = "amarok";
version = "3.1.1";
version = "3.2.2";
src = fetchurl {
url = "mirror://kde/stable/amarok/${finalAttrs.version}/amarok-${finalAttrs.version}.tar.xz";
sha256 = "sha256-CrilxE8v6OcEdnWlfmQM54fxyAE0rB5VX8vvzZRyLmY=";
sha256 = "sha256-/N48N9H4FezIiTD+bR6k1LCx7Tsz/NMt9VQq+HTdKrA=";
};
outputs = [
@@ -5,13 +5,13 @@
stdenv.mkDerivation rec {
pname = "fluidsynth";
version = "2.4.2";
version = "2.4.3";
src = fetchFromGitHub {
owner = "FluidSynth";
repo = "fluidsynth";
rev = "v${version}";
hash = "sha256-rpTL1eOm3PQIBuxoPEZwj64QXasNQN80kGSW7h6dDdw=";
hash = "sha256-LaJcWrHgt/RzlDQmpzOjF/9ugD5d+8XWRt7pU3SM5Rk=";
};
outputs = [ "out" "dev" "man" ];
@@ -13,18 +13,18 @@
stdenv.mkDerivation (finalAttrs: {
pname = "youtube-music";
version = "3.7.2";
version = "3.7.4";
src = fetchFromGitHub {
owner = "th-ch";
repo = "youtube-music";
rev = "v${finalAttrs.version}";
hash = "sha256-gZ3EvIjPa/THRwMigglGp+Wtv+wEN7V11KOu1QsyJpE=";
hash = "sha256-qzvfYxM5mxxujWE0SDUapmN+Px9NkP58e1UeLEtZ7bc=";
};
pnpmDeps = pnpm.fetchDeps {
inherit (finalAttrs) pname version src;
hash = "sha256-4yeLfolBquKFjKB4iYj8rMPvclfpjwHhV6/Xb/YNQWo=";
hash = "sha256-guD1yWFd+uO9H/egHS0PJ9HIIlF+wFS/98YtvjIzZW8=";
};
nativeBuildInputs = [
@@ -23,7 +23,7 @@
trezorSupport ? true,
hidapi,
libusb1,
protobuf_21,
protobuf,
udev,
}:
@@ -96,7 +96,7 @@ stdenv.mkDerivation rec {
python3
hidapi
libusb1
protobuf_21
protobuf
]
++ lib.optionals (trezorSupport && stdenv.hostPlatform.isLinux) [ udev ];
@@ -138,5 +138,7 @@ stdenv.mkDerivation rec {
rnhmjoj
];
mainProgram = "monero-wallet-cli";
# internal build tool generate_translations_header is tricky to compile for the build platform
broken = !stdenv.buildPlatform.canExecute stdenv.hostPlatform;
};
}
@@ -30,7 +30,7 @@
trezorSupport ? true,
hidapi,
libusb1,
protobuf_21,
protobuf,
python3,
udev,
}:
@@ -77,7 +77,7 @@ stdenv.mkDerivation rec {
++ lib.optionals trezorSupport [
hidapi
libusb1
protobuf_21
protobuf
python3
]
++ lib.optionals (trezorSupport && stdenv.hostPlatform.isLinux) [
@@ -5,7 +5,6 @@
stdenv,
emacs,
texinfo,
writeText,
}:
let
@@ -15,43 +14,43 @@ let
stdenv
emacs
texinfo
writeText
;
};
libBuildHelper = import ./lib-build-helper.nix;
in
libBuildHelper.extendMkDerivation' genericBuild (
finalAttrs:
lib.extendMkDerivation {
constructDrv = genericBuild;
extendDrvArgs =
finalAttrs:
{
pname,
dontUnpack ? true,
meta ? { },
...
}@args:
{
pname,
dontUnpack ? true,
meta ? { },
...
}@args:
{
{
elpa2nix = args.elpa2nix or ./elpa2nix.el;
elpa2nix = args.elpa2nix or ./elpa2nix.el;
inherit dontUnpack;
inherit dontUnpack;
installPhase =
args.installPhase or ''
runHook preInstall
installPhase =
args.installPhase or ''
runHook preInstall
emacs --batch -Q -l "$elpa2nix" \
-f elpa2nix-install-package \
"$src" "$out/share/emacs/site-lisp/elpa"
emacs --batch -Q -l "$elpa2nix" \
-f elpa2nix-install-package \
"$src" "$out/share/emacs/site-lisp/elpa"
runHook postInstall
'';
runHook postInstall
'';
meta = {
homepage = args.src.meta.homepage or "https://elpa.gnu.org/packages/${pname}.html";
} // meta;
}
meta = {
homepage = args.src.meta.homepage or "https://elpa.gnu.org/packages/${pname}.html";
} // meta;
};
)
}
@@ -5,122 +5,106 @@
stdenv,
emacs,
texinfo,
writeText,
...
}:
let
inherit (lib) optionalAttrs;
setupHook = writeText "setup-hook.sh" ''
source ${./emacs-funcs.sh}
if [[ ! -v emacsHookDone ]]; then
emacsHookDone=1
# If this is for a wrapper derivation, emacs and the dependencies are all
# run-time dependencies. If this is for precompiling packages into bytecode,
# emacs is a compile-time dependency of the package.
addEnvHooks "$hostOffset" addEmacsVars
addEnvHooks "$targetOffset" addEmacsVars
fi
'';
libBuildHelper = import ./lib-build-helper.nix;
in
libBuildHelper.extendMkDerivation' stdenv.mkDerivation (
finalAttrs:
lib.extendMkDerivation {
constructDrv = stdenv.mkDerivation;
extendDrvArgs =
finalAttrs:
{
buildInputs ? [ ],
nativeBuildInputs ? [ ],
packageRequires ? [ ],
propagatedBuildInputs ? [ ],
propagatedUserEnvPkgs ? [ ],
postInstall ? "",
meta ? { },
turnCompilationWarningToError ? false,
ignoreCompilationError ? false,
...
}@args:
{
buildInputs ? [ ],
nativeBuildInputs ? [ ],
packageRequires ? [ ],
propagatedBuildInputs ? [ ],
propagatedUserEnvPkgs ? [ ],
postInstall ? "",
meta ? { },
turnCompilationWarningToError ? false,
ignoreCompilationError ? false,
...
}@args:
{
name = args.name or "emacs-${finalAttrs.pname}-${finalAttrs.version}";
{
name = args.name or "emacs-${finalAttrs.pname}-${finalAttrs.version}";
unpackCmd =
args.unpackCmd or ''
case "$curSrc" in
*.el)
# keep original source filename without the hash
local filename=$(basename "$curSrc")
filename="''${filename:33}"
cp $curSrc $filename
chmod +w $filename
sourceRoot="."
;;
*)
_defaultUnpack "$curSrc"
;;
esac
'';
unpackCmd =
args.unpackCmd or ''
case "$curSrc" in
*.el)
# keep original source filename without the hash
local filename=$(basename "$curSrc")
filename="''${filename:33}"
cp $curSrc $filename
chmod +w $filename
sourceRoot="."
;;
*)
_defaultUnpack "$curSrc"
;;
esac
'';
inherit packageRequires;
buildInputs = finalAttrs.packageRequires ++ buildInputs;
nativeBuildInputs = [
emacs
texinfo
] ++ nativeBuildInputs;
propagatedBuildInputs = finalAttrs.packageRequires ++ propagatedBuildInputs;
propagatedUserEnvPkgs = finalAttrs.packageRequires ++ propagatedUserEnvPkgs;
inherit packageRequires;
buildInputs = [ emacs ] ++ buildInputs;
nativeBuildInputs = [
emacs
texinfo
] ++ nativeBuildInputs;
propagatedBuildInputs = finalAttrs.packageRequires ++ propagatedBuildInputs;
propagatedUserEnvPkgs = finalAttrs.packageRequires ++ propagatedUserEnvPkgs;
setupHook = args.setupHook or setupHook;
strictDeps = args.strictDeps or true;
inherit turnCompilationWarningToError ignoreCompilationError;
inherit turnCompilationWarningToError ignoreCompilationError;
meta =
{
broken = false;
platforms = emacs.meta.platforms;
}
// optionalAttrs ((args.src.meta.homepage or "") != "") {
homepage = args.src.meta.homepage;
}
// meta;
}
meta =
{
broken = false;
platforms = emacs.meta.platforms;
}
// optionalAttrs ((args.src.meta.homepage or "") != "") {
homepage = args.src.meta.homepage;
}
// meta;
}
// optionalAttrs (emacs.withNativeCompilation or false) {
// optionalAttrs (emacs.withNativeCompilation or false) {
addEmacsNativeLoadPath = args.addEmacsNativeLoadPath or true;
addEmacsNativeLoadPath = args.addEmacsNativeLoadPath or true;
postInstall =
''
# Besides adding the output directory to the native load path, make sure
# the current package's elisp files are in the load path, otherwise
# (require 'file-b) from file-a.el in the same package will fail.
mkdir -p $out/share/emacs/native-lisp
source ${./emacs-funcs.sh}
addEmacsVars "$out"
postInstall =
''
# Besides adding the output directory to the native load path, make sure
# the current package's elisp files are in the load path, otherwise
# (require 'file-b) from file-a.el in the same package will fail.
mkdir -p $out/share/emacs/native-lisp
addEmacsVars "$out"
# package-activate-all is used to activate packages. In other builder
# helpers, package-initialize is used for this purpose because
# package-activate-all is not available before Emacs 27.
find $out/share/emacs -type f -name '*.el' -not -name ".dir-locals.el" -print0 \
| xargs --verbose -0 -I {} -n 1 -P $NIX_BUILD_CORES sh -c \
"emacs \
--batch \
-f package-activate-all \
--eval '(setq native-comp-eln-load-path (cdr native-comp-eln-load-path))' \
--eval '(let ((default-directory \"$out/share/emacs/site-lisp\")) (normal-top-level-add-subdirs-to-load-path))' \
--eval '(setq large-file-warning-threshold nil)' \
--eval '(setq byte-compile-error-on-warn ${
if finalAttrs.turnCompilationWarningToError then "t" else "nil"
})' \
-f batch-native-compile {} \
|| exit ${if finalAttrs.ignoreCompilationError then "0" else "\\$?"}"
''
+ postInstall;
}
# package-activate-all is used to activate packages. In other builder
# helpers, package-initialize is used for this purpose because
# package-activate-all is not available before Emacs 27.
find $out/share/emacs -type f -name '*.el' -not -name ".dir-locals.el" -print0 \
| xargs --verbose -0 -I {} -n 1 -P $NIX_BUILD_CORES sh -c \
"emacs \
--batch \
-f package-activate-all \
--eval '(setq native-comp-eln-load-path (cdr native-comp-eln-load-path))' \
--eval '(let ((default-directory \"$out/share/emacs/site-lisp\")) (normal-top-level-add-subdirs-to-load-path))' \
--eval '(setq large-file-warning-threshold nil)' \
--eval '(setq byte-compile-error-on-warn ${
if finalAttrs.turnCompilationWarningToError then "t" else "nil"
})' \
-f batch-native-compile {} \
|| exit ${if finalAttrs.ignoreCompilationError then "0" else "\\$?"}"
''
+ postInstall;
};
)
}

Some files were not shown because too many files have changed in this diff Show More