Merge commit bbdc2b27 into haskell-updates
This commit is contained in:
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -229,3 +229,9 @@ adb9714bd909df283c66bbd641bd631ff50a4260
|
||||
|
||||
# tmuxPlugins sha-to-sri.py script
|
||||
516b1e74c358a9c4b06e5591f8c1a2897aad0c33
|
||||
|
||||
# treewide: migrate comments in lib to rfc145 style
|
||||
ef85e0daa092c9eae0d32c7ce16b889728a5fbc0
|
||||
d89ad6c70e0e89aaae75e9f886878ea4e103965a
|
||||
e0fe216f4912dd88a021d12a44155fd2cfeb31c8
|
||||
80d5b411f6397d5c3e755a0635d95742f76f3c75
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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,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: {}
|
||||
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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`.
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 ======
|
||||
|
||||
@@ -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
@@ -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
@@ -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:
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" ];
|
||||
|
||||
@@ -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.";
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ];
|
||||
};
|
||||
}
|
||||
@@ -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 ];
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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}") {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -437,6 +437,7 @@ let
|
||||
(assertKeyIsSystemdCredential "PresharedKey")
|
||||
(assertOnlyFields [
|
||||
"PublicKey"
|
||||
"PublicKeyFile"
|
||||
"PresharedKey"
|
||||
"PresharedKeyFile"
|
||||
"AllowedIPs"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ''
|
||||
|
||||
@@ -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"
|
||||
'';
|
||||
}
|
||||
@@ -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 { };
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
)
|
||||
@@ -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
@@ -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}/")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
'';
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
})
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
'';
|
||||
}
|
||||
)
|
||||
@@ -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
|
||||
@@ -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
|
||||
'';
|
||||
}
|
||||
)
|
||||
@@ -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
Reference in New Issue
Block a user