Merge branch 'NixOS:master' into patch-1

This commit is contained in:
Sam Grayson 2023-10-25 23:09:33 -05:00 committed by GitHub
commit 14ffe0e240
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4440 changed files with 111746 additions and 59727 deletions

10
.github/CODEOWNERS vendored
View File

@ -24,10 +24,10 @@
# Libraries
/lib @edolstra @infinisil
/lib/systems @alyssais @ericson2314 @amjoseph-nixpkgs
/lib/generators.nix @edolstra @Profpatsch
/lib/cli.nix @edolstra @Profpatsch
/lib/debug.nix @edolstra @Profpatsch
/lib/asserts.nix @edolstra @Profpatsch
/lib/generators.nix @infinisil @edolstra @Profpatsch
/lib/cli.nix @infinisil @edolstra @Profpatsch
/lib/debug.nix @infinisil @edolstra @Profpatsch
/lib/asserts.nix @infinisil @edolstra @Profpatsch
/lib/path.* @infinisil @fricklerhandwerk
/lib/fileset @infinisil
/doc/functions/fileset.section.md @infinisil
@ -53,7 +53,7 @@
/pkgs/test/nixpkgs-check-by-name @infinisil
/pkgs/by-name/README.md @infinisil
/pkgs/top-level/by-name-overlay.nix @infinisil
/.github/workflows/check-by-name.nix @infinisil
/.github/workflows/check-by-name.yml @infinisil
# Nixpkgs build-support
/pkgs/build-support/writers @lassulus @Profpatsch

View File

@ -14,7 +14,9 @@ For new packages please briefly describe the package or provide a link to its ho
- [ ] aarch64-linux
- [ ] x86_64-darwin
- [ ] aarch64-darwin
- [ ] For non-Linux: Is `sandbox = true` set in `nix.conf`? (See [Nix manual](https://nixos.org/manual/nix/stable/command-ref/conf-file.html))
- For non-Linux: Is sandboxing enabled in `nix.conf`? (See [Nix manual](https://nixos.org/manual/nix/stable/command-ref/conf-file.html))
- [ ] `sandbox = relaxed`
- [ ] `sandbox = true`
- [ ] Tested, as applicable:
- [NixOS test(s)](https://nixos.org/manual/nixos/unstable/index.html#sec-nixos-tests) (look inside [nixos/tests](https://github.com/NixOS/nixpkgs/blob/master/nixos/tests))
- and/or [package tests](https://nixos.org/manual/nixpkgs/unstable/#sec-package-tests)

View File

@ -18,12 +18,34 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Resolving the merge commit
env:
GH_TOKEN: ${{ github.token }}
run: |
if result=$(git ls-remote --exit-code ${{ github.event.pull_request.base.repo.clone_url }} refs/pull/${{ github.event.pull_request.number }}/merge); then
mergedSha=$(cut -f1 <<< "$result")
echo "The PR appears to not have any conflicts, checking the merge commit $mergedSha"
# This checks for mergeability of a pull request as recommended in
# https://docs.github.com/en/rest/guides/using-the-rest-api-to-interact-with-your-git-database?apiVersion=2022-11-28#checking-mergeability-of-pull-requests
while true; do
echo "Checking whether the pull request can be merged"
prInfo=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/"$GITHUB_REPOSITORY"/pulls/${{ github.event.pull_request.number }})
mergeable=$(jq -r .mergeable <<< "$prInfo")
mergedSha=$(jq -r .merge_commit_sha <<< "$prInfo")
if [[ "$mergeable" == "null" ]]; then
# null indicates that GitHub is still computing whether it's mergeable
# Wait a couple seconds before trying again
echo "GitHub is still computing whether this PR can be merged, waiting 5 seconds before trying again"
sleep 5
else
break
fi
done
if [[ "$mergeable" == "true" ]]; then
echo "The PR can be merged, checking the merge commit $mergedSha"
else
echo "The PR may have a merge conflict"
echo "The PR cannot be merged, it has a merge conflict"
exit 1
fi
echo "mergedSha=$mergedSha" >> "$GITHUB_ENV"

View File

@ -538,7 +538,7 @@ To get a sense for what changes are considered mass rebuilds, see [previously me
When adding yourself as maintainer, in the same pull request, make a separate
commit with the message `maintainers: add <handle>`.
Add the commit before those making changes to the package or module.
See [Nixpkgs Maintainers](../maintainers/README.md) for details.
See [Nixpkgs Maintainers](./maintainers/README.md) for details.
### Writing good commit messages
@ -565,7 +565,7 @@ Names of files and directories should be in lowercase, with dashes between words
- Do not use tab characters, i.e. configure your editor to use soft tabs. For instance, use `(setq-default indent-tabs-mode nil)` in Emacs. Everybody has different tab settings so its asking for trouble.
- Use `lowerCamelCase` for variable names, not `UpperCamelCase`. Note, this rule does not apply to package attribute names, which instead follow the rules in [](#sec-package-naming).
- Use `lowerCamelCase` for variable names, not `UpperCamelCase`. Note, this rule does not apply to package attribute names, which instead follow the rules in [package naming](./pkgs/README.md#package-naming).
- Function calls with attribute set arguments are written as

View File

@ -3,6 +3,7 @@
This directory houses the sources files for the Nixpkgs manual.
You can find the [rendered documentation for Nixpkgs `unstable` on nixos.org](https://nixos.org/manual/nixpkgs/unstable/).
The rendering tool is [nixos-render-docs](../pkgs/tools/nix/nixos-render-docs/src/nixos_render_docs), sometimes abbreviated `nrd`.
[Docs for Nixpkgs stable](https://nixos.org/manual/nixpkgs/stable/) are also available.

View File

@ -243,3 +243,26 @@ or
***
```
## `fetchFromBittorrent` {#fetchfrombittorrent}
`fetchFromBittorrent` expects two arguments. `url` which can either be a Magnet URI (Magnet Link) such as `magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c` or an HTTP URL pointing to a `.torrent` file. It can also take a `config` argument which will craft a `settings.json` configuration file and give it to `transmission`, the underlying program that is performing the fetch. The available config options for `transmission` can be found [here](https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md#options)
```
{ fetchFromBittorrent }:
fetchFromBittorrent {
config = { peer-limit-global = 100; };
url = "magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c";
sha256 = "";
}
```
### Parameters {#fetchfrombittorrent-parameters}
- `url`: Magnet URI (Magnet Link) such as `magnet:?xt=urn:btih:dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c` or an HTTP URL pointing to a `.torrent` file.
- `backend`: Which bittorrent program to use. Default: `"transmission"`. Valid values are `"rqbit"` or `"transmission"`. These are the two most suitable torrent clients for fetching in a fixed-output derivation at the time of writing, as they can be easily exited after usage. `rqbit` is written in Rust and has a smaller closure size than `transmission`, and the performance and peer discovery properties differs between these clients, requiring experimentation to decide upon which is the best.
- `config`: When using `transmission` as the `backend`, a json configuration can
be supplied to transmission. Refer to the [upstream documentation](https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md) for information on how to configure.

View File

@ -157,3 +157,17 @@ in the example below and rebuild.
You may make any other changes to your VM in this attribute set. For example,
you could enable Docker or X11 forwarding to your Darwin host.
## Troubleshooting the generated configuration {#sec-darwin-builder-troubleshoot}
The `linux-builder` package exposes the attributes `nixosConfig` and `nixosOptions` that allow you to inspect the generated NixOS configuration in the `nix repl`. For example:
```
$ nix repl --file ~/src/nixpkgs --argstr system aarch64-darwin
nix-repl> darwin.linux-builder.nixosConfig.nix.package
«derivation /nix/store/...-nix-2.17.0.drv»
nix-repl> :p darwin.linux-builder.nixosOptions.virtualisation.memorySize.definitionsWithLocations
[ { file = "/home/user/src/nixpkgs/nixos/modules/profiles/macos-builder.nix"; value = 3072; } ]
```

View File

@ -23,6 +23,7 @@ let
{ name = "sources"; description = "source filtering functions"; }
{ name = "cli"; description = "command-line serialization functions"; }
{ name = "gvariant"; description = "GVariant formatted string serialization functions"; }
{ name = "customisation"; description = "Functions to customise (derivation-related) functions, derivatons, or attribute sets"; }
];
};

View File

@ -12,6 +12,8 @@ If you are packaging a Flutter desktop application, use [`buildFlutterApplicatio
If the upstream source is missing a `pubspec.lock` file, you'll have to vendor one and specify it using `pubspecLockFile`. If it is needed, one will be generated for you and printed when attempting to build the derivation.
The `depsListFile` must always be provided when packaging in Nixpkgs. It will be generated and printed if the derivation is attempted to be built without one. Alternatively, `autoDepsList` may be set to `true` only when outside of Nixpkgs, as it relies on import-from-derivation.
The `dart` commands run can be overridden through `pubGetScript` and `dartCompileCommand`, you can also add flags using `dartCompileFlags` or `dartJitFlags`.
Dart supports multiple [outputs types](https://dart.dev/tools/dart-compile#types-of-output), you can choose between them using `dartOutputType` (defaults to `exe`). If you want to override the binaries path or the source path they come from, you can use `dartEntryPoints`. Outputs that require a runtime will automatically be wrapped with the relevant runtime (`dartaotruntime` for `aot-snapshot`, `dart run` for `jit-snapshot` and `kernel`, `node` for `js`), this can be overridden through `dartRuntimeCommand`.
@ -31,6 +33,7 @@ buildDartApplication rec {
};
pubspecLockFile = ./pubspec.lock;
depsListFile = ./deps.json;
vendorHash = "sha256-Atm7zfnDambN/BmmUf4BG0yUz/y6xWzf0reDw3Ad41s=";
}
```
@ -39,9 +42,7 @@ buildDartApplication rec {
The function `buildFlutterApplication` builds Flutter applications.
The deps.json file must always be provided when packaging in Nixpkgs. It will be generated and printed if the derivation is attempted to be built without one. Alternatively, `autoDepsList` may be set to `true` when outside of Nixpkgs, as it relies on import-from-derivation.
A `pubspec.lock` file must be available. See the [Dart documentation](#ssec-dart-applications) for more details.
See the [Dart documentation](#ssec-dart-applications) for more details on required files and arguments.
```nix
{ flutter, fetchFromGitHub }:

View File

@ -18,7 +18,7 @@ In the following is an example expression using `buildGoModule`, the following a
To avoid updating this field when dependencies change, run `go mod vendor` in your source repo and set `vendorHash = null;`
To obtain the actual hash, set `vendorHash = lib.fakeSha256;` and run the build ([more details here](#sec-source-hashes)).
To obtain the actual hash, set `vendorHash = lib.fakeHash;` and run the build ([more details here](#sec-source-hashes)).
- `proxyVendor`: Fetches (go mod download) and proxies the vendor directory. This is useful if your code depends on c code and go mod tidy does not include the needed sources to build or if any dependency has case-insensitive conflicts which will produce platform-dependent `vendorHash` checksums.
- `modPostBuild`: Shell commands to run after the build of the goModules executes `go mod vendor`, and before calculating fixed output derivation's `vendorHash` (or `vendorSha256`). Note that if you change this attribute, you need to update `vendorHash` (or `vendorSha256`) attribute.

View File

@ -161,6 +161,8 @@ git config --global url."https://github.com/".insteadOf git://github.com/
`buildNpmPackage` allows you to package npm-based projects in Nixpkgs without the use of an auto-generated dependencies file (as used in [node2nix](#javascript-node2nix)). It works by utilizing npm's cache functionality -- creating a reproducible cache that contains the dependencies of a project, and pointing npm to it.
Here's an example:
```nix
{ lib, buildNpmPackage, fetchFromGitHub }:
@ -191,6 +193,8 @@ buildNpmPackage rec {
}
```
In the default `installPhase` set by `buildNpmPackage`, it uses `npm pack --json --dry-run` to decide what files to install in `$out/lib/node_modules/$name/`, where `$name` is the `name` string defined in the package's `package.json`. Additionally, the `bin` and `man` keys in the source's `package.json` are used to decide what binaries and manpages are supposed to be installed. If these are not defined, `npm pack` may miss some files, and no binaries will be produced.
#### Arguments {#javascript-buildNpmPackage-arguments}
* `npmDepsHash`: The output hash of the dependencies for this project. Can be calculated in advance with [`prefetch-npm-deps`](#javascript-buildNpmPackage-prefetch-npm-deps).
@ -204,10 +208,11 @@ buildNpmPackage rec {
* `npmBuildFlags`: Flags to pass to `npm run ${npmBuildScript}`.
* `npmPackFlags`: Flags to pass to `npm pack`.
* `npmPruneFlags`: Flags to pass to `npm prune`. Defaults to the value of `npmInstallFlags`.
* `makeWrapperArgs`: Flags to pass to `makeWrapper`, added to executable calling the generated `.js` with `node` as an interpreter. These scripts are defined in `package.json`.
#### prefetch-npm-deps {#javascript-buildNpmPackage-prefetch-npm-deps}
`prefetch-npm-deps` can calculate the hash of the dependencies of an npm project ahead of time.
`prefetch-npm-deps` is a Nixpkgs package that calculates the hash of the dependencies of an npm project ahead of time.
```console
$ ls
@ -217,6 +222,15 @@ $ prefetch-npm-deps package-lock.json
sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
```
#### fetchNpmDeps {#javascript-buildNpmPackage-fetchNpmDeps}
`fetchNpmDeps` is a Nix function that requires the following mandatory arguments:
- `src`: A directory / tarball with `package-lock.json` file
- `hash`: The output hash of the node dependencies defined in `package-lock.json`.
It returns a derivation with all `package-lock.json` dependencies downloaded into `$out/`, usable as an npm cache.
### corepack {#javascript-corepack}
This package puts the corepack wrappers for pnpm and yarn in your PATH, and they will honor the `packageManager` setting in the `package.json`.

View File

@ -12,6 +12,7 @@
| python310 | python3 | CPython 3.10 |
| python311 | | CPython 3.11 |
| python312 | | CPython 3.12 |
| python313 | | CPython 3.13 |
| pypy27 | pypy2, pypy | PyPy2.7 |
| pypy39 | pypy3 | PyPy 3.9 |

View File

@ -817,7 +817,7 @@ $ cargo test
## Using community maintained Rust toolchains {#using-community-maintained-rust-toolchains}
::: {.note}
Note: The following projects cannot be used within nixpkgs since [IFD](#ssec-import-from-derivation) is disallowed.
The following projects cannot be used within Nixpkgs since [Import From Derivation](https://nixos.org/manual/nix/unstable/language/import-from-derivation) (IFD) is disallowed in Nixpkgs.
To package things that require Rust nightly, `RUSTC_BOOTSTRAP = true;` can sometimes be used as a hack.
:::

View File

@ -101,25 +101,62 @@ genericBuild
### Building a `stdenv` package in `nix-shell` {#sec-building-stdenv-package-in-nix-shell}
To build a `stdenv` package in a [`nix-shell`](https://nixos.org/manual/nix/unstable/command-ref/nix-shell.html), use
To build a `stdenv` package in a [`nix-shell`](https://nixos.org/manual/nix/unstable/command-ref/nix-shell.html), enter a shell, find the [phases](#sec-stdenv-phases) you wish to build, then invoke `genericBuild` manually:
Go to an empty directory, invoke `nix-shell` with the desired package, and from inside the shell, set the output variables to a writable directory:
```bash
cd "$(mktemp -d)"
nix-shell '<nixpkgs>' -A some_package
eval "${unpackPhase:-unpackPhase}"
cd $sourceRoot
eval "${patchPhase:-patchPhase}"
eval "${configurePhase:-configurePhase}"
eval "${buildPhase:-buildPhase}"
export out=$(pwd)/out
```
Next, invoke the desired parts of the build.
First, run the phases that generate a working copy of the sources, which will change directory to the sources for you:
```bash
phases="${prePhases[*]:-} unpackPhase patchPhase" genericBuild
```
Then, run more phases up until the failure is reached.
For example, if the failure is in the build phase, the following phases would be required:
```bash
phases="${preConfigurePhases[*]:-} configurePhase ${preBuildPhases[*]:-} buildPhase" genericBuild
```
Re-run a single phase as many times as necessary to examine the failure like so:
```bash
phases="buildPhase" genericBuild
```
To modify a [phase](#sec-stdenv-phases), first print it with
```bash
echo "$buildPhase"
```
Or, if that is empty, for instance, if it is using a function:
```bash
type buildPhase
```
then change it in a text editor, and paste it back to the terminal.
::: {.note}
This method may have some inconsistencies in environment variables and behaviour compared to a normal build within the [Nix build sandbox](https://nixos.org/manual/nix/unstable/language/derivations#builder-execution).
The following is a non-exhaustive list of such differences:
- `TMP`, `TMPDIR`, and similar variables likely point to non-empty directories that the build might conflict with files in.
- Output store paths are not writable, so the variables for outputs need to be overridden to writable paths.
- Other environment variables may be inconsistent with a `nix-build` either due to `nix-shell`'s initialization script or due to the use of `nix-shell` without the `--pure` option.
If the build fails differently inside the shell than in the sandbox, consider using [`breakpointHook`](#breakpointhook) and invoking `nix-build` instead.
The [`--keep-failed`](https://nixos.org/manual/nix/unstable/command-ref/conf-file#opt--keep-failed) option for `nix-build` may also be useful to examine the build directory of a failed build.
:::
## Tools provided by `stdenv` {#sec-tools-of-stdenv}
The standard environment provides the following packages:

View File

@ -542,6 +542,36 @@ rec {
attrs:
map (name: f name attrs.${name}) (attrNames attrs);
/*
Deconstruct an attrset to a list of name-value pairs as expected by [`builtins.listToAttrs`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-listToAttrs).
Each element of the resulting list is an attribute set with these attributes:
- `name` (string): The name of the attribute
- `value` (any): The value of the attribute
The following is always true:
```nix
builtins.listToAttrs (attrsToList attrs) == attrs
```
:::{.warning}
The opposite is not always true. In general expect that
```nix
attrsToList (builtins.listToAttrs list) != list
```
This is because the `listToAttrs` removes duplicate names and doesn't preserve the order of the list.
:::
Example:
attrsToList { foo = 1; bar = "asdf"; }
=> [ { name = "bar"; value = "asdf"; } { name = "foo"; value = 1; } ]
Type:
attrsToList :: AttrSet -> [ { name :: String; value :: Any; } ]
*/
attrsToList = mapAttrsToList nameValuePair;
/* Like `mapAttrs`, except that it recursively applies itself to
the *leaf* attributes of a potentially-nested attribute set:

View File

@ -13,16 +13,7 @@ rec {
scenarios (e.g. in ~/.config/nixpkgs/config.nix). For instance,
if you want to "patch" the derivation returned by a package
function in Nixpkgs to build another version than what the
function itself provides, you can do something like this:
mySed = overrideDerivation pkgs.gnused (oldAttrs: {
name = "sed-4.2.2-pre";
src = fetchurl {
url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2;
hash = "sha256-MxBJRcM2rYzQYwJ5XKxhXTQByvSg5jZc5cSHEZoB2IY=";
};
patches = [];
});
function itself provides.
For another application, see build-support/vm, where this
function is used to build arbitrary derivations inside a QEMU
@ -35,6 +26,19 @@ rec {
You should in general prefer `drv.overrideAttrs` over this function;
see the nixpkgs manual for more information on overriding.
Example:
mySed = overrideDerivation pkgs.gnused (oldAttrs: {
name = "sed-4.2.2-pre";
src = fetchurl {
url = ftp://alpha.gnu.org/gnu/sed/sed-4.2.2-pre.tar.bz2;
hash = "sha256-MxBJRcM2rYzQYwJ5XKxhXTQByvSg5jZc5cSHEZoB2IY=";
};
patches = [];
});
Type:
overrideDerivation :: Derivation -> ( Derivation -> AttrSet ) -> Derivation
*/
overrideDerivation = drv: f:
let
@ -55,6 +59,10 @@ rec {
injects `override` attribute which can be used to override arguments of
the function.
Please refer to documentation on [`<pkg>.overrideDerivation`](#sec-pkg-overrideDerivation) to learn about `overrideDerivation` and caveats
related to its use.
Example:
nix-repl> x = {a, b}: { result = a + b; }
nix-repl> y = lib.makeOverridable x { a = 1; b = 2; }
@ -65,12 +73,11 @@ rec {
nix-repl> y.override { a = 10; }
{ override = «lambda»; overrideDerivation = «lambda»; result = 12; }
Please refer to "Nixpkgs Contributors Guide" section
"<pkg>.overrideDerivation" to learn about `overrideDerivation` and caveats
related to its use.
Type:
makeOverridable :: (AttrSet -> a) -> AttrSet -> a
*/
makeOverridable = f: origArgs:
let
makeOverridable = f: lib.setFunctionArgs
(origArgs: let
result = f origArgs;
# Creates a functor with the same arguments as f
@ -95,7 +102,8 @@ rec {
lib.setFunctionArgs result (lib.functionArgs result) // {
override = overrideArgs;
}
else result;
else result)
(lib.functionArgs f);
/* Call the package function in the file `fn` with the required
@ -104,20 +112,29 @@ rec {
`autoArgs`. This function is intended to be partially
parameterised, e.g.,
```nix
callPackage = callPackageWith pkgs;
pkgs = {
libfoo = callPackage ./foo.nix { };
libbar = callPackage ./bar.nix { };
};
```
If the `libbar` function expects an argument named `libfoo`, it is
automatically passed as an argument. Overrides or missing
arguments can be supplied in `args`, e.g.
```nix
libbar = callPackage ./bar.nix {
libfoo = null;
enableX11 = true;
};
```
<!-- TODO: Apply "Example:" tag to the examples above -->
Type:
callPackageWith :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
*/
callPackageWith = autoArgs: fn: args:
let
@ -128,7 +145,7 @@ rec {
# This includes automatic ones and ones passed explicitly
allArgs = builtins.intersectAttrs fargs autoArgs // args;
# A list of argument names that the function requires, but
# a list of argument names that the function requires, but
# wouldn't be passed to it
missingArgs = lib.attrNames
# Filter out arguments that have a default value
@ -175,7 +192,11 @@ rec {
/* Like callPackage, but for a function that returns an attribute
set of derivations. The override function is added to the
individual attributes. */
individual attributes.
Type:
callPackagesWith :: AttrSet -> ((AttrSet -> AttrSet) | Path) -> AttrSet -> AttrSet
*/
callPackagesWith = autoArgs: fn: args:
let
f = if lib.isFunction fn then fn else import fn;
@ -192,7 +213,11 @@ rec {
/* Add attributes to each output of a derivation without changing
the derivation itself and check a given condition when evaluating. */
the derivation itself and check a given condition when evaluating.
Type:
extendDerivation :: Bool -> Any -> Derivation -> Derivation
*/
extendDerivation = condition: passthru: drv:
let
outputs = drv.outputs or [ "out" ];
@ -226,7 +251,11 @@ rec {
/* Strip a derivation of all non-essential attributes, returning
only those needed by hydra-eval-jobs. Also strictly evaluate the
result to ensure that there are no thunks kept alive to prevent
garbage collection. */
garbage collection.
Type:
hydraJob :: (Derivation | Null) -> (Derivation | Null)
*/
hydraJob = drv:
let
outputs = drv.outputs or ["out"];
@ -264,7 +293,11 @@ rec {
called with the overridden packages. The package sets may be
hierarchical: the packages in the set are called with the scope
provided by `newScope` and the set provides a `newScope` attribute
which can form the parent scope for later package sets. */
which can form the parent scope for later package sets.
Type:
makeScope :: (AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a) -> (AttrSet -> AttrSet) -> AttrSet
*/
makeScope = newScope: f:
let self = f self // {
newScope = scope: newScope (self // scope);
@ -286,7 +319,25 @@ rec {
{ inherit otherSplices keep extra f; };
/* Like makeScope, but aims to support cross compilation. It's still ugly, but
hopefully it helps a little bit. */
hopefully it helps a little bit.
Type:
makeScopeWithSplicing' ::
{ splicePackages :: Splice -> AttrSet
, newScope :: AttrSet -> ((AttrSet -> a) | Path) -> AttrSet -> a
}
-> { otherSplices :: Splice, keep :: AttrSet -> AttrSet, extra :: AttrSet -> AttrSet }
-> AttrSet
Splice ::
{ pkgsBuildBuild :: AttrSet
, pkgsBuildHost :: AttrSet
, pkgsBuildTarget :: AttrSet
, pkgsHostHost :: AttrSet
, pkgsHostTarget :: AttrSet
, pkgsTargetTarget :: AttrSet
}
*/
makeScopeWithSplicing' =
{ splicePackages
, newScope

View File

@ -81,8 +81,8 @@ let
inherit (self.attrsets) attrByPath hasAttrByPath setAttrByPath
getAttrFromPath attrVals attrValues getAttrs catAttrs filterAttrs
filterAttrsRecursive foldlAttrs foldAttrs collect nameValuePair mapAttrs
mapAttrs' mapAttrsToList concatMapAttrs mapAttrsRecursive mapAttrsRecursiveCond
genAttrs isDerivation toDerivation optionalAttrs
mapAttrs' mapAttrsToList attrsToList concatMapAttrs mapAttrsRecursive
mapAttrsRecursiveCond genAttrs isDerivation toDerivation optionalAttrs
zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil
recursiveUpdate matchAttrs overrideExisting showAttrPath getOutput getBin
getLib getDev getMan chooseDevOutputs zipWithNames zip

View File

@ -58,7 +58,8 @@ An attribute set with these values:
- `_internalBase` (path):
Any files outside of this path cannot influence the set of files.
This is always a directory.
This is always a directory and should be as long as possible.
This is used by `lib.fileset.toSource` to check that all files are under the `root` argument
- `_internalBaseRoot` (path):
The filesystem root of `_internalBase`, same as `(lib.path.splitRoot _internalBase).root`.
@ -143,9 +144,37 @@ Arguments:
- (-) Leaves us with no identity element for `union` and no reasonable return value for `unions []`.
From a set theory perspective, which has a well-known notion of empty sets, this is unintuitive.
### No intersection for lists
While there is `intersection a b`, there is no function `intersections [ a b c ]`.
Arguments:
- (+) There is no known use case for such a function, it can be added later if a use case arises
- (+) There is no suitable return value for `intersections [ ]`, see also "Nullary intersections" [here](https://en.wikipedia.org/w/index.php?title=List_of_set_identities_and_relations&oldid=1177174035#Definitions)
- (-) Could throw an error for that case
- (-) Create a special value to represent "all the files" and return that
- (+) Such a value could then not be used with `fileFilter` unless the internal representation is changed considerably
- (-) Could return the empty file set
- (+) This would be wrong in set theory
- (-) Inconsistent with `union` and `unions`
### Intersection base path
The base path of the result of an `intersection` is the longest base path of the arguments.
E.g. the base path of `intersection ./foo ./foo/bar` is `./foo/bar`.
Meanwhile `intersection ./foo ./bar` returns the empty file set without a base path.
Arguments:
- Alternative: Use the common prefix of all base paths as the resulting base path
- (-) This is unnecessarily strict, because the purpose of the base path is to track the directory under which files _could_ be in the file set. It should be as long as possible.
All files contained in `intersection ./foo ./foo/bar` will be under `./foo/bar` (never just under `./foo`), and `intersection ./foo ./bar` will never contain any files (never under `./.`).
This would lead to `toSource` having to unexpectedly throw errors for cases such as `toSource { root = ./foo; fileset = intersect ./foo base; }`, where `base` may be `./bar` or `./.`.
- (-) There is no benefit to the user, since base path is not directly exposed in the interface
### Empty directories
File sets can only represent a _set_ of local files, directories on their own are not representable.
File sets can only represent a _set_ of local files.
Directories on their own are not representable.
Arguments:
- (+) There does not seem to be a sensible set of combinators when directories can be represented on their own.
@ -161,7 +190,7 @@ Arguments:
- `./.` represents all files in `./.` _and_ the directory itself, but not its subdirectories, meaning that at least `./.` will be preserved even if it's empty.
In that case, `intersect ./. ./foo` should only include files and no directories themselves, since `./.` includes only `./.` as a directory, and same for `./foo`, so there's no overlap in directories.
In that case, `intersection ./. ./foo` should only include files and no directories themselves, since `./.` includes only `./.` as a directory, and same for `./foo`, so there's no overlap in directories.
But intuitively this operation should result in the same as `./foo` everything else is just confusing.
- (+) This matches how Git only supports files, so developers should already be used to it.
- (-) Empty directories (even if they contain nested directories) are neither representable nor preserved when coercing from paths.
@ -176,7 +205,7 @@ File sets do not support Nix store paths in strings such as `"/nix/store/...-sou
Arguments:
- (+) Such paths are usually produced by derivations, which means `toSource` would either:
- Require IFD if `builtins.path` is used as the underlying primitive
- Require [Import From Derivation](https://nixos.org/manual/nix/unstable/language/import-from-derivation) (IFD) if `builtins.path` is used as the underlying primitive
- Require importing the entire `root` into the store such that derivations can be used to do the filtering
- (+) The convenient path coercion like `union ./foo ./bar` wouldn't work for absolute paths, requiring more verbose alternate interfaces:
- `let root = "/nix/store/...-source"; in union "${root}/foo" "${root}/bar"`

View File

@ -6,7 +6,9 @@ let
_coerceMany
_toSourceFilter
_unionMany
_fileFilter
_printFileset
_intersection
;
inherit (builtins)
@ -18,6 +20,7 @@ let
;
inherit (lib.lists)
elemAt
imap0
;
@ -39,6 +42,7 @@ let
;
inherit (lib.trivial)
isFunction
pipe
;
@ -276,6 +280,94 @@ If a directory does not recursively contain any file, it is omitted from the sto
_unionMany
];
/*
Filter a file set to only contain files matching some predicate.
Type:
fileFilter ::
({
name :: String,
type :: String,
...
} -> Bool)
-> FileSet
-> FileSet
Example:
# Include all regular `default.nix` files in the current directory
fileFilter (file: file.name == "default.nix") ./.
# Include all non-Nix files from the current directory
fileFilter (file: ! hasSuffix ".nix" file.name) ./.
# Include all files that start with a "." in the current directory
fileFilter (file: hasPrefix "." file.name) ./.
# Include all regular files (not symlinks or others) in the current directory
fileFilter (file: file.type == "regular")
*/
fileFilter =
/*
The predicate function to call on all files contained in given file set.
A file is included in the resulting file set if this function returns true for it.
This function is called with an attribute set containing these attributes:
- `name` (String): The name of the file
- `type` (String, one of `"regular"`, `"symlink"` or `"unknown"`): The type of the file.
This matches result of calling [`builtins.readFileType`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-readFileType) on the file's path.
Other attributes may be added in the future.
*/
predicate:
# The file set to filter based on the predicate function
fileset:
if ! isFunction predicate then
throw "lib.fileset.fileFilter: Expected the first argument to be a function, but it's a ${typeOf predicate} instead."
else
_fileFilter predicate
(_coerce "lib.fileset.fileFilter: second argument" fileset);
/*
The file set containing all files that are in both of two given file sets.
See also [Intersection (set theory)](https://en.wikipedia.org/wiki/Intersection_(set_theory)).
The given file sets are evaluated as lazily as possible,
with the first argument being evaluated first if needed.
Type:
intersection :: FileSet -> FileSet -> FileSet
Example:
# Limit the selected files to the ones in ./., so only ./src and ./Makefile
intersection ./. (unions [ ../LICENSE ./src ./Makefile ])
*/
intersection =
# The first file set.
# This argument can also be a path,
# which gets [implicitly coerced to a file set](#sec-fileset-path-coercion).
fileset1:
# The second file set.
# This argument can also be a path,
# which gets [implicitly coerced to a file set](#sec-fileset-path-coercion).
fileset2:
let
filesets = _coerceMany "lib.fileset.intersection" [
{
context = "first argument";
value = fileset1;
}
{
context = "second argument";
value = fileset2;
}
];
in
_intersection
(elemAt filesets 0)
(elemAt filesets 1);
/*
Incrementally evaluate and trace a file set in a pretty way.
This function is only intended for debugging purposes.

View File

@ -172,11 +172,11 @@ rec {
else if ! isPath value then
if isStringLike value then
throw ''
${context} ("${toString value}") is a string-like value, but it should be a path instead.
${context} ("${toString value}") is a string-like value, but it should be a file set or a path instead.
Paths represented as strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.''
else
throw ''
${context} is of type ${typeOf value}, but it should be a path instead.''
${context} is of type ${typeOf value}, but it should be a file set or a path instead.''
else if ! pathExists value then
throw ''
${context} (${toString value}) does not exist.''
@ -461,6 +461,43 @@ rec {
else
nonEmpty;
# Transforms the filesetTree of a file set to a shorter base path, e.g.
# _shortenTreeBase [ "foo" ] (_create /foo/bar null)
# => { bar = null; }
_shortenTreeBase = targetBaseComponents: fileset:
let
recurse = index:
# If we haven't reached the required depth yet
if index < length fileset._internalBaseComponents then
# Create an attribute set and recurse as the value, this can be lazily evaluated this way
{ ${elemAt fileset._internalBaseComponents index} = recurse (index + 1); }
else
# Otherwise we reached the appropriate depth, here's the original tree
fileset._internalTree;
in
recurse (length targetBaseComponents);
# Transforms the filesetTree of a file set to a longer base path, e.g.
# _lengthenTreeBase [ "foo" "bar" ] (_create /foo { bar.baz = "regular"; })
# => { baz = "regular"; }
_lengthenTreeBase = targetBaseComponents: fileset:
let
recurse = index: tree:
# If the filesetTree is an attribute set and we haven't reached the required depth yet
if isAttrs tree && index < length targetBaseComponents then
# Recurse with the tree under the right component (which might not exist)
recurse (index + 1) (tree.${elemAt targetBaseComponents index} or null)
else
# For all values here we can just return the tree itself:
# tree == null -> the result is also null, everything is excluded
# tree == "directory" -> the result is also "directory",
# because the base path is always a directory and everything is included
# isAttrs tree -> the result is `tree`
# because we don't need to recurse any more since `index == length longestBaseComponents`
tree;
in
recurse (length fileset._internalBaseComponents) fileset._internalTree;
# Computes the union of a list of filesets.
# The filesets must already be coerced and validated to be in the same filesystem root
# Type: [ Fileset ] -> Fileset
@ -497,11 +534,7 @@ rec {
# So the tree under `/foo/bar` gets nested under `{ bar = ...; ... }`,
# while the tree under `/foo/baz` gets nested under `{ baz = ...; ... }`
# Therefore allowing combined operations over them.
trees = map (fileset:
setAttrByPath
(drop (length commonBaseComponents) fileset._internalBaseComponents)
fileset._internalTree
) filesetsWithBase;
trees = map (_shortenTreeBase commonBaseComponents) filesetsWithBase;
# Folds all trees together into a single one using _unionTree
# We do not use a fold here because it would cause a thunk build-up
@ -533,4 +566,102 @@ rec {
# The non-null elements have to be attribute sets representing partial trees
# We need to recurse into those
zipAttrsWith (name: _unionTrees) withoutNull;
# Computes the intersection of a list of filesets.
# The filesets must already be coerced and validated to be in the same filesystem root
# Type: Fileset -> Fileset -> Fileset
_intersection = fileset1: fileset2:
let
# The common base components prefix, e.g.
# (/foo/bar, /foo/bar/baz) -> /foo/bar
# (/foo/bar, /foo/baz) -> /foo
commonBaseComponentsLength =
# TODO: Have a `lib.lists.commonPrefixLength` function such that we don't need the list allocation from commonPrefix here
length (
commonPrefix
fileset1._internalBaseComponents
fileset2._internalBaseComponents
);
# To be able to intersect filesetTree's together, they need to have the same base path.
# Base paths can be intersected by taking the longest one (if any)
# The fileset with the longest base, if any, e.g.
# (/foo/bar, /foo/bar/baz) -> /foo/bar/baz
# (/foo/bar, /foo/baz) -> null
longestBaseFileset =
if commonBaseComponentsLength == length fileset1._internalBaseComponents then
# The common prefix is the same as the first path, so the second path is equal or longer
fileset2
else if commonBaseComponentsLength == length fileset2._internalBaseComponents then
# The common prefix is the same as the second path, so the first path is longer
fileset1
else
# The common prefix is neither the first nor the second path
# This means there's no overlap between the two sets
null;
# Whether the result should be the empty value without a base
resultIsEmptyWithoutBase =
# If either fileset is the empty fileset without a base, the intersection is too
fileset1._internalIsEmptyWithoutBase
|| fileset2._internalIsEmptyWithoutBase
# If there is no overlap between the base paths
|| longestBaseFileset == null;
# Lengthen each fileset's tree to the longest base prefix
tree1 = _lengthenTreeBase longestBaseFileset._internalBaseComponents fileset1;
tree2 = _lengthenTreeBase longestBaseFileset._internalBaseComponents fileset2;
# With two filesetTree's with the same base, we can compute their intersection
resultTree = _intersectTree tree1 tree2;
in
if resultIsEmptyWithoutBase then
_emptyWithoutBase
else
_create longestBaseFileset._internalBase resultTree;
# The intersection of two filesetTree's with the same base path
# The second element is only evaluated as much as necessary.
# Type: filesetTree -> filesetTree -> filesetTree
_intersectTree = lhs: rhs:
if isAttrs lhs && isAttrs rhs then
# Both sides are attribute sets, we can recurse for the attributes existing on both sides
mapAttrs
(name: _intersectTree lhs.${name})
(builtins.intersectAttrs lhs rhs)
else if lhs == null || isString rhs then
# If the lhs is null, the result should also be null
# And if the rhs is the identity element
# (a string, aka it includes everything), then it's also the lhs
lhs
else
# In all other cases it's the rhs
rhs;
_fileFilter = predicate: fileset:
let
recurse = path: tree:
mapAttrs (name: subtree:
if isAttrs subtree || subtree == "directory" then
recurse (path + "/${name}") subtree
else if
predicate {
inherit name;
type = subtree;
# To ensure forwards compatibility with more arguments being added in the future,
# adding an attribute which can't be deconstructed :)
"lib.fileset.fileFilter: The predicate function passed as the first argument must be able to handle extra attributes for future compatibility. If you're using `{ name, file }:`, use `{ name, file, ... }:` instead." = null;
}
then
subtree
else
null
) (_directoryEntries path tree);
in
if fileset._internalIsEmptyWithoutBase then
_emptyWithoutBase
else
_create fileset._internalBase
(recurse fileset._internalBase fileset._internalTree);
}

View File

@ -355,8 +355,8 @@ expectFailure 'toSource { root = ./a; fileset = ./.; }' 'lib.fileset.toSource: `
rm -rf *
# Path coercion only works for paths
expectFailure 'toSource { root = ./.; fileset = 10; }' 'lib.fileset.toSource: `fileset` is of type int, but it should be a path instead.'
expectFailure 'toSource { root = ./.; fileset = "/some/path"; }' 'lib.fileset.toSource: `fileset` \("/some/path"\) is a string-like value, but it should be a path instead.
expectFailure 'toSource { root = ./.; fileset = 10; }' 'lib.fileset.toSource: `fileset` is of type int, but it should be a file set or a path instead.'
expectFailure 'toSource { root = ./.; fileset = "/some/path"; }' 'lib.fileset.toSource: `fileset` \("/some/path"\) is a string-like value, but it should be a file set or a path instead.
\s*Paths represented as strings are not supported by `lib.fileset`, use `lib.sources` or derivations instead.'
# Path coercion errors for non-existent paths
@ -587,6 +587,164 @@ done
# So, just using 1000 files for now.
checkFileset 'unions (mapAttrsToList (name: _: ./. + "/${name}/a") (builtins.readDir ./.))'
## lib.fileset.intersection
# Different filesystem roots in root and fileset are not supported
mkdir -p {foo,bar}/mock-root
expectFailure 'with ((import <nixpkgs/lib>).extend (import <nixpkgs/lib/fileset/mock-splitRoot.nix>)).fileset;
toSource { root = ./.; fileset = intersection ./foo/mock-root ./bar/mock-root; }
' 'lib.fileset.intersection: Filesystem roots are not the same:
\s*first argument: root "'"$work"'/foo/mock-root"
\s*second argument: root "'"$work"'/bar/mock-root"
\s*Different roots are not supported.'
rm -rf -- *
# Coercion errors show the correct context
expectFailure 'toSource { root = ./.; fileset = intersection ./a ./.; }' 'lib.fileset.intersection: first argument \('"$work"'/a\) does not exist.'
expectFailure 'toSource { root = ./.; fileset = intersection ./. ./b; }' 'lib.fileset.intersection: second argument \('"$work"'/b\) does not exist.'
# The tree of later arguments should not be evaluated if a former argument already excludes all files
tree=(
[a]=0
)
checkFileset 'intersection _emptyWithoutBase (_create ./. (abort "This should not be used!"))'
# We don't have any combinators that can explicitly remove files yet, so we need to rely on internal functions to test this for now
checkFileset 'intersection (_create ./. { a = null; }) (_create ./. { a = abort "This should not be used!"; })'
# If either side is empty, the result is empty
tree=(
[a]=0
)
checkFileset 'intersection _emptyWithoutBase _emptyWithoutBase'
checkFileset 'intersection _emptyWithoutBase (_create ./. null)'
checkFileset 'intersection (_create ./. null) _emptyWithoutBase'
checkFileset 'intersection (_create ./. null) (_create ./. null)'
# If the intersection base paths are not overlapping, the result is empty and has no base path
mkdir a b c
touch {a,b,c}/x
expectEqual 'toSource { root = ./c; fileset = intersection ./a ./b; }' 'toSource { root = ./c; fileset = _emptyWithoutBase; }'
rm -rf -- *
# If the intersection exists, the resulting base path is the longest of them
mkdir a
touch x a/b
expectEqual 'toSource { root = ./a; fileset = intersection ./a ./.; }' 'toSource { root = ./a; fileset = ./a; }'
expectEqual 'toSource { root = ./a; fileset = intersection ./. ./a; }' 'toSource { root = ./a; fileset = ./a; }'
rm -rf -- *
# Also finds the intersection with null'd filesetTree's
tree=(
[a]=0
[b]=1
[c]=0
)
checkFileset 'intersection (_create ./. { a = "regular"; b = "regular"; c = null; }) (_create ./. { a = null; b = "regular"; c = "regular"; })'
# Actually computes the intersection between files
tree=(
[a]=0
[b]=0
[c]=1
[d]=1
[e]=0
[f]=0
)
checkFileset 'intersection (unions [ ./a ./b ./c ./d ]) (unions [ ./c ./d ./e ./f ])'
tree=(
[a/x]=0
[a/y]=0
[b/x]=1
[b/y]=1
[c/x]=0
[c/y]=0
)
checkFileset 'intersection ./b ./.'
checkFileset 'intersection ./b (unions [ ./a/x ./a/y ./b/x ./b/y ./c/x ./c/y ])'
# Complicated case
tree=(
[a/x]=0
[a/b/i]=1
[c/d/x]=0
[c/d/f]=1
[c/x]=0
[c/e/i]=1
[c/e/j]=1
)
checkFileset 'intersection (unions [ ./a/b ./c/d ./c/e ]) (unions [ ./a ./c/d/f ./c/e ])'
## File filter
# The predicate is not called when there's no files
tree=()
checkFileset 'fileFilter (file: abort "this is not needed") ./.'
checkFileset 'fileFilter (file: abort "this is not needed") _emptyWithoutBase'
# The predicate must be able to handle extra attributes
touch a
expectFailure 'toSource { root = ./.; fileset = fileFilter ({ name, type }: true) ./.; }' 'called with unexpected argument '\''"lib.fileset.fileFilter: The predicate function passed as the first argument must be able to handle extra attributes for future compatibility. If you'\''re using `\{ name, file \}:`, use `\{ name, file, ... \}:` instead."'\'
rm -rf -- *
# .name is the name, and it works correctly, even recursively
tree=(
[a]=1
[b]=0
[c/a]=1
[c/b]=0
[d/c/a]=1
[d/c/b]=0
)
checkFileset 'fileFilter (file: file.name == "a") ./.'
tree=(
[a]=0
[b]=1
[c/a]=0
[c/b]=1
[d/c/a]=0
[d/c/b]=1
)
checkFileset 'fileFilter (file: file.name != "a") ./.'
# `.type` is the file type
mkdir d
touch d/a
ln -s d/b d/b
mkfifo d/c
expectEqual \
'toSource { root = ./.; fileset = fileFilter (file: file.type == "regular") ./.; }' \
'toSource { root = ./.; fileset = ./d/a; }'
expectEqual \
'toSource { root = ./.; fileset = fileFilter (file: file.type == "symlink") ./.; }' \
'toSource { root = ./.; fileset = ./d/b; }'
expectEqual \
'toSource { root = ./.; fileset = fileFilter (file: file.type == "unknown") ./.; }' \
'toSource { root = ./.; fileset = ./d/c; }'
expectEqual \
'toSource { root = ./.; fileset = fileFilter (file: file.type != "regular") ./.; }' \
'toSource { root = ./.; fileset = union ./d/b ./d/c; }'
expectEqual \
'toSource { root = ./.; fileset = fileFilter (file: file.type != "symlink") ./.; }' \
'toSource { root = ./.; fileset = union ./d/a ./d/c; }'
expectEqual \
'toSource { root = ./.; fileset = fileFilter (file: file.type != "unknown") ./.; }' \
'toSource { root = ./.; fileset = union ./d/a ./d/b; }'
rm -rf -- *
# It's lazy
tree=(
[b]=1
[c/a]=1
)
# Note that union evaluates the first argument first if necessary, that's why we can use ./c/a here
checkFileset 'union ./c/a (fileFilter (file: assert file.name != "a"; true) ./.)'
# but here we need to use ./c
checkFileset 'union (fileFilter (file: assert file.name != "a"; true) ./.) ./c'
## Tracing
# The second trace argument is returned
@ -609,6 +767,10 @@ rm -rf -- *
# The empty file set without a base also prints as empty
expectTrace '_emptyWithoutBase' '(empty)'
expectTrace 'unions [ ]' '(empty)'
mkdir foo bar
touch {foo,bar}/x
expectTrace 'intersection ./foo ./bar' '(empty)'
rm -rf -- *
# If a directory is fully included, print it as such
touch a

View File

@ -1,26 +1,76 @@
{ lib, ... }:
rec {
/*
Compute the fixed point of the given function `f`, which is usually an
attribute set that expects its final, non-recursive representation as an
argument:
`fix f` computes the fixed point of the given function `f`. In other words, the return value is `x` in `x = f x`.
```
f = self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }
`f` must be a lazy function.
This means that `x` must be a value that can be partially evaluated,
such as an attribute set, a list, or a function.
This way, `f` can use one part of `x` to compute another part.
**Relation to syntactic recursion**
This section explains `fix` by refactoring from syntactic recursion to a call of `fix` instead.
For context, Nix lets you define attributes in terms of other attributes syntactically using the [`rec { }` syntax](https://nixos.org/manual/nix/stable/language/constructs.html#recursive-sets).
```nix
nix-repl> rec {
foo = "foo";
bar = "bar";
foobar = foo + bar;
}
{ bar = "bar"; foo = "foo"; foobar = "foobar"; }
```
Nix evaluates this recursion until all references to `self` have been
resolved. At that point, the final result is returned and `f x = x` holds:
This is convenient when constructing a value to pass to a function for example,
but an equivalent effect can be achieved with the `let` binding syntax:
```nix
nix-repl> let self = {
foo = "foo";
bar = "bar";
foobar = self.foo + self.bar;
}; in self
{ bar = "bar"; foo = "foo"; foobar = "foobar"; }
```
But in general you can get more reuse out of `let` bindings by refactoring them to a function.
```nix
nix-repl> f = self: {
foo = "foo";
bar = "bar";
foobar = self.foo + self.bar;
}
```
This is where `fix` comes in, it contains the syntactic that's not in `f` anymore.
```nix
nix-repl> fix = f:
let self = f self; in self;
```
By applying `fix` we get the final result.
```nix
nix-repl> fix f
{ bar = "bar"; foo = "foo"; foobar = "foobar"; }
```
Such a refactored `f` using `fix` is not useful by itself.
See [`extends`](#function-library-lib.fixedPoints.extends) for an example use case.
There `self` is also often called `final`.
Type: fix :: (a -> a) -> a
See https://en.wikipedia.org/wiki/Fixed-point_combinator for further
details.
Example:
fix (self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; })
=> { bar = "bar"; foo = "foo"; foobar = "foobar"; }
fix (self: [ 1 2 (elemAt self 0 + elemAt self 1) ])
=> [ 1 2 3 ]
*/
fix = f: let x = f x; in x;

View File

@ -109,7 +109,13 @@ rec {
The package is specified in the third argument under `default` as a list of strings
representing its attribute path in nixpkgs (or another package set).
Because of this, you need to pass nixpkgs itself (or a subset) as the first argument.
Because of this, you need to pass nixpkgs itself (usually `pkgs` in a module;
alternatively to nixpkgs itself, another package set) as the first argument.
If you pass another package set you should set the `pkgsText` option.
This option is used to display the expression for the package set. It is `"pkgs"` by default.
If your expression is complex you should parenthesize it, as the `pkgsText` argument
is usually immediately followed by an attribute lookup (`.`).
The second argument may be either a string or a list of strings.
It provides the display name of the package in the description of the generated option
@ -118,68 +124,100 @@ rec {
To include extra information in the description, pass `extraDescription` to
append arbitrary text to the generated description.
You can also pass an `example` value, either a literal string or an attribute path.
The default argument can be omitted if the provided name is
an attribute of pkgs (if name is a string) or a
valid attribute path in pkgs (if name is a list).
The `default` argument can be omitted if the provided name is
an attribute of pkgs (if `name` is a string) or a valid attribute path in pkgs (if `name` is a list).
You can also set `default` to just a string in which case it is interpreted as an attribute name
(a singleton attribute path, if you will).
If you wish to explicitly provide no default, pass `null` as `default`.
Type: mkPackageOption :: pkgs -> (string|[string]) -> { default? :: [string], example? :: null|string|[string], extraDescription? :: string } -> option
If you want users to be able to set no package, pass `nullable = true`.
In this mode a `default = null` will not be interpreted as no default and is interpreted literally.
Type: mkPackageOption :: pkgs -> (string|[string]) -> { nullable? :: bool, default? :: string|[string], example? :: null|string|[string], extraDescription? :: string, pkgsText? :: string } -> option
Example:
mkPackageOption pkgs "hello" { }
=> { _type = "option"; default = «derivation /nix/store/3r2vg51hlxj3cx5vscp0vkv60bqxkaq0-hello-2.10.drv»; defaultText = { ... }; description = "The hello package to use."; type = { ... }; }
=> { ...; default = pkgs.hello; defaultText = literalExpression "pkgs.hello"; description = "The hello package to use."; type = package; }
Example:
mkPackageOption pkgs "GHC" {
default = [ "ghc" ];
example = "pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])";
}
=> { _type = "option"; default = «derivation /nix/store/jxx55cxsjrf8kyh3fp2ya17q99w7541r-ghc-8.10.7.drv»; defaultText = { ... }; description = "The GHC package to use."; example = { ... }; type = { ... }; }
=> { ...; default = pkgs.ghc; defaultText = literalExpression "pkgs.ghc"; description = "The GHC package to use."; example = literalExpression "pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])"; type = package; }
Example:
mkPackageOption pkgs [ "python39Packages" "pytorch" ] {
mkPackageOption pkgs [ "python3Packages" "pytorch" ] {
extraDescription = "This is an example and doesn't actually do anything.";
}
=> { _type = "option"; default = «derivation /nix/store/gvqgsnc4fif9whvwd9ppa568yxbkmvk8-python3.9-pytorch-1.10.2.drv»; defaultText = { ... }; description = "The pytorch package to use. This is an example and doesn't actually do anything."; type = { ... }; }
=> { ...; default = pkgs.python3Packages.pytorch; defaultText = literalExpression "pkgs.python3Packages.pytorch"; description = "The pytorch package to use. This is an example and doesn't actually do anything."; type = package; }
Example:
mkPackageOption pkgs "nushell" {
nullable = true;
}
=> { ...; default = pkgs.nushell; defaultText = literalExpression "pkgs.nushell"; description = "The nushell package to use."; type = nullOr package; }
Example:
mkPackageOption pkgs "coreutils" {
default = null;
}
=> { ...; description = "The coreutils package to use."; type = package; }
Example:
mkPackageOption pkgs "dbus" {
nullable = true;
default = null;
}
=> { ...; default = null; description = "The dbus package to use."; type = nullOr package; }
Example:
mkPackageOption pkgs.javaPackages "OpenJFX" {
default = "openjfx20";
pkgsText = "pkgs.javaPackages";
}
=> { ...; default = pkgs.javaPackages.openjfx20; defaultText = literalExpression "pkgs.javaPackages.openjfx20"; description = "The OpenJFX package to use."; type = package; }
*/
mkPackageOption =
# Package set (a specific version of nixpkgs or a subset)
# Package set (an instantiation of nixpkgs such as pkgs in modules or another package set)
pkgs:
# Name for the package, shown in option description
name:
{
# Whether the package can be null, for example to disable installing a package altogether.
# Whether the package can be null, for example to disable installing a package altogether (defaults to false)
nullable ? false,
# The attribute path where the default package is located (may be omitted)
# The attribute path where the default package is located (may be omitted, in which case it is copied from `name`)
default ? name,
# A string or an attribute path to use as an example (may be omitted)
example ? null,
# Additional text to include in the option description (may be omitted)
extraDescription ? "",
# Representation of the package set passed as pkgs (defaults to `"pkgs"`)
pkgsText ? "pkgs"
}:
let
name' = if isList name then last name else name;
in mkOption ({
type = with lib.types; (if nullable then nullOr else lib.id) package;
default' = if isList default then default else [ default ];
defaultText = concatStringsSep "." default';
defaultValue = attrByPath default'
(throw "${defaultText} cannot be found in ${pkgsText}") pkgs;
defaults = if default != null then {
default = defaultValue;
defaultText = literalExpression ("${pkgsText}." + defaultText);
} else optionalAttrs nullable {
default = null;
};
in mkOption (defaults // {
description = "The ${name'} package to use."
+ (if extraDescription == "" then "" else " ") + extraDescription;
} // (if default != null then let
default' = if isList default then default else [ default ];
defaultPath = concatStringsSep "." default';
defaultValue = attrByPath default'
(throw "${defaultPath} cannot be found in pkgs") pkgs;
in {
default = defaultValue;
defaultText = literalExpression ("pkgs." + defaultPath);
} else if nullable then {
default = null;
} else { }) // lib.optionalAttrs (example != null) {
type = with lib.types; (if nullable then nullOr else lib.id) package;
} // optionalAttrs (example != null) {
example = literalExpression
(if isList example then "pkgs." + concatStringsSep "." example else example);
(if isList example then "${pkgsText}." + concatStringsSep "." example else example);
});
/* Alias of mkPackageOption. Previously used to create options with markdown

View File

@ -854,7 +854,7 @@ rec {
assert (lib.isBool flag);
mesonOption feature (if flag then "enabled" else "disabled");
/* Create an --{enable,disable}-<feat> string that can be passed to
/* Create an --{enable,disable}-<feature> string that can be passed to
standard GNU Autoconf scripts.
Example:
@ -863,11 +863,12 @@ rec {
enableFeature false "shared"
=> "--disable-shared"
*/
enableFeature = enable: feat:
assert isString feat; # e.g. passing openssl instead of "openssl"
"--${if enable then "enable" else "disable"}-${feat}";
enableFeature = flag: feature:
assert lib.isBool flag;
assert lib.isString feature; # e.g. passing openssl instead of "openssl"
"--${if flag then "enable" else "disable"}-${feature}";
/* Create an --{enable-<feat>=<value>,disable-<feat>} string that can be passed to
/* Create an --{enable-<feature>=<value>,disable-<feature>} string that can be passed to
standard GNU Autoconf scripts.
Example:
@ -876,9 +877,10 @@ rec {
enableFeatureAs false "shared" (throw "ignored")
=> "--disable-shared"
*/
enableFeatureAs = enable: feat: value: enableFeature enable feat + optionalString enable "=${value}";
enableFeatureAs = flag: feature: value:
enableFeature flag feature + optionalString flag "=${value}";
/* Create an --{with,without}-<feat> string that can be passed to
/* Create an --{with,without}-<feature> string that can be passed to
standard GNU Autoconf scripts.
Example:
@ -887,11 +889,11 @@ rec {
withFeature false "shared"
=> "--without-shared"
*/
withFeature = with_: feat:
assert isString feat; # e.g. passing openssl instead of "openssl"
"--${if with_ then "with" else "without"}-${feat}";
withFeature = flag: feature:
assert isString feature; # e.g. passing openssl instead of "openssl"
"--${if flag then "with" else "without"}-${feature}";
/* Create an --{with-<feat>=<value>,without-<feat>} string that can be passed to
/* Create an --{with-<feature>=<value>,without-<feature>} string that can be passed to
standard GNU Autoconf scripts.
Example:
@ -900,7 +902,8 @@ rec {
withFeatureAs false "shared" (throw "ignored")
=> "--without-shared"
*/
withFeatureAs = with_: feat: value: withFeature with_ feat + optionalString with_ "=${value}";
withFeatureAs = flag: feature: value:
withFeature flag feature + optionalString flag "=${value}";
/* Create a fixed width string with additional prefix to match
required width.

View File

@ -29,6 +29,15 @@ let
assert type.check value;
setType type.name ({ inherit name; } // value));
# gnu-config will ignore the portion of a triple matching the
# regex `e?abi.*$` when determining the validity of a triple. In
# other words, `i386-linuxabichickenlips` is a valid triple.
removeAbiSuffix = x:
let match = builtins.match "(.*)e?abi.*" x;
in if match==null
then x
else lib.elemAt match 0;
in
rec {
@ -466,7 +475,7 @@ rec {
else vendors.unknown;
kernel = if hasPrefix "darwin" args.kernel then getKernel "darwin"
else if hasPrefix "netbsd" args.kernel then getKernel "netbsd"
else getKernel args.kernel;
else getKernel (removeAbiSuffix args.kernel);
abi =
/**/ if args ? abi then getAbi args.abi
else if isLinux parsed || isWindows parsed then

View File

@ -20,6 +20,10 @@ let
expr = (builtins.tryEval (builtins.seq expr "didn't throw"));
expected = { success = false; value = false; };
};
testingEval = expr: {
expr = (builtins.tryEval expr).success;
expected = true;
};
testingDeepThrow = expr: testingThrow (builtins.deepSeq expr expr);
testSanitizeDerivationName = { name, expected }:
@ -39,6 +43,18 @@ in
runTests {
# CUSTOMIZATION
testFunctionArgsMakeOverridable = {
expr = functionArgs (makeOverridable ({ a, b, c ? null}: {}));
expected = { a = false; b = false; c = true; };
};
testFunctionArgsMakeOverridableOverride = {
expr = functionArgs (makeOverridable ({ a, b, c ? null }: {}) { a = 1; b = 2; }).override;
expected = { a = false; b = false; c = true; };
};
# TRIVIAL
testId = {
@ -816,6 +832,26 @@ runTests {
expected = { a = 1; b = 2; };
};
testListAttrsReverse = let
exampleAttrs = {foo=1; bar="asdf"; baz = [1 3 3 7]; fnord=null;};
exampleSingletonList = [{name="foo"; value=1;}];
in {
expr = {
isReverseToListToAttrs = builtins.listToAttrs (attrsToList exampleAttrs) == exampleAttrs;
isReverseToAttrsToList = attrsToList (builtins.listToAttrs exampleSingletonList) == exampleSingletonList;
testDuplicatePruningBehaviour = attrsToList (builtins.listToAttrs [{name="a"; value=2;} {name="a"; value=1;}]);
};
expected = {
isReverseToAttrsToList = true;
isReverseToListToAttrs = true;
testDuplicatePruningBehaviour = [{name="a"; value=2;}];
};
};
testAttrsToListsCanDealWithFunctions = testingEval (
attrsToList { someFunc= a: a + 1;}
);
# GENERATORS
# these tests assume attributes are converted to lists
# in alphabetical order

View File

@ -227,8 +227,16 @@ checkConfigOutput '^false$' config.enableAlias ./alias-with-priority-can-overrid
# Check mkPackageOption
checkConfigOutput '^"hello"$' config.package.pname ./declare-mkPackageOption.nix
checkConfigOutput '^"hello"$' config.namedPackage.pname ./declare-mkPackageOption.nix
checkConfigOutput '^".*Hello.*"$' options.namedPackage.description ./declare-mkPackageOption.nix
checkConfigOutput '^"hello"$' config.pathPackage.pname ./declare-mkPackageOption.nix
checkConfigOutput '^"pkgs\.hello\.override \{ stdenv = pkgs\.clangStdenv; \}"$' options.packageWithExample.example.text ./declare-mkPackageOption.nix
checkConfigOutput '^".*Example extra description\..*"$' options.packageWithExtraDescription.description ./declare-mkPackageOption.nix
checkConfigError 'The option .undefinedPackage. is used but not defined' config.undefinedPackage ./declare-mkPackageOption.nix
checkConfigOutput '^null$' config.nullablePackage ./declare-mkPackageOption.nix
checkConfigOutput '^"null or package"$' options.nullablePackageWithDefault.type.description ./declare-mkPackageOption.nix
checkConfigOutput '^"myPkgs\.hello"$' options.packageWithPkgsText.defaultText.text ./declare-mkPackageOption.nix
checkConfigOutput '^"hello-other"$' options.packageFromOtherSet.default.pname ./declare-mkPackageOption.nix
# submoduleWith

View File

@ -7,6 +7,28 @@ in {
options = {
package = lib.mkPackageOption pkgs "hello" { };
namedPackage = lib.mkPackageOption pkgs "Hello" {
default = [ "hello" ];
};
namedPackageSingletonDefault = lib.mkPackageOption pkgs "Hello" {
default = "hello";
};
pathPackage = lib.mkPackageOption pkgs [ "hello" ] { };
packageWithExample = lib.mkPackageOption pkgs "hello" {
example = "pkgs.hello.override { stdenv = pkgs.clangStdenv; }";
};
packageWithPathExample = lib.mkPackageOption pkgs "hello" {
example = [ "hello" ];
};
packageWithExtraDescription = lib.mkPackageOption pkgs "hello" {
extraDescription = "Example extra description.";
};
undefinedPackage = lib.mkPackageOption pkgs "hello" {
default = null;
};
@ -15,5 +37,17 @@ in {
nullable = true;
default = null;
};
nullablePackageWithDefault = lib.mkPackageOption pkgs "hello" {
nullable = true;
};
packageWithPkgsText = lib.mkPackageOption pkgs "hello" {
pkgsText = "myPkgs";
};
packageFromOtherSet = let myPkgs = {
hello = pkgs.hello // { pname = "hello-other"; };
}; in lib.mkPackageOption myPkgs "hello" { };
};
}

View File

@ -793,6 +793,12 @@
githubId = 5053729;
name = "Alias Gram";
};
alias-dev = {
email = "alias-dev@protonmail.com";
github = "alias-dev";
githubId = 30437811;
name = "Alex Andrews";
};
alibabzo = {
email = "alistair.bill@gmail.com";
github = "alistairbill";
@ -829,6 +835,12 @@
githubId = 5892756;
name = "Alec Snyder";
};
allusive = {
email = "jasper@allusive.dev";
name = "Allusive";
github = "allusive-dev";
githubId = 99632976;
};
almac = {
email = "alma.cemerlic@gmail.com";
github = "a1mac";
@ -1262,6 +1274,9 @@
github = "antonmosich";
githubId = 27223336;
name = "Anton Mosich";
keys = [ {
fingerprint = "F401 287C 324F 0A1C B321 657B 9B96 97B8 FB18 7D14";
} ];
};
antono = {
email = "self@antono.info";
@ -2596,12 +2611,6 @@
githubId = 200617;
name = "Ben Sima";
};
bstrik = {
email = "dutchman55@gmx.com";
github = "bstrik";
githubId = 7716744;
name = "Berno Strik";
};
btlvr = {
email = "btlvr@protonmail.com";
github = "btlvr";
@ -3689,6 +3698,12 @@
githubId = 490965;
name = "Craig Swank";
};
ctron = {
email = "ctron@dentrassi.de";
github = "ctron";
githubId = 202474;
name = "Jens Reimann";
};
cust0dian = {
email = "serg@effectful.software";
github = "cust0dian";
@ -3862,12 +3877,25 @@
githubId = 50051176;
name = "Daniel Rolls";
};
danielsidhion = {
email = "nixpkgs@sidhion.com";
github = "DanielSidhion";
githubId = 160084;
name = "Daniel Sidhion";
};
daniyalsuri6 = {
email = "daniyal.suri@gmail.com";
github = "daniyalsuri6";
githubId = 107034852;
name = "Daniyal Suri";
};
dannixon = {
email = "dan@dan-nixon.com";
github = "DanNixon";
githubId = 4037377;
name = "Dan Nixon";
matrix = "@dannixon:matrix.org";
};
dansbandit = {
github = "dansbandit";
githubId = 4530687;
@ -3956,7 +3984,7 @@
};
davidarmstronglewis = {
email = "davidlewis@mac.com";
github = "davidarmstronglewis";
github = "oceanlewis";
githubId = 6754950;
name = "David Armstrong Lewis";
};
@ -4406,6 +4434,15 @@
githubId = 14034137;
name = "Mostly Void";
};
ditsuke = {
name = "Tushar";
email = "hello@ditsuke.com";
github = "ditsuke";
githubId = 72784348;
keys = [{
fingerprint = "8FD2 153F 4889 541A 54F1 E09E 71B6 C31C 8A5A 9D21";
}];
};
djacu = {
email = "daniel.n.baker@gmail.com";
github = "djacu";
@ -4483,6 +4520,12 @@
githubId = 1708810;
name = "Daniel Vianna";
};
dmytrokyrychuk = {
email = "dmytro@kyrych.uk";
github = "dmytrokyrychuk";
githubId = 699961;
name = "Dmytro Kyrychuk";
};
dnr = {
email = "dnr@dnr.im";
github = "dnr";
@ -5299,6 +5342,11 @@
githubId = 1855930;
name = "Ertugrul Söylemez";
};
esau79p = {
github = "EsAu79p";
githubId = 21313906;
name = "EsAu";
};
esclear = {
github = "esclear";
githubId = 7432848;
@ -5836,10 +5884,14 @@
githubId = 1618343;
};
foo-dogsquared = {
email = "foo.dogsquared@gmail.com";
email = "foodogsquared@foodogsquared.one";
github = "foo-dogsquared";
githubId = 34962634;
matrix = "@foodogsquared:matrix.org";
name = "Gabriel Arazas";
keys = [{
fingerprint = "DDD7 D0BD 602E 564B AA04 FC35 1431 0D91 4115 2B92";
}];
};
fooker = {
email = "fooker@lab.sh";
@ -6153,6 +6205,16 @@
githubId = 45048741;
name = "Alwanga Oyango";
};
galaxy = {
email = "galaxy@dmc.chat";
matrix = "@galaxy:mozilla.org";
name = "The Galaxy";
github = "ga1aksy";
githubId = 148551648;
keys = [{
fingerprint = "48CA 3873 9E9F CA8E 76A0 835A E3DE CF85 4212 E1EA";
}];
};
gal_bolle = {
email = "florent.becker@ens-lyon.org";
github = "FlorentBecker";
@ -6296,6 +6358,16 @@
fingerprint = "D0CF 440A A703 E0F9 73CB A078 82BB 70D5 41AE 2DB4";
}];
};
gepbird = {
email = "gutyina.gergo.2@gmail.com";
github = "gepbird";
githubId = 29818440;
name = "Gutyina Gergő";
keys = [
{ fingerprint = "RoAfvqa6w1l8Vdm3W60TDXurYwJ6h03VEGD+wDNGEwc"; }
{ fingerprint = "MP2UpIRtJpbFFqyucP431H/FPCfn58UhEUTro4lXtRs"; }
];
};
gerg-l = {
email = "gregleyda@proton.me";
github = "Gerg-L";
@ -6448,6 +6520,10 @@
githubId = 1447245;
name = "Robin Gloster";
};
gm6k = {
email = "nix@quidecco.pl";
name = "Isidor Zeuner";
};
gmemstr = {
email = "git@gmem.ca";
github = "gmemstr";
@ -6571,6 +6647,12 @@
githubId = 4656860;
name = "Gaute Ravndal";
};
gray-heron = {
email = "ave+nix@cezar.info";
github = "gray-heron";
githubId = 7032646;
name = "Cezary Siwek";
};
graysonhead = {
email = "grayson@graysonhead.net";
github = "graysonhead";
@ -6795,6 +6877,12 @@
githubId = 33523827;
name = "Harrison Thorne";
};
haruki7049 = {
email = "tontonkirikiri@gmail.com";
github = "haruki7049";
githubId = 64677724;
name = "haruki7049";
};
harvidsen = {
email = "harvidsen@gmail.com";
github = "harvidsen";
@ -7160,6 +7248,13 @@
fingerprint = "731A 7A05 AD8B 3AE5 956A C227 4A03 18E0 4E55 5DE5";
}];
};
hubble = {
name = "Hubble the Wolverine";
email = "hubblethewolverine@gmail.com";
matrix = "@hubofeverything:bark.lgbt";
github = "the-furry-hubofeverything";
githubId = 53921912;
};
hufman = {
email = "hufman@gmail.com";
github = "hufman";
@ -8039,6 +8134,12 @@
githubId = 854319;
name = "Matt McHenry";
};
jerrysm64 = {
email = "jerry.starke@icloud.com";
github = "jerrysm64";
githubId = 42114389;
name = "Jerry Starke";
};
jeschli = {
email = "jeschli@gmail.com";
github = "0mbi";
@ -8142,6 +8243,12 @@
githubId = 6445082;
name = "Joseph Lukasik";
};
jgoux = {
email = "hi@jgoux.dev";
github = "jgoux";
githubId = 1443499;
name = "Julien Goux";
};
jhh = {
email = "jeff@j3ff.io";
github = "jhh";
@ -8542,6 +8649,12 @@
github = "jorsn";
githubId = 4646725;
};
joscha = {
name = "Joscha Loos";
email = "j.loos@posteo.net";
github = "jooooscha";
githubId = 57965027;
};
josephst = {
name = "Joseph Stahl";
email = "hello@josephstahl.com";
@ -8584,6 +8697,12 @@
githubId = 1918771;
name = "Joe Doyle";
};
jpentland = {
email = "joe.pentland@gmail.com";
github = "jpentland";
githubId = 1135582;
name = "Joe Pentland";
};
jperras = {
email = "joel@nerderati.com";
github = "jperras";
@ -8716,6 +8835,12 @@
githubId = 1189739;
name = "Julio Borja Barra";
};
jue89 = {
email = "me@jue.yt";
github = "jue89";
githubId = 6105784;
name = "Juergen Fitschen";
};
jugendhacker = {
name = "j.r";
email = "j.r@jugendhacker.de";
@ -8860,6 +8985,15 @@
githubId = 386765;
matrix = "@k900:0upti.me";
};
kachick = {
email = "kachick1@gmail.com";
github = "kachick";
githubId = 1180335;
name = "Kenichi Kamiya";
keys = [{
fingerprint = "9121 5D87 20CA B405 C63F 24D2 EF6E 574D 040A E2A5";
}];
};
kaction = {
name = "Dmitry Bogatov";
email = "KAction@disroot.org";
@ -9947,6 +10081,17 @@
githubId = 3696783;
name = "Leroy Hopson";
};
liketechnik = {
name = "Florian Warzecha";
email = "liketechnik@disroot.org";
github = "liketechnik";
githubId = 24209689;
keys = [{
fingerprint = "92D8 A09D 03DD B774 AABD 53B9 E136 2F07 D750 DB5C";
}];
};
lillycham = {
email = "lillycat332@gmail.com";
github = "lillycat332";
@ -10810,6 +10955,12 @@
githubId = 29855073;
name = "Michael Colicchia";
};
massimogengarelli = {
email = "massimo.gengarelli@gmail.com";
github = "massix";
githubId = 585424;
name = "Massimo Gengarelli";
};
matejc = {
email = "cotman.matej@gmail.com";
github = "matejc";
@ -10985,12 +11136,6 @@
githubId = 4708337;
name = "Marcelo A. de L. Santos";
};
maxhille = {
email = "mh@lambdasoup.com";
github = "maxhille";
githubId = 693447;
name = "Max Hille";
};
maximsmol = {
email = "maximsmol@gmail.com";
github = "maximsmol";
@ -11560,6 +11705,13 @@
githubId = 149558;
name = "Merlin Gaillard";
};
mirkolenz = {
name = "Mirko Lenz";
email = "mirko@mirkolenz.com";
matrix = "@mlenz:matrix.org";
github = "mirkolenz";
githubId = 5160954;
};
mirrexagon = {
email = "mirrexagon@mirrexagon.com";
github = "mirrexagon";
@ -12801,6 +12953,12 @@
githubId = 9939720;
name = "Philippe Nguyen";
};
npulidomateo = {
matrix = "@npulidomateo:matrix.org";
github = "npulidomateo";
githubId = 13149442;
name = "Nico Pulido-Mateo";
};
nrdxp = {
email = "tim.deh@pm.me";
matrix = "@timdeh:matrix.org";
@ -13522,6 +13680,12 @@
githubId = 152312;
name = "Periklis Tsirakidis";
};
perstark = {
email = "perstark.se@gmail.com";
github = "perstarkse";
githubId = 63069986;
name = "Per Stark";
};
petercommand = {
email = "petercommand@gmail.com";
github = "petercommand";
@ -13790,6 +13954,12 @@
githubId = 610615;
name = "Chih-Mao Chen";
};
pks = {
email = "ps@pks.im";
github = "pks-t";
githubId = 4056630;
name = "Patrick Steinhardt";
};
plabadens = {
name = "Pierre Labadens";
email = "labadens.pierre+nixpkgs@gmail.com";
@ -14109,6 +14279,12 @@
githubId = 406946;
name = "Valentin Lorentz";
};
prominentretail = {
email = "me@jakepark.me";
github = "ProminentRetail";
githubId = 94048404;
name = "Jake Park";
};
proofconstruction = {
email = "source@proof.construction";
github = "proofconstruction";
@ -14350,6 +14526,12 @@
githubId = 1332289;
name = "Quentin Machu";
};
quinn-dougherty = {
email = "quinnd@riseup.net";
github = "quinn-dougherty";
githubId = 39039420;
name = "Quinn Dougherty";
};
qyliss = {
email = "hi@alyssa.is";
github = "alyssais";
@ -14680,6 +14862,12 @@
githubId = 165283;
name = "Alexey Kutepov";
};
rexxDigital = {
email = "joellarssonpriv@gmail.com";
github = "rexxDigital";
githubId = 44014925;
name = "Rexx Larsson";
};
rgnns = {
email = "jglievano@gmail.com";
github = "rgnns";
@ -14752,6 +14940,12 @@
githubId = 42619;
name = "Wei-Ming Yang";
};
rickvanprim = {
email = "me@rickvanprim.com";
github = "rickvanprim";
githubId = 13792812;
name = "James Leitch";
};
rickynils = {
email = "rickynils@gmail.com";
github = "rickynils";
@ -14906,6 +15100,12 @@
githubId = 496447;
name = "Robert Hensing";
};
robert-manchester = {
email = "robert.manchester@gmail.com";
github = "robert-manchester";
githubId = 86313040;
name = "Robert Manchester";
};
robertodr = {
email = "roberto.diremigio@gmail.com";
github = "robertodr";
@ -15072,15 +15272,6 @@
}];
name = "Rahul Butani";
};
rs0vere = {
email = "rs0vere@proton.me";
github = "rs0vere";
githubId = 140035635;
keys = [{
fingerprint = "C6D8 B5C2 FA79 901B DCCF 95E1 FEC4 5C5A ED00 C58D";
}];
name = "Red Star Over Earth";
};
rski = {
name = "rski";
email = "rom.skiad+nix@gmail.com";
@ -15105,6 +15296,12 @@
githubId = 47790121;
name = "Ryan Burns";
};
rtimush = {
email = "rtimush@gmail.com";
github = "rtimush";
githubId = 831307;
name = "Roman Timushev";
};
rtreffer = {
email = "treffer+nixos@measite.de";
github = "rtreffer";
@ -15221,6 +15418,12 @@
fingerprint = "E4F4 1EAB BF0F C785 06D8 62EF EF68 CF41 D42A 593D";
}];
};
ryangibb = {
email = "ryan@freumh.org";
github = "ryangibb";
githubId = 22669046;
name = "Ryan Gibb";
};
ryanorendorff = {
github = "ryanorendorff";
githubId = 12442942;
@ -15336,7 +15539,7 @@
};
SamirTalwar = {
email = "lazy.git@functional.computer";
github = "SamirTalwar";
github = "abstracte";
githubId = 47852;
name = "Samir Talwar";
};
@ -15490,6 +15693,12 @@
githubId = 3958212;
name = "Tom Sorlie";
};
schinmai-akamai = {
email = "schinmai@akamai.com";
github = "schinmai-akamai";
githubId = 70169773;
name = "Tarun Chinmai Sekar";
};
schmitthenner = {
email = "development@schmitthenner.eu";
github = "fkz";
@ -15903,6 +16112,12 @@
fingerprint = "AB63 4CD9 3322 BD42 6231 F764 C404 1EA6 B326 33DE";
}];
};
shivaraj-bh = {
email = "sbh69840@gmail.com";
name = "Shivaraj B H";
github = "shivaraj-bh";
githubId = 23645788;
};
shlevy = {
email = "shea@shealevy.com";
github = "shlevy";
@ -16073,6 +16288,12 @@
fingerprint = "B234 EFD4 2B42 FE81 EE4D 7627 F72C 4A88 7F9A 24CA";
}];
};
sironheart = {
email = "git@beisenherz.dev";
github = "Sironheart";
githubId = 13799656;
name = "Steffen Beisenherz";
};
sirseruju = {
email = "sir.seruju@yandex.ru";
github = "SirSeruju";
@ -16280,6 +16501,16 @@
fingerprint = "E067 520F 5EF2 C175 3F60 50C0 BA46 725F 6A26 7442";
}];
};
soispha = {
name = "Soispha";
email = "soispha@vhack.eu";
matrix = "@soispha:vhack.eu";
github = "soispha";
githubId = 132207423;
keys = [{
fingerprint = "9606 FC74 9FCE 1636 0723 D4AD A5E9 4010 C3A6 42AD";
}];
};
solson = {
email = "scott@solson.me";
matrix = "@solson:matrix.org";
@ -16344,6 +16575,11 @@
fingerprint = "75F0 AB7C FE01 D077 AEE6 CAFD 353E 4A18 EE0F AB72";
}];
};
spacefault = {
github = "spacefault";
githubId = 74156492;
name = "spacefault";
};
spacefrogg = {
email = "spacefrogg-nixos@meterriblecrew.net";
github = "spacefrogg";
@ -16982,6 +17218,12 @@
githubId = 1901799;
name = "Nathan van Doorn";
};
taranarmo = {
email = "taranarmo@gmail.com";
github = "taranarmo";
githubId = 11619234;
name = "Sergey Volkov";
};
tari = {
email = "peter@taricorp.net";
github = "tari";
@ -17624,6 +17866,12 @@
githubId = 858790;
name = "Tobias Mayer";
};
tochiaha = {
email = "tochiahan@proton.me";
github = "Tochiaha";
githubId = 74688871;
name = "Tochukwu Ahanonu";
};
tokudan = {
email = "git@danielfrank.net";
github = "tokudan";
@ -17669,6 +17917,10 @@
githubId = 13155277;
name = "Tom Houle";
};
tomkoid = {
email = "tomaszierl@outlook.com";
name = "Tomkoid";
};
tomodachi94 = {
email = "tomodachi94+nixpkgs@protonmail.com";
matrix = "@tomodachi94:matrix.org";
@ -17739,12 +17991,6 @@
githubId = 10110;
name = "Travis B. Hartwell";
};
travisdavis-ops = {
email = "travisdavismedia@gmail.com";
github = "TravisDavis-ops";
githubId = 52011418;
name = "Travis Davis";
};
traxys = {
email = "quentin+dev@familleboyer.net";
github = "traxys";
@ -17830,6 +18076,12 @@
githubId = 15064765;
name = "tshaynik";
};
tsowell = {
email = "tom@ldtlb.com";
github = "tsowell";
githubId = 4044033;
name = "Thomas Sowell";
};
ttuegel = {
email = "ttuegel@mailbox.org";
github = "ttuegel";
@ -17954,6 +18206,12 @@
githubId = 1983821;
name = "Eric Wolf";
};
u2x1 = {
email = "u2x1@outlook.com";
github = "u2x1";
githubId = 30677291;
name = "u2x1";
};
uakci = {
name = "uakci";
email = "uakci@uakci.pl";
@ -17972,6 +18230,16 @@
githubId = 1607770;
name = "Ulrik Strid";
};
unclamped = {
name = "Maru";
email = "clear6860@tutanota.com";
matrix = "@unhidden0174:matrix.org";
github = "unclamped";
githubId = 104658278;
keys = [{
fingerprint = "57A2 CC43 3068 CB62 89C1 F1DA 9137 BB2E 77AD DE7E";
}];
};
unclechu = {
name = "Viacheslav Lotsmanov";
email = "lotsmanov89@gmail.com";
@ -18263,6 +18531,15 @@
githubId = 245573;
name = "Dmitry Kalinkin";
};
vgskye = {
name = "Skye Green";
email = "me@skye.vg";
github = "vgskye";
githubId = 116078858;
keys = [{
fingerprint = "CDEA 7E04 69E3 0885 A754 4B05 0104 BC05 F41B 77B8";
}];
};
victormeriqui = {
name = "Victor Meriqui";
email = "victor.meriqui@ororatech.com";
@ -18628,6 +18905,12 @@
fingerprint = "F844 80B2 0CA9 D6CC C7F5 2479 A776 D2AD 099E 8BC0";
}];
};
wexder = {
email = "wexder19@gmail.com";
github = "wexder";
githubId = 24979302;
name = "Vladimír Zahradník";
};
wheelsandmetal = {
email = "jakob@schmutz.co.uk";
github = "wheelsandmetal";
@ -19069,7 +19352,7 @@
];
};
yayayayaka = {
email = "nixpkgs@uwu.is";
email = "github@uwu.is";
matrix = "@yaya:uwu.is";
github = "yayayayaka";
githubId = 73759599;
@ -19151,6 +19434,11 @@
github = "ymeister";
githubId = 47071325;
};
ymstnt = {
name = "YMSTNT";
github = "ymstnt";
githubId = 21342713;
};
yoavlavi = {
email = "yoav@yoavlavi.com";
github = "yoav-lavi";
@ -19183,6 +19471,13 @@
github = "YorikSar";
githubId = 428074;
};
YoshiRulz = {
name = "YoshiRulz";
email = "OSSYoshiRulz+Nixpkgs@gmail.com";
matrix = "@YoshiRulz:matrix.org";
github = "YoshiRulz";
githubId = 13409956;
};
yrashk = {
email = "yrashk@gmail.com";
github = "yrashk";

View File

@ -12,5 +12,5 @@ import ../../pkgs/top-level/release.nix
scrubJobs = false;
# No need to evaluate on i686.
supportedSystems = [ "x86_64-linux" ];
limitedSupportedSystems = [];
bootstrapConfigs = [];
}

View File

@ -13,12 +13,15 @@ STDOUT->autoflush(1);
my $ua = LWP::UserAgent->new();
if (!defined $ENV{GH_TOKEN}) {
die "Set GH_TOKEN before running this script";
}
keys %$maintainers_json; # reset the internal iterator so a prior each() doesn't affect the loop
while(my($k, $v) = each %$maintainers_json) {
my $current_user = %$v{'github'};
if (!defined $current_user) {
print "$k has no github handle\n";
next;
}
my $github_id = %$v{'githubId'};
if (!defined $github_id) {
@ -37,13 +40,16 @@ while(my($k, $v) = each %$maintainers_json) {
sleep($ratelimit_reset - time() + 5);
}
if ($resp->code != 200) {
print $current_user . " likely deleted their github account\n";
print "$k likely deleted their github account\n";
next;
}
my $resp_json = from_json($resp->content);
my $api_user = %$resp_json{"login"};
if (lc($current_user) ne lc($api_user)) {
print $current_user . " is now known on github as " . $api_user . ". Editing maintainer-list.nix…\n";
if (!defined $current_user) {
print "$k is known on github as $api_user.\n";
}
elsif (lc($current_user) ne lc($api_user)) {
print "$k is now known on github as $api_user. Editing maintainer-list.nix…\n";
my $file = path($maintainers_list_nix);
my $data = $file->slurp_utf8;
$data =~ s/github = "$current_user";$/github = "$api_user";/m;

View File

@ -34,7 +34,6 @@ loadkit,,,,,,alerque
lpeg,,,,,,vyp
lpeg_patterns,,,,,,
lpeglabel,,,,1.6.0,,
lpty,,,,,,
lrexlib-gnu,,,,,,
lrexlib-pcre,,,,,,vyp
lrexlib-posix,,,,,,
@ -72,6 +71,7 @@ lualogging,,,,,,
luaossl,,,,,5.1,
luaposix,,,,34.1.1-1,,vyp lblasc
luarepl,,,,,,
luarocks-build-rust-mlua,,,,,,mrcjkb
luasec,,,,,,flosse
luasocket,,,,,,
luasql-sqlite3,,,,,,vyp
@ -92,6 +92,7 @@ mediator_lua,,,,,,
middleclass,,,,,,
mpack,,,,,,
moonscript,https://github.com/leafo/moonscript.git,dev-1,,,,arobyn
nui-nvim,,,,,,mrcjkb
nvim-client,https://github.com/neovim/lua-client.git,,,,,
nvim-cmp,https://github.com/hrsh7th/nvim-cmp,,,,,
penlight,https://github.com/lunarmodules/Penlight.git,,,,,alerque
@ -99,6 +100,7 @@ plenary.nvim,https://github.com/nvim-lua/plenary.nvim.git,,,,5.1,
rapidjson,https://github.com/xpol/lua-rapidjson.git,,,,,
rest.nvim,,,,,5.1,teto
readline,,,,,,
rustaceanvim,,,,,,mrcjkb
say,https://github.com/Olivine-Labs/say.git,,,,,
serpent,,,,,,lockejan
sqlite,,,,,,
@ -109,5 +111,7 @@ teal-language-server,,,http://luarocks.org/dev,,,
telescope.nvim,,,,,5.1,
telescope-manix,,,,,,
tl,,,,,,mephistophiles
toml,,,,,,mrcjkb
toml-edit,,,,,5.1,mrcjkb
vstruct,https://github.com/ToxicFrog/vstruct.git,,,,,
vusted,,,,,,figsoda

1 name src ref server version luaversion maintainers
34 lpeg vyp
35 lpeg_patterns
36 lpeglabel 1.6.0
lpty
37 lrexlib-gnu
38 lrexlib-pcre vyp
39 lrexlib-posix
71 luaossl 5.1
72 luaposix 34.1.1-1 vyp lblasc
73 luarepl
74 luarocks-build-rust-mlua mrcjkb
75 luasec flosse
76 luasocket
77 luasql-sqlite3 vyp
92 middleclass
93 mpack
94 moonscript https://github.com/leafo/moonscript.git dev-1 arobyn
95 nui-nvim mrcjkb
96 nvim-client https://github.com/neovim/lua-client.git
97 nvim-cmp https://github.com/hrsh7th/nvim-cmp
98 penlight https://github.com/lunarmodules/Penlight.git alerque
100 rapidjson https://github.com/xpol/lua-rapidjson.git
101 rest.nvim 5.1 teto
102 readline
103 rustaceanvim mrcjkb
104 say https://github.com/Olivine-Labs/say.git
105 serpent lockejan
106 sqlite
111 telescope.nvim 5.1
112 telescope-manix
113 tl mephistophiles
114 toml mrcjkb
115 toml-edit 5.1 mrcjkb
116 vstruct https://github.com/ToxicFrog/vstruct.git
117 vusted figsoda

View File

@ -327,7 +327,6 @@ def run_nix_expr(expr, nixpkgs: str):
:param expr nix expression to fetch current plugins
:param nixpkgs Path towards a nixpkgs checkout
'''
# local_pkgs = str(Path(__file__).parent.parent.parent)
with CleanEnvironment(nixpkgs) as nix_path:
cmd = [
"nix",
@ -341,8 +340,8 @@ def run_nix_expr(expr, nixpkgs: str):
"--nix-path",
nix_path,
]
log.debug("Running command %s", " ".join(cmd))
out = subprocess.check_output(cmd)
log.debug("Running command: %s", " ".join(cmd))
out = subprocess.check_output(cmd, timeout=90)
data = json.loads(out)
return data
@ -572,7 +571,6 @@ class CleanEnvironment(object):
self.empty_config = NamedTemporaryFile()
self.empty_config.write(b"{}")
self.empty_config.flush()
# os.environ["NIXPKGS_CONFIG"] = self.empty_config.name
return f"localpkgs={self.local_pkgs}"
def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
@ -788,8 +786,11 @@ def update_plugins(editor: Editor, args):
autocommit = not args.no_commit
if autocommit:
from datetime import date
editor.nixpkgs_repo = git.Repo(editor.root, search_parent_directories=True)
commit(editor.nixpkgs_repo, f"{editor.attr_path}: update", [args.outfile])
updated = date.today().strftime('%m-%d-%Y')
commit(editor.nixpkgs_repo, f"{editor.attr_path}: updated the {updated}", [args.outfile])
if redirects:
update()

View File

@ -350,6 +350,7 @@ with lib.maintainers; {
mic92
zowoq
qbit
mfrw
];
githubTeams = [
"golang"
@ -406,7 +407,6 @@ with lib.maintainers; {
home-assistant = {
members = [
fab
globin
hexa
mic92
];
@ -611,6 +611,7 @@ with lib.maintainers; {
minimal-bootstrap = {
members = [
alejandrosame
artturin
emilytrau
ericson2314
@ -682,6 +683,18 @@ with lib.maintainers; {
shortName = "Numtide team";
};
ocaml = {
members = [
alizter
];
githubTeams = [
"ocaml"
];
scope = "Maintain the OCaml compiler and package set.";
shortName = "OCaml";
enableFeatureFreezePing = true;
};
openstack = {
members = [
SuperSandro2000
@ -728,7 +741,6 @@ with lib.maintainers; {
aanderse
drupol
etu
globin
ma27
talyz
];

View File

@ -26,7 +26,7 @@ directory which is scanned by the ICL loader for ICD files. For example:
```ShellSession
$ export \
OCL_ICD_VENDORS=`nix-build '<nixpkgs>' --no-out-link -A rocm-opencl-icd`/etc/OpenCL/vendors/
OCL_ICD_VENDORS=`nix-build '<nixpkgs>' --no-out-link -A rocmPackages.clr.icd`/etc/OpenCL/vendors/
```
The second mechanism is to add the OpenCL driver package to
@ -50,13 +50,13 @@ Platform Vendor Advanced Micro Devices, Inc.
Modern AMD [Graphics Core
Next](https://en.wikipedia.org/wiki/Graphics_Core_Next) (GCN) GPUs are
supported through the rocm-opencl-icd package. Adding this package to
supported through the rocmPackages.clr.icd package. Adding this package to
[](#opt-hardware.opengl.extraPackages)
enables OpenCL support:
```nix
hardware.opengl.extraPackages = [
rocm-opencl-icd
rocmPackages.clr.icd
];
```

View File

@ -45,8 +45,8 @@ services.xserver.displayManager.gdm.enable = true;
You can set the keyboard layout (and optionally the layout variant):
```nix
services.xserver.layout = "de";
services.xserver.xkbVariant = "neo";
services.xserver.xkb.layout = "de";
services.xserver.xkb.variant = "neo";
```
The X server is started automatically at boot time. If you don't want
@ -266,7 +266,7 @@ Once the configuration is applied, and you did a logout/login cycle, the
layout should be ready to use. You can try it by e.g. running
`setxkbmap us-greek` and then type `<alt>+a` (it may not get applied in
your terminal straight away). To change the default, the usual
`services.xserver.layout` option can still be used.
`services.xserver.xkb.layout` option can still be used.
A layout can have several other components besides `xkb_symbols`, for
example we will define new keycodes for some multimedia key and bind

View File

@ -69,4 +69,4 @@ do:
`/etc/group` and `/etc/shadow`. This also creates home directories
- `usrbinenv` creates `/usr/bin/env`
- `var` creates some directories in `/var` that are not service-specific
- `wrappers` creates setuid wrappers like `ping` and `sudo`
- `wrappers` creates setuid wrappers like `sudo`

View File

@ -90,7 +90,7 @@ lib.mkOption {
```
:::
### `mkPackageOption`, `mkPackageOptionMD` {#sec-option-declarations-util-mkPackageOption}
### `mkPackageOption` {#sec-option-declarations-util-mkPackageOption}
Usage:
@ -121,15 +121,13 @@ valid attribute path in pkgs (if name is a list).
If you wish to explicitly provide no default, pass `null` as `default`.
During the transition to CommonMark documentation `mkPackageOption` creates an option with a DocBook description attribute, once the transition is completed it will create a CommonMark description instead. `mkPackageOptionMD` always creates an option with a CommonMark description attribute and will be removed some time after the transition is completed.
[]{#ex-options-declarations-util-mkPackageOption}
Examples:
::: {#ex-options-declarations-util-mkPackageOption-hello .example}
### Simple `mkPackageOption` usage
```nix
lib.mkPackageOptionMD pkgs "hello" { }
lib.mkPackageOption pkgs "hello" { }
# is like
lib.mkOption {
type = lib.types.package;
@ -143,7 +141,7 @@ lib.mkOption {
::: {#ex-options-declarations-util-mkPackageOption-ghc .example}
### `mkPackageOption` with explicit default and example
```nix
lib.mkPackageOptionMD pkgs "GHC" {
lib.mkPackageOption pkgs "GHC" {
default = [ "ghc" ];
example = "pkgs.haskell.packages.ghc92.ghc.withPackages (hkgs: [ hkgs.primes ])";
}

View File

@ -528,7 +528,7 @@ The only required parameter is `name`.
: A string representation of the type function name.
`definition`
`description`
: Description of the type used in documentation. Give information of
the type and any of its arguments.

View File

@ -58,7 +58,7 @@ have a predefined type and string generator already declared under
and returning a set with YAML-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result).
`pkgs.formats.ini` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \... }
`pkgs.formats.ini` { *`listsAsDuplicateKeys`* ? false, *`listToValue`* ? null, \.\.\. }
: A function taking an attribute set with values

View File

@ -44,6 +44,10 @@ of actions is always the same:
- Inspect what changed during these actions and print units that failed and
that were newly started
By default, some units are filtered from the outputs to make it less spammy.
This can be disabled for development or testing by setting the environment variable
`STC_DISPLAY_ALL_UNITS=1`
Most of these actions are either self-explaining but some of them have to do
with our units or the activation script. For this reason, these topics are
explained in the next sections.

View File

@ -16,7 +16,7 @@ You can quickly validate your edits with `make`:
```ShellSession
$ cd /path/to/nixpkgs/nixos/doc/manual
$ nix-shell
nix-shell$ make
nix-shell$ devmode
```
Once you are done making modifications to the manual, it's important to

View File

@ -2,7 +2,7 @@
In addition to numerous new and upgraded packages, this release has the following highlights:
- The [Haskell](http://haskell.org/) packages infrastructure has been re-designed from the ground up ("Haskell NG"). NixOS now distributes the latest version of every single package registered on [Hackage](http://hackage.haskell.org/) \-- well in excess of 8,000 Haskell packages. Detailed instructions on how to use that infrastructure can be found in the [User's Guide to the Haskell Infrastructure](https://nixos.org/nixpkgs/manual/#users-guide-to-the-haskell-infrastructure). Users migrating from an earlier release may find helpful information below, in the list of backwards-incompatible changes. Furthermore, we distribute 51(!) additional Haskell package sets that provide every single [LTS Haskell](http://www.stackage.org/) release since version 0.0 as well as the most recent [Stackage Nightly](http://www.stackage.org/) snapshot. The announcement ["Full Stackage Support in Nixpkgs"](https://nixos.org/nix-dev/2015-September/018138.html) gives additional details.
- The [Haskell](http://haskell.org/) packages infrastructure has been re-designed from the ground up ("Haskell NG"). NixOS now distributes the latest version of every single package registered on [Hackage](http://hackage.haskell.org/) -- well in excess of 8,000 Haskell packages. Detailed instructions on how to use that infrastructure can be found in the [User's Guide to the Haskell Infrastructure](https://nixos.org/nixpkgs/manual/#users-guide-to-the-haskell-infrastructure). Users migrating from an earlier release may find helpful information below, in the list of backwards-incompatible changes. Furthermore, we distribute 51(!) additional Haskell package sets that provide every single [LTS Haskell](http://www.stackage.org/) release since version 0.0 as well as the most recent [Stackage Nightly](http://www.stackage.org/) snapshot. The announcement ["Full Stackage Support in Nixpkgs"](https://nixos.org/nix-dev/2015-September/018138.html) gives additional details.
- Nix has been updated to version 1.10, which among other improvements enables cryptographic signatures on binary caches for improved security.
@ -178,7 +178,7 @@ The new option `system.stateVersion` ensures that certain configuration changes
- Nix now requires binary caches to be cryptographically signed. If you have unsigned binary caches that you want to continue to use, you should set `nix.requireSignedBinaryCaches = false`.
- Steam now doesn't need root rights to work. Instead of using `*-steam-chrootenv`, you should now just run `steam`. `steamChrootEnv` package was renamed to `steam`, and old `steam` package \-- to `steamOriginal`.
- Steam now doesn't need root rights to work. Instead of using `*-steam-chrootenv`, you should now just run `steam`. `steamChrootEnv` package was renamed to `steam`, and old `steam` package -- to `steamOriginal`.
- CMPlayer has been renamed to bomi upstream. Package `cmplayer` was accordingly renamed to `bomi`

View File

@ -130,7 +130,7 @@ In addition to numerous new and upgraded packages, this release includes the fol
don't lose access to their files.
In any other case, it's safe to use OpenSSL 3 for PHP's OpenSSL extension. This can be done by setting
[](#opt-services.nextcloud.enableBrokenCiphersForSSE) to `false`.
`services.nextcloud.enableBrokenCiphersForSSE` to `false`.
- The `coq` package and versioned variants starting at `coq_8_14` no
longer include CoqIDE, which is now available through

View File

@ -4,6 +4,8 @@
- FoundationDB now defaults to major version 7.
- PostgreSQL now defaults to major version 15.
- Support for WiFi6 (IEEE 802.11ax) and WPA3-SAE-PK was enabled in the `hostapd` package, along with a significant rework of the hostapd module.
- LXD now supports virtual machine instances to complement the existing container support
@ -24,8 +26,18 @@
- `root` and `wheel` are not given the ability to set (or preserve)
arbitrary environment variables.
- [glibc](https://www.gnu.org/software/libc/) has been updated from version 2.37 to 2.38, see [the release notes](https://sourceware.org/glibc/wiki/Release/2.38) for what was changed.
[`sudo-rs`]: https://github.com/memorysafety/sudo-rs/
- All [ROCm](https://rocm.docs.amd.com/en/latest/) packages have been updated to 5.7.0.
- [ROCm](https://rocm.docs.amd.com/en/latest/) package attribute sets are versioned: `rocmPackages` -> `rocmPackages_5`.
- If the user has a custom shell enabled via `users.users.${USERNAME}.shell = ${CUSTOMSHELL}`, the
assertion will require them to also set `programs.${CUSTOMSHELL}.enable =
true`. This is generally safe behavior, but for anyone needing to opt out from
the check `users.users.${USERNAME}.ignoreShellProgramCheck = true` will do the job.
## New Services {#sec-release-23.11-new-services}
- [MCHPRS](https://github.com/MCHPR/MCHPRS), a multithreaded Minecraft server built for redstone. Available as [services.mchprs](#opt-services.mchprs.enable).
@ -58,12 +70,18 @@
- [Prometheus MySQL exporter](https://github.com/prometheus/mysqld_exporter), a MySQL server exporter for Prometheus. Available as [services.prometheus.exporters.mysqld](#opt-services.prometheus.exporters.mysqld.enable).
- [LibreNMS](https://www.librenms.org), a auto-discovering PHP/MySQL/SNMP based network monitoring. Available as [services.librenms](#opt-services.librenms.enable).
- [sitespeed-io](https://sitespeed.io), a tool that can generate metrics (timings, diagnostics) for websites. Available as [services.sitespeed-io](#opt-services.sitespeed-io.enable).
- [stalwart-mail](https://stalw.art), an all-in-one email server (SMTP, IMAP, JMAP). Available as [services.stalwart-mail](#opt-services.stalwart-mail.enable).
- [tang](https://github.com/latchset/tang), a server for binding data to network presence. Available as [services.tang](#opt-services.tang.enable).
- [Jool](https://nicmx.github.io/Jool/en/index.html), a kernelspace NAT64 and SIIT implementation, providing translation between IPv4 and IPv6. Available as [networking.jool.enable](#opt-networking.jool.enable).
- [Home Assistant Satellite], a streaming audio satellite for Home Assistant voice pipelines, where you can reuse existing mic/speaker hardware. Available as [services.homeassistant-satellite](#opt-services.homeassistant-satellite.enable).
- [Apache Guacamole](https://guacamole.apache.org/), a cross-platform, clientless remote desktop gateway. Available as [services.guacamole-server](#opt-services.guacamole-server.enable) and [services.guacamole-client](#opt-services.guacamole-client.enable) services.
- [pgBouncer](https://www.pgbouncer.org), a PostgreSQL connection pooler. Available as [services.pgbouncer](#opt-services.pgbouncer.enable).
@ -83,14 +101,30 @@
- [Honk](https://humungus.tedunangst.com/r/honk), a complete ActivityPub server with minimal setup and support costs.
Available as [services.honk](#opt-services.honk.enable).
- [ferretdb](https://www.ferretdb.io/), an open-source proxy, converting the MongoDB 6.0+ wire protocol queries to PostgreSQL or SQLite. Available as [services.ferretdb](options.html#opt-services.ferretdb.enable).
- [MicroBin](https://microbin.eu/), a feature rich, performant and secure text and file sharing web application, a "paste bin". Available as [services.microbin](#opt-services.microbin.enable).
- [NNCP](http://www.nncpgo.org/). Added nncp-daemon and nncp-caller services. Configuration is set with [programs.nncp.settings](#opt-programs.nncp.settings) and the daemons are enabled at [services.nncp](#opt-services.nncp.caller.enable).
- [FastNetMon Advanced](https://fastnetmon.com/product-overview/), a commercial high performance DDoS detector / sensor. Available as [services.fastnetmon-advanced](#opt-services.fastnetmon-advanced.enable).
- [tuxedo-rs](https://github.com/AaronErhardt/tuxedo-rs), Rust utilities for interacting with hardware from TUXEDO Computers.
- [audiobookshelf](https://github.com/advplyr/audiobookshelf/), a self-hosted audiobook and podcast server. Available as [services.audiobookshelf](#opt-services.audiobookshelf.enable).
- [ZITADEL](https://zitadel.com), a turnkey identity and access management platform. Available as [services.zitadel](#opt-services.zitadel.enable).
- [netclient](https://github.com/gravitl/netclient), an automated WireGuard® Management Client. Available as [services.netclient](#opt-services.netclient.enable).
- [trunk-ng](https://github.com/ctron/trunk), A fork of `trunk`: Build, bundle & ship your Rust WASM application to the web
- [virt-manager](https://virt-manager.org/), an UI for managing virtual machines in libvirt, is now available as `programs.virt-manager`.
- [Soft Serve](https://github.com/charmbracelet/soft-serve), a tasty, self-hostable Git server for the command line. Available as [services.soft-serve](#opt-services.soft-serve.enable).
- [Rosenpass](https://rosenpass.eu/), a service for post-quantum-secure VPNs with WireGuard. Available as [services.rosenpass](#opt-services.rosenpass.enable).
## Backward Incompatibilities {#sec-release-23.11-incompatibilities}
- `network-online.target` has been fixed to no longer time out for systems with `networking.useDHCP = true` and `networking.useNetworkd = true`.
@ -114,7 +148,7 @@
- `pass` now does not contain `password-store.el`. Users should get `password-store.el` from Emacs lisp package set `emacs.pkgs.password-store`.
- `services.knot` now supports `.settings` from RFC42. The change is not 100% compatible with the previous `.extraConfig`.
- `services.knot` now supports `.settings` from RFC42. The previous `.extraConfig` still works the same, but it displays a warning now.
- `mu` now does not install `mu4e` files by default. Users should get `mu4e` from Emacs lisp package set `emacs.pkgs.mu4e`.
@ -146,6 +180,17 @@
- `consul` has been updated to `1.16.0`. See the [release note](https://github.com/hashicorp/consul/releases/tag/v1.16.0) for more details. Once a new Consul version has started and upgraded its data directory, it generally cannot be downgraded to the previous version.
- `llvmPackages_rocm` has been moved to `rocmPackages.llvm`.
- `hip`, `rocm-opencl-runtime`, `rocm-opencl-icd`, and `rocclr` have been combined into `rocmPackages.clr`.
- `clang-ocl`, `clr`, `composable_kernel`, `hipblas`, `hipcc`, `hip-common`, `hipcub`,
`hipfft`, `hipfort`, `hipify`, `hipsolver`, `hipsparse`, `migraphx`, `miopen`, `miopengemm`,
`rccl`, `rdc`, `rocalution`, `rocblas`, `rocdgbapi`, `rocfft`, `rocgdb`, `rocm-cmake`,
`rocm-comgr`, `rocm-core`, `rocm-device-libs`, `rocminfo`, `rocmlir`, `rocm-runtime`,
`rocm-smi`, `rocm-thunk`, `rocprim`, `rocprofiler`, `rocrand`, `rocr-debug-agent`,
`rocsolver`, `rocsparse`, `rocthrust`, `roctracer`, `rocwmma`, and `tensile` have been moved to `rocmPackages`.
- `himalaya` has been updated to `0.8.0`, which drops the native TLS support (in favor of Rustls) and add OAuth 2.0 support. See the [release note](https://github.com/soywod/himalaya/releases/tag/v0.8.0) for more details.
- `nix-prefetch-git` now ignores global and user git config, to improve reproducibility.
@ -183,6 +228,8 @@
- `odoo` now defaults to 16, updated from 15.
- `varnish` was upgraded from 7.2.x to 7.4.x, see https://varnish-cache.org/docs/7.3/whats-new/upgrading-7.3.html and https://varnish-cache.org/docs/7.4/whats-new/upgrading-7.4.html for upgrade notes. The current LTS version is still offered as `varnish60`.
- `util-linux` is now supported on Darwin and is no longer an alias to `unixtools`. Use the `unixtools.util-linux` package for access to the Apple variants of the utilities.
- `services.keyd` changed API. Now you can create multiple configuration files.
@ -197,6 +244,8 @@
- `fileSystems.<name>.autoResize` now uses `systemd-growfs` to resize the file system online in stage 2. This means that `f2fs` and `ext2` can no longer be auto resized, while `xfs` and `btrfs` now can be.
- `nixos-rebuild {switch,boot,test,dry-activate}` now runs the system activation inside `systemd-run`, creating an ephemeral systemd service and protecting the system switch against issues like network disconnections during remote (e.g. SSH) sessions. This has the side effect of running the switch in an isolated environment, that could possible break post-switch scripts that depends on things like environment variables being set. If you want to opt-out from this behavior for now, you may set the `NIXOS_SWITCH_USE_DIRTY_ENV` environment variable before running `nixos-rebuild`. However, keep in mind that this option will be removed in the future.
- The `services.vaultwarden.config` option default value was changed to make Vaultwarden only listen on localhost, following the [secure defaults for most NixOS services](https://github.com/NixOS/nixpkgs/issues/100192).
- `services.lemmy.settings.federation` was removed in 0.17.0 and no longer has any effect. To enable federation, the hostname must be set in the configuration file and then federation must be enabled in the admin web UI. See the [release notes](https://github.com/LemmyNet/lemmy/blob/c32585b03429f0f76d1e4ff738786321a0a9df98/RELEASES.md#upgrade-instructions) for more details.
@ -215,6 +264,10 @@
- The binary of the package `cloud-sql-proxy` has changed from `cloud_sql_proxy` to `cloud-sql-proxy`.
- Garage has been upgraded to 0.9.x. `services.garage.package` now needs to be explicitly set, so version upgrades can be done in a controlled fashion. For this, we expose `garage_x_y` attributes which can be set here.
- `voms` and `xrootd` now moves the `$out/etc` content to the `$etc` output instead of `$out/etc.orig`, when input argument `externalEtc` is not `null`.
- The `woodpecker-*` CI packages have been updated to 1.0.0. This release is wildly incompatible with the 0.15.X versions that were previously packaged. Please read [upstream's documentation](https://woodpecker-ci.org/docs/next/migrations#100) to learn how to update your CI configurations.
- The Caddy module gained a new option named `services.caddy.enableReload` which is enabled by default. It allows reloading the service instead of restarting it, if only a config file has changed. This option must be disabled if you have turned off the [Caddy admin API](https://caddyserver.com/docs/caddyfile/options#admin). If you keep this option enabled, you should consider setting [`grace_period`](https://caddyserver.com/docs/caddyfile/options#grace-period) to a non-infinite value to prevent Caddy from delaying the reload indefinitely.
@ -244,6 +297,8 @@
- Package `noto-fonts-emoji` was renamed to `noto-fonts-color-emoji`;
see [#221181](https://github.com/NixOS/nixpkgs/issues/221181).
- Package `cloud-sql-proxy` was renamed to `google-cloud-sql-proxy` as it cannot be used with other cloud providers.;
- Package `pash` was removed due to being archived upstream. Use `powershell` as an alternative.
- `security.sudo.extraRules` now includes `root`'s default rule, with ordering
@ -251,6 +306,8 @@
order, or relying on `mkBefore` and `mkAfter`, but may impact users calling
`mkOrder n` with n  400.
- X keyboard extension (XKB) options have been reorganized into a single attribute set, `services.xserver.xkb`. Specifically, `services.xserver.layout` is now `services.xserver.xkb.layout`, `services.xserver.xkbModel` is now `services.xserver.xkb.model`, `services.xserver.xkbOptions` is now `services.xserver.xkb.options`, `services.xserver.xkbVariant` is now `services.xserver.xkb.variant`, and `services.xserver.xkbDir` is now `services.xserver.xkb.dir`.
- `networking.networkmanager.firewallBackend` was removed as NixOS is now using iptables-nftables-compat even when using iptables, therefore Networkmanager now uses the nftables backend unconditionally.
- [`lib.lists.foldl'`](https://nixos.org/manual/nixpkgs/stable#function-library-lib.lists.foldl-prime) now always evaluates the initial accumulator argument first.
@ -260,10 +317,24 @@
- `rome` was removed because it is no longer maintained and is succeeded by `biome`.
- The `prometheus-knot-exporter` was migrated to a version maintained by CZ.NIC. Various metric names have changed, so checking existing rules is recommended.
- The `services.mtr-exporter.target` has been removed in favor of `services.mtr-exporter.jobs` which allows specifying multiple targets.
- Setting `nixpkgs.config` options while providing an external `pkgs` instance will now raise an error instead of silently ignoring the options. NixOS modules no longer set `nixpkgs.config` to accomodate this. This specifically affects `services.locate`, `services.xserver.displayManager.lightdm.greeters.tiny` and `programs.firefox` NixOS modules. No manual intervention should be required in most cases, however, configurations relying on those modules affecting packages outside the system environment should switch to explicit overlays.
- `service.borgmatic.settings.location` and `services.borgmatic.configurations.<name>.location` are deprecated, please move your options out of sections to the global scope.
- `dagger` was removed because using a package called `dagger` and packaging it from source violates their trademark policy.
- `win-virtio` package was renamed to `virtio-win` to be consistent with the upstream package name.
- `ps3netsrv` has been replaced with the webman-mod fork, the executable has been renamed from `ps3netsrv++` to `ps3netsrv` and cli parameters have changed.
- `ssm-agent` package and module were renamed to `amazon-ssm-agent` to be consistent with the upstream package name.
- `services.kea.{ctrl-agent,dhcp-ddns,dhcp,dhcp6}` now use separate runtime directories instead of `/run/kea` to work around the runtime directory being cleared on service start.
## Other Notable Changes {#sec-release-23.11-notable-changes}
- The Cinnamon module now enables XDG desktop integration by default. If you are experiencing collisions related to xdg-desktop-portal-gtk you can safely remove `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];` from your NixOS configuration.
@ -290,18 +361,28 @@
- `jq` was updated to 1.7, its [first release in 5 years](https://github.com/jqlang/jq/releases/tag/jq-1.7).
- `zfs` was updated from 2.1.x to 2.2.0, [enabling newer kernel support and adding new features](https://github.com/openzfs/zfs/releases/tag/zfs-2.2.0).
- A new option was added to the virtualisation module that enables specifying explicitly named network interfaces in QEMU VMs. The existing `virtualisation.vlans` is still supported for cases where the name of the network interface is irrelevant.
- DocBook option documentation is no longer supported, all module documentation now uses markdown.
- `services.outline` can now be configured to use local filesystem storage instead of S3 storage using [services.outline.storage.storageType](#opt-services.outline.storage.storageType).
- `paperwork` was updated to version 2.2. Documents scanned with this version will not be visible to previous versions if you downgrade. See the [upstream announcement](https://forum.openpaper.work/t/paperwork-2-2-testing-phase/316#important-switch-from-jpeg-to-png-for-new-pages-2) for details and workarounds.
- `buildGoModule` `go-modules` attrs have been renamed to `goModules`.
- The `fonts.fonts` and `fonts.enableDefaultFonts` options have been renamed to `fonts.packages` and `fonts.enableDefaultPackages` respectively.
- `pkgs.openvpn3` now optionally supports systemd-resolved. `programs.openvpn3` will automatically enable systemd-resolved support if `config.services.resolved.enable` is enabled.
- `services.fail2ban.jails` can now be configured with attribute sets defining settings and filters instead of lines. The stringed options `daemonConfig` and `extraSettings` have respectively been replaced by `daemonSettings` and `jails.DEFAULT.settings` which use attribute sets.
- The application firewall `opensnitch` now uses the process monitor method eBPF as default as recommended by upstream. The method can be changed with the setting [services.opensnitch.settings.ProcMonitorMethod](#opt-services.opensnitch.settings.ProcMonitorMethod).
- `services.hedgedoc` has been heavily refactored, reducing the amount of declared options in the module. Most of the options should still work without any changes. Some options have been deprecated, as they no longer have any effect. See [#244941](https://github.com/NixOS/nixpkgs/pull/244941) for more details.
- The module [services.ankisyncd](#opt-services.ankisyncd.package) has been switched to [anki-sync-server-rs](https://github.com/ankicommunity/anki-sync-server-rs) from the old python version, which was difficult to update, had not been updated in a while, and did not support recent versions of anki.
Unfortunately all servers supporting new clients (newer version of anki-sync-server, anki's built in sync server and this new rust package) do not support the older sync protocol that was used in the old server, so such old clients will also need updating and in particular the anki package in nixpkgs is also being updated in this release.
The module update takes care of the new config syntax and the data itself (user login and cards) are compatible, so users of the module will be able to just log in again after updating both client and server without any extra action.
@ -329,6 +410,8 @@ The module update takes care of the new config syntax and the data itself (user
- `programs.gnupg.agent.pinentryFlavor` is now set in `/etc/gnupg/gpg-agent.conf`, and will no longer take precedence over a `pinentry-program` set in `~/.gnupg/gpg-agent.conf`.
- `programs.gnupg` now has the option `agent.settings` to set verbatim config values in `/etc/gnupg/gpg-agent.conf`.
- `dockerTools.buildImage`, `dockerTools.buildLayeredImage` and `dockerTools.streamLayeredImage` now use `lib.makeOverridable` to allow `dockerTools`-based images to be customized more efficiently at the nix-level.
- `services.influxdb2` now supports doing an automatic initial setup and provisioning of users, organizations, buckets and authentication tokens, see [#249502](https://github.com/NixOS/nixpkgs/pull/249502) for more details.
@ -339,6 +422,8 @@ The module update takes care of the new config syntax and the data itself (user
- Suricata was upgraded from 6.0 to 7.0 and no longer considers HTTP/2 support as experimental, see [upstream release notes](https://forum.suricata.io/t/suricata-7-0-0-released/3715) for more details.
- Cloud support in the `netdata` package is now disabled by default. To enable it use the `netdataCloud` package.
- `networking.nftables` now has the option `networking.nftables.table.<table>` to create tables
and have them be updated atomically, instead of flushing the ruleset.
@ -379,6 +464,8 @@ The module update takes care of the new config syntax and the data itself (user
If you use this feature, updates to CoreDNS may require updating `vendorHash` by following these steps again.
- `ffmpeg` default upgraded from `ffmpeg_5` to `ffmpeg_6`.
- `fusuma` now enables the following plugins: [appmatcher](https://github.com/iberianpig/fusuma-plugin-appmatcher), [keypress](https://github.com/iberianpig/fusuma-plugin-keypress), [sendkey](https://github.com/iberianpig/fusuma-plugin-sendkey), [tap](https://github.com/iberianpig/fusuma-plugin-tap) and [wmctrl](https://github.com/iberianpig/fusuma-plugin-wmctrl).
## Nixpkgs internals {#sec-release-23.11-nixpkgs-internals}
@ -411,6 +498,8 @@ The module update takes care of the new config syntax and the data itself (user
- `python3.pkgs.flitBuildHook` has been removed. Use `flit-core` and `format = "pyproject"` instead.
- The `extend` function of `llvmPackages` has been removed due it coming from the `tools` attrset thus only extending the `tool` attrset. A possible replacement is to construct the set from `libraries` and `tools`, or patch nixpkgs.
- The `qemu-vm.nix` module now supports disabling overriding `fileSystems` with
`virtualisation.fileSystems`. This enables the user to boot VMs from
"external" disk images not created by the qemu-vm module. You can stop the
@ -418,3 +507,7 @@ The module update takes care of the new config syntax and the data itself (user
`virtualisation.fileSystems = lib.mkForce { };`.
- The `electron` packages now places its application files in `$out/libexec/electron` instead of `$out/lib/electron`. Packages using electron-builder will fail to build and need to be adjusted by changing `lib` to `libexec`.
- `teleport` has been upgraded from major version 12 to major version 14. Please see upstream [upgrade instructions](https://goteleport.com/docs/management/operations/upgrading/) and release notes for versions [13](https://goteleport.com/docs/changelog/#1300-050823) and [14](https://goteleport.com/docs/changelog/#1400-092023). Note that Teleport does not officially support upgrades across more than one major version at a time. If you're running Teleport server components, it is recommended to first upgrade to an intermediate 13.x version by setting `services.teleport.package = pkgs.teleport_13`. Afterwards, this option can be removed to upgrade to the default version (14).
- The Linux kernel module `msr` (see [`msr(4)`](https://man7.org/linux/man-pages/man4/msr.4.html)), which provides an interface to read and write the model-specific registers (MSRs) of an x86 CPU, can now be configured via `hardware.cpu.x86.msr`.

View File

@ -34,9 +34,6 @@ evalConfigArgs@
in lib.optional (e != "") (import e)
}:
let pkgs_ = pkgs;
in
let
inherit (lib) optional;
@ -58,8 +55,9 @@ let
nixpkgs.system = lib.mkDefault system;
})
++
(optional (pkgs_ != null) {
_module.args.pkgs = lib.mkForce pkgs_;
(optional (pkgs != null) {
# This should be default priority, so it conflicts with any user-defined pkgs.
nixpkgs.pkgs = pkgs;
})
);
};
@ -109,10 +107,10 @@ let
nixosWithUserModules = noUserModules.extendModules { modules = allUserModules; };
withExtraArgs = nixosSystem: nixosSystem // {
withExtraAttrs = configuration: configuration // {
inherit extraArgs;
inherit (nixosSystem._module.args) pkgs;
extendModules = args: withExtraArgs (nixosSystem.extendModules args);
inherit (configuration._module.args) pkgs;
extendModules = args: withExtraAttrs (configuration.extendModules args);
};
in
withWarnings (withExtraArgs nixosWithUserModules)
withWarnings (withExtraAttrs nixosWithUserModules)

View File

@ -1,15 +1,22 @@
{ lib, stdenv, squashfsTools, closureInfo
, fileName ? "squashfs"
, # The root directory of the squashfs filesystem is filled with the
# closures of the Nix store paths listed here.
storeContents ? []
# Pseudo files to be added to squashfs image
, pseudoFiles ? []
, noStrip ? false
, # Compression parameters.
# For zstd compression you can use "zstd -Xcompression-level 6".
comp ? "xz -Xdict-size 100%"
}:
let
pseudoFilesArgs = lib.concatMapStrings (f: ''-p "${f}" '') pseudoFiles;
in
stdenv.mkDerivation {
name = "squashfs.img";
name = "${fileName}.img";
__structuredAttrs = true;
nativeBuildInputs = [ squashfsTools ];
@ -31,8 +38,8 @@ stdenv.mkDerivation {
'' + ''
# Generate the squashfs image.
mksquashfs nix-path-registration $(cat $closureInfo/store-paths) $out \
-no-hardlinks -keep-as-directory -all-root -b 1048576 -comp ${comp} \
mksquashfs nix-path-registration $(cat $closureInfo/store-paths) $out ${pseudoFilesArgs} \
-no-hardlinks ${lib.optionalString noStrip "-no-strip"} -keep-as-directory -all-root -b 1048576 -comp ${comp} \
-processors $NIX_BUILD_CORES
'';
}

View File

@ -40,6 +40,7 @@ rec {
otherHostGuestMatrix = {
aarch64-darwin = {
aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -machine virt,gic-version=2,accel=hvf:tcg -cpu max";
inherit (otherHostGuestMatrix.x86_64-darwin) x86_64-linux;
};
x86_64-darwin = {
x86_64-linux = "${qemuPkg}/bin/qemu-system-x86_64 -machine type=q35,accel=hvf:tcg -cpu max";

View File

@ -65,6 +65,9 @@ in {
'' + optionalString (def.vrfConfig != { }) ''
[VRF]
${attrsToSection def.vrfConfig}
'' + optionalString (def.wlanConfig != { }) ''
[WLAN]
${attrsToSection def.wlanConfig}
'' + optionalString (def.batmanAdvancedConfig != { }) ''
[BatmanAdvanced]
${attrsToSection def.batmanAdvancedConfig}

View File

@ -19,6 +19,8 @@ from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
from test_driver.logger import rootlog
from .qmp import QMPSession
CHAR_TO_KEY = {
"A": "shift-a",
"N": "shift-n",
@ -144,6 +146,7 @@ class StartCommand:
def cmd(
self,
monitor_socket_path: Path,
qmp_socket_path: Path,
shell_socket_path: Path,
allow_reboot: bool = False,
) -> str:
@ -167,6 +170,7 @@ class StartCommand:
return (
f"{self._cmd}"
f" -qmp unix:{qmp_socket_path},server=on,wait=off"
f" -monitor unix:{monitor_socket_path}"
f" -chardev socket,id=shell,path={shell_socket_path}"
f"{qemu_opts}"
@ -194,11 +198,14 @@ class StartCommand:
state_dir: Path,
shared_dir: Path,
monitor_socket_path: Path,
qmp_socket_path: Path,
shell_socket_path: Path,
allow_reboot: bool,
) -> subprocess.Popen:
return subprocess.Popen(
self.cmd(monitor_socket_path, shell_socket_path, allow_reboot),
self.cmd(
monitor_socket_path, qmp_socket_path, shell_socket_path, allow_reboot
),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
@ -309,6 +316,7 @@ class Machine:
shared_dir: Path
state_dir: Path
monitor_path: Path
qmp_path: Path
shell_path: Path
start_command: StartCommand
@ -317,6 +325,7 @@ class Machine:
process: Optional[subprocess.Popen]
pid: Optional[int]
monitor: Optional[socket.socket]
qmp_client: Optional[QMPSession]
shell: Optional[socket.socket]
serial_thread: Optional[threading.Thread]
@ -352,6 +361,7 @@ class Machine:
self.state_dir = self.tmp_dir / f"vm-state-{self.name}"
self.monitor_path = self.state_dir / "monitor"
self.qmp_path = self.state_dir / "qmp"
self.shell_path = self.state_dir / "shell"
if (not self.keep_vm_state) and self.state_dir.exists():
self.cleanup_statedir()
@ -360,6 +370,7 @@ class Machine:
self.process = None
self.pid = None
self.monitor = None
self.qmp_client = None
self.shell = None
self.serial_thread = None
@ -791,6 +802,28 @@ class Machine:
with self.nested(f"waiting for TCP port {port} on {addr}"):
retry(port_is_open, timeout)
def wait_for_open_unix_socket(
self, addr: str, is_datagram: bool = False, timeout: int = 900
) -> None:
"""
Wait until a process is listening on the given UNIX-domain socket
(default to a UNIX-domain stream socket).
"""
nc_flags = [
"-z",
"-uU" if is_datagram else "-U",
]
def socket_is_open(_: Any) -> bool:
status, _ = self.execute(f"nc {' '.join(nc_flags)} {addr}")
return status == 0
with self.nested(
f"waiting for UNIX-domain {'datagram' if is_datagram else 'stream'} on '{addr}'"
):
retry(socket_is_open, timeout)
def wait_for_closed_port(
self, port: int, addr: str = "localhost", timeout: int = 900
) -> None:
@ -1090,11 +1123,13 @@ class Machine:
self.state_dir,
self.shared_dir,
self.monitor_path,
self.qmp_path,
self.shell_path,
allow_reboot,
)
self.monitor, _ = monitor_socket.accept()
self.shell, _ = shell_socket.accept()
self.qmp_client = QMPSession.from_path(self.qmp_path)
# Store last serial console lines for use
# of wait_for_console_text

View File

@ -0,0 +1,98 @@
import json
import logging
import os
import socket
from collections.abc import Iterator
from pathlib import Path
from queue import Queue
from typing import Any
logger = logging.getLogger(__name__)
class QMPAPIError(RuntimeError):
def __init__(self, message: dict[str, Any]):
assert "error" in message, "Not an error message!"
try:
self.class_name = message["class"]
self.description = message["desc"]
# NOTE: Some errors can occur before the Server is able to read the
# id member; in these cases the id member will not be part of the
# error response, even if provided by the client.
self.transaction_id = message.get("id")
except KeyError:
raise RuntimeError("Malformed QMP API error response")
def __str__(self) -> str:
return f"<QMP API error related to transaction {self.transaction_id} [{self.class_name}]: {self.description}>"
class QMPSession:
def __init__(self, sock: socket.socket) -> None:
self.sock = sock
self.results: Queue[dict[str, str]] = Queue()
self.pending_events: Queue[dict[str, Any]] = Queue()
self.reader = sock.makefile("r")
self.writer = sock.makefile("w")
# Make the reader non-blocking so we can kind of select on it.
os.set_blocking(self.reader.fileno(), False)
hello = self._wait_for_new_result()
logger.debug(f"Got greeting from QMP API: {hello}")
# The greeting message format is:
# { "QMP": { "version": json-object, "capabilities": json-array } }
assert "QMP" in hello, f"Unexpected result: {hello}"
self.send("qmp_capabilities")
@classmethod
def from_path(cls, path: Path) -> "QMPSession":
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(str(path))
return cls(sock)
def __del__(self) -> None:
self.sock.close()
def _wait_for_new_result(self) -> dict[str, str]:
assert self.results.empty(), "Results set is not empty, missed results!"
while self.results.empty():
self.read_pending_messages()
return self.results.get()
def read_pending_messages(self) -> None:
line = self.reader.readline()
if not line:
return
evt_or_result = json.loads(line)
logger.debug(f"Received a message: {evt_or_result}")
# It's a result
if "return" in evt_or_result or "QMP" in evt_or_result:
self.results.put(evt_or_result)
# It's an event
elif "event" in evt_or_result:
self.pending_events.put(evt_or_result)
else:
raise QMPAPIError(evt_or_result)
def wait_for_event(self, timeout: int = 10) -> dict[str, Any]:
while self.pending_events.empty():
self.read_pending_messages()
return self.pending_events.get(timeout=timeout)
def events(self, timeout: int = 10) -> Iterator[dict[str, Any]]:
while not self.pending_events.empty():
yield self.pending_events.get(timeout=timeout)
def send(self, cmd: str, args: dict[str, str] = {}) -> dict[str, str]:
self.read_pending_messages()
assert self.results.empty(), "Results set is not empty, missed results!"
data: dict[str, Any] = dict(execute=cmd)
if args != {}:
data["arguments"] = args
logger.debug(f"Sending {data} to QMP...")
json.dump(data, self.writer)
self.writer.write("\n")
self.writer.flush()
return self._wait_for_new_result()

View File

@ -28,15 +28,17 @@ let
{
virtualisation.qemu.package = testModuleArgs.config.qemu.package;
})
(optionalAttrs (!config.node.pkgsReadOnly) {
({ options, ... }: {
key = "nodes.nix-pkgs";
config = {
# Ensure we do not use aliases. Ideally this is only set
# when the test framework is used by Nixpkgs NixOS tests.
nixpkgs.config.allowAliases = false;
# TODO: switch to nixpkgs.hostPlatform and make sure containers-imperative test still evaluates.
nixpkgs.system = hostPkgs.stdenv.hostPlatform.system;
};
config = optionalAttrs (!config.node.pkgsReadOnly) (
mkIf (!options.nixpkgs.pkgs.isDefined) {
# Ensure we do not use aliases. Ideally this is only set
# when the test framework is used by Nixpkgs NixOS tests.
nixpkgs.config.allowAliases = false;
# TODO: switch to nixpkgs.hostPlatform and make sure containers-imperative test still evaluates.
nixpkgs.system = hostPkgs.stdenv.hostPlatform.system;
}
);
})
testModuleArgs.config.extraBaseModules
];

View File

@ -127,8 +127,8 @@ in
${optionalString (config.environment.sessionVariables ? XKB_CONFIG_ROOT)
"-I${config.environment.sessionVariables.XKB_CONFIG_ROOT}"
} \
-model '${xkbModel}' -layout '${layout}' \
-option '${xkbOptions}' -variant '${xkbVariant}' > "$out"
-model '${xkb.model}' -layout '${xkb.layout}' \
-option '${xkb.options}' -variant '${xkb.variant}' > "$out"
'');
}

View File

@ -0,0 +1,49 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.fanout;
mknodCmds = n: lib.lists.imap0 (i: s:
"mknod /dev/fanout${builtins.toString i} c $MAJOR ${builtins.toString i}"
) (lib.lists.replicate n "");
in
{
options.services.fanout = {
enable = lib.mkEnableOption (lib.mdDoc "fanout");
fanoutDevices = lib.mkOption {
type = lib.types.int;
default = 1;
description = "Number of /dev/fanout devices";
};
bufferSize = lib.mkOption {
type = lib.types.int;
default = 16384;
description = "Size of /dev/fanout buffer in bytes";
};
};
config = lib.mkIf cfg.enable {
boot.extraModulePackages = [ config.boot.kernelPackages.fanout.out ];
boot.kernelModules = [ "fanout" ];
boot.extraModprobeConfig = ''
options fanout buffersize=${builtins.toString cfg.bufferSize}
'';
systemd.services.fanout = {
description = "Bring up /dev/fanout devices";
script = ''
MAJOR=$(${pkgs.gnugrep}/bin/grep fanout /proc/devices | ${pkgs.gawk}/bin/awk '{print $1}')
${lib.strings.concatLines (mknodCmds cfg.fanoutDevices)}
'';
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
User = "root";
RemainAfterExit = "yes";
Restart = "no";
};
};
};
}

View File

@ -1,43 +0,0 @@
{ config, lib, pkgs, ... }:
{
options = {
gnu = lib.mkOption {
type = lib.types.bool;
default = false;
description = lib.mdDoc ''
When enabled, GNU software is chosen by default whenever a there is
a choice between GNU and non-GNU software (e.g., GNU lsh
vs. OpenSSH).
'';
};
};
config = lib.mkIf config.gnu {
environment.systemPackages = with pkgs;
# TODO: Adjust `requiredPackages' from `system-path.nix'.
# TODO: Add Inetutils once it has the new `ifconfig'.
[ parted
#fdisk # XXX: GNU fdisk currently fails to build and it's redundant
# with the `parted' command.
nano zile
texinfo # for the stand-alone Info reader
]
++ lib.optional (!stdenv.isAarch32) grub2;
# GNU GRUB, where available.
boot.loader.grub.enable = !pkgs.stdenv.isAarch32;
# GNU lsh.
services.openssh.enable = false;
services.lshd.enable = true;
programs.ssh.startAgent = false;
services.xserver.startGnuPGAgent = true;
# TODO: GNU dico.
# TODO: GNU Inetutils' inetd.
# TODO: GNU Pies.
};
}

View File

@ -7,7 +7,7 @@ let
in
{
options.networking.iproute2 = {
enable = mkEnableOption (lib.mdDoc "copy IP route configuration files");
enable = mkEnableOption (lib.mdDoc "copying IP route configuration files");
rttablesExtraConfig = mkOption {
type = types.lines;
default = "";

View File

@ -1,121 +1,154 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.qt;
isQGnome = cfg.platformTheme == "gnome" && builtins.elem cfg.style ["adwaita" "adwaita-dark"];
isQtStyle = cfg.platformTheme == "gtk2" && !(builtins.elem cfg.style ["adwaita" "adwaita-dark"]);
isQt5ct = cfg.platformTheme == "qt5ct";
isLxqt = cfg.platformTheme == "lxqt";
isKde = cfg.platformTheme == "kde";
platformPackages = with pkgs; {
gnome = [ qgnomeplatform qgnomeplatform-qt6 ];
gtk2 = [ libsForQt5.qtstyleplugins qt6Packages.qt6gtk2 ];
kde = [ libsForQt5.plasma-integration libsForQt5.systemsettings ];
lxqt = [ lxqt.lxqt-qtplugin lxqt.lxqt-config ];
qt5ct = [ libsForQt5.qt5ct qt6Packages.qt6ct ];
};
packages =
if isQGnome then [
pkgs.qgnomeplatform
pkgs.adwaita-qt
pkgs.qgnomeplatform-qt6
pkgs.adwaita-qt6
]
else if isQtStyle then [ pkgs.libsForQt5.qtstyleplugins pkgs.qt6Packages.qt6gtk2 ]
else if isQt5ct then [ pkgs.libsForQt5.qt5ct pkgs.qt6Packages.qt6ct ]
else if isLxqt then [ pkgs.lxqt.lxqt-qtplugin pkgs.lxqt.lxqt-config ]
else if isKde then [ pkgs.libsForQt5.plasma-integration pkgs.libsForQt5.systemsettings ]
else throw "`qt.platformTheme` ${cfg.platformTheme} and `qt.style` ${cfg.style} are not compatible.";
stylePackages = with pkgs; {
bb10bright = [ libsForQt5.qtstyleplugins ];
bb10dark = [ libsForQt5.qtstyleplugins ];
cde = [ libsForQt5.qtstyleplugins ];
cleanlooks = [ libsForQt5.qtstyleplugins ];
gtk2 = [ libsForQt5.qtstyleplugins qt6Packages.qt6gtk2 ];
motif = [ libsForQt5.qtstyleplugins ];
plastique = [ libsForQt5.qtstyleplugins ];
adwaita = [ adwaita-qt adwaita-qt6 ];
adwaita-dark = [ adwaita-qt adwaita-qt6 ];
adwaita-highcontrast = [ adwaita-qt adwaita-qt6 ];
adwaita-highcontrastinverse = [ adwaita-qt adwaita-qt6 ];
breeze = [ libsForQt5.breeze-qt5 ];
kvantum = [ libsForQt5.qtstyleplugin-kvantum qt6Packages.qtstyleplugin-kvantum ];
};
in
{
meta.maintainers = [ maintainers.romildo ];
meta.maintainers = with lib.maintainers; [ romildo thiagokokada ];
imports = [
(mkRenamedOptionModule ["qt5" "enable" ] ["qt" "enable" ])
(mkRenamedOptionModule ["qt5" "platformTheme" ] ["qt" "platformTheme" ])
(mkRenamedOptionModule ["qt5" "style" ] ["qt" "style" ])
(lib.mkRenamedOptionModule [ "qt5" "enable" ] [ "qt" "enable" ])
(lib.mkRenamedOptionModule [ "qt5" "platformTheme" ] [ "qt" "platformTheme" ])
(lib.mkRenamedOptionModule [ "qt5" "style" ] [ "qt" "style" ])
];
options = {
qt = {
enable = lib.mkEnableOption "" // {
description = lib.mdDoc ''
Whether to enable Qt configuration, including theming.
enable = mkEnableOption (lib.mdDoc "Qt theming configuration");
Enabling this option is necessary for Qt plugins to work in the
installed profiles (e.g.: `nix-env -i` or `environment.systemPackages`).
'';
};
platformTheme = mkOption {
type = types.enum [
"gtk2"
"gnome"
"lxqt"
"qt5ct"
"kde"
];
platformTheme = lib.mkOption {
type = with lib.types; nullOr (enum (lib.attrNames platformPackages));
default = null;
example = "gnome";
relatedPackages = [
"qgnomeplatform"
"qgnomeplatform-qt6"
["libsForQt5" "qtstyleplugins"]
["libsForQt5" "qt5ct"]
["lxqt" "lxqt-qtplugin"]
["libsForQt5" "plasma-integration"]
[ "libsForQt5" "plasma-integration" ]
[ "libsForQt5" "qt5ct" ]
[ "libsForQt5" "qtstyleplugins" ]
[ "libsForQt5" "systemsettings" ]
[ "lxqt" "lxqt-config" ]
[ "lxqt" "lxqt-qtplugin" ]
[ "qt6Packages" "qt6ct" ]
[ "qt6Packages" "qt6gtk2" ]
];
description = lib.mdDoc ''
Selects the platform theme to use for Qt applications.
The options are
- `gtk`: Use GTK theme with [qtstyleplugins](https://github.com/qt/qtstyleplugins)
- `gnome`: Use GNOME theme with [qgnomeplatform](https://github.com/FedoraQt/QGnomePlatform)
- `gtk2`: Use GTK theme with [qtstyleplugins](https://github.com/qt/qtstyleplugins)
- `kde`: Use Qt settings from Plasma.
- `lxqt`: Use LXQt style set using the [lxqt-config-appearance](https://github.com/lxqt/lxqt-config)
application.
- `qt5ct`: Use Qt style set using the [qt5ct](https://sourceforge.net/projects/qt5ct/)
application.
- `kde`: Use Qt settings from Plasma.
and [qt6ct](https://github.com/trialuser02/qt6ct) applications.
'';
};
style = mkOption {
type = types.enum [
"adwaita"
"adwaita-dark"
"cleanlooks"
"gtk2"
"motif"
"plastique"
];
style = lib.mkOption {
type = with lib.types; nullOr (enum (lib.attrNames stylePackages));
default = null;
example = "adwaita";
relatedPackages = [
"adwaita-qt"
"adwaita-qt6"
["libsForQt5" "qtstyleplugins"]
["qt6Packages" "qt6gtk2"]
[ "libsForQt5" "breeze-qt5" ]
[ "libsForQt5" "qtstyleplugin-kvantum" ]
[ "libsForQt5" "qtstyleplugins" ]
[ "qt6Packages" "qt6gtk2" ]
[ "qt6Packages" "qtstyleplugin-kvantum" ]
];
description = lib.mdDoc ''
Selects the style to use for Qt applications.
The options are
- `adwaita`, `adwaita-dark`: Use Adwaita Qt style with
- `adwaita`, `adwaita-dark`, `adwaita-highcontrast`, `adawaita-highcontrastinverse`:
Use Adwaita Qt style with
[adwaita](https://github.com/FedoraQt/adwaita-qt)
- `cleanlooks`, `gtk2`, `motif`, `plastique`: Use styles from
- `breeze`: Use the Breeze style from
[breeze](https://github.com/KDE/breeze)
- `bb10bright`, `bb10dark`, `cleanlooks`, `gtk2`, `motif`, `plastique`:
Use styles from
[qtstyleplugins](https://github.com/qt/qtstyleplugins)
- `kvantum`: Use styles from
[kvantum](https://github.com/tsujan/Kvantum)
'';
};
};
};
config = mkIf cfg.enable {
config = lib.mkIf cfg.enable {
assertions =
let
gnomeStyles = [
"adwaita"
"adwaita-dark"
"adwaita-highcontrast"
"adwaita-highcontrastinverse"
"breeze"
];
in
[
{
assertion = cfg.platformTheme == "gnome" -> (builtins.elem cfg.style gnomeStyles);
message = ''
`qt.platformTheme` "gnome" must have `qt.style` set to a theme that supports both Qt and Gtk,
for example: ${lib.concatStringsSep ", " gnomeStyles}.
'';
}
];
environment.variables = {
QT_QPA_PLATFORMTHEME = cfg.platformTheme;
QT_STYLE_OVERRIDE = mkIf (! (isQt5ct || isLxqt || isKde)) cfg.style;
QT_QPA_PLATFORMTHEME = lib.mkIf (cfg.platformTheme != null) cfg.platformTheme;
QT_STYLE_OVERRIDE = lib.mkIf (cfg.style != null) cfg.style;
};
environment.profileRelativeSessionVariables = let
qtVersions = with pkgs; [ qt5 qt6 ];
in {
QT_PLUGIN_PATH = map (qt: "/${qt.qtbase.qtPluginPrefix}") qtVersions;
QML2_IMPORT_PATH = map (qt: "/${qt.qtbase.qtQmlPrefix}") qtVersions;
};
environment.systemPackages = packages;
environment.profileRelativeSessionVariables =
let
qtVersions = with pkgs; [ qt5 qt6 ];
in
{
QT_PLUGIN_PATH = map (qt: "/${qt.qtbase.qtPluginPrefix}") qtVersions;
QML2_IMPORT_PATH = map (qt: "/${qt.qtbase.qtQmlPrefix}") qtVersions;
};
environment.systemPackages =
lib.optionals (cfg.platformTheme != null) (platformPackages.${cfg.platformTheme})
++ lib.optionals (cfg.style != null) (stylePackages.${cfg.style});
};
}

View File

@ -15,7 +15,7 @@ let
in
{
options.networking.stevenblack = {
enable = mkEnableOption (mdDoc "Enable the stevenblack hosts file blocklist");
enable = mkEnableOption (mdDoc "the stevenblack hosts file blocklist");
block = mkOption {
type = types.listOf (types.enum [ "fakenews" "gambling" "porn" "social" ]);

View File

@ -89,12 +89,6 @@ in
for a running system, entries can be removed for a more
minimal NixOS installation.
Note: If `pkgs.nano` is removed from this list,
make sure another editor is installed and the
`EDITOR` environment variable is set to it.
Environment variables can be set using
{option}`environment.variables`.
Like with systemPackages, packages are installed to
{file}`/run/current-system/sw`. They are
automatically available to all users, and are

View File

@ -172,6 +172,17 @@ let
'';
};
ignoreShellProgramCheck = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
By default, nixos will check that programs.SHELL.enable is set to
true if the user has a custom shell specified. If that behavior isn't
required and there are custom overrides in place to make sure that the
shell is functional, set this to true.
'';
};
subUidRanges = mkOption {
type = with types; listOf (submodule subordinateUidRange);
default = [];
@ -330,6 +341,20 @@ let
administrator before being able to use the system again.
'';
};
linger = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Whether to enable lingering for this user. If true, systemd user
units will start at boot, rather than starting at login and stopping
at logout. This is the declarative equivalent of running
`loginctl enable-linger` for this user.
If false, user units will not be started until the user logs in, and
may be stopped on logout depending on the settings in `logind.conf`.
'';
};
};
config = mkMerge
@ -449,6 +474,8 @@ let
gidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) cfg.groups) "gid";
sdInitrdUidsAreUnique = idsAreUnique (filterAttrs (n: u: u.uid != null) config.boot.initrd.systemd.users) "uid";
sdInitrdGidsAreUnique = idsAreUnique (filterAttrs (n: g: g.gid != null) config.boot.initrd.systemd.groups) "gid";
groupNames = lib.mapAttrsToList (n: g: g.name) cfg.groups;
usersWithoutExistingGroup = lib.filterAttrs (n: u: !lib.elem u.group groupNames) cfg.users;
spec = pkgs.writeText "users-groups.json" (builtins.toJSON {
inherit (cfg) mutableUsers;
@ -661,6 +688,20 @@ in {
'';
};
system.activationScripts.update-lingering = let
lingerDir = "/var/lib/systemd/linger";
lingeringUsers = map (u: u.name) (attrValues (flip filterAttrs cfg.users (n: u: u.linger)));
lingeringUsersFile = builtins.toFile "lingering-users"
(concatStrings (map (s: "${s}\n")
(sort (a: b: a < b) lingeringUsers))); # this sorting is important for `comm` to work correctly
in stringAfter [ "users" ] ''
if [ -e ${lingerDir} ] ; then
cd ${lingerDir}
ls ${lingerDir} | sort | comm -3 -1 ${lingeringUsersFile} - | xargs -r ${pkgs.systemd}/bin/loginctl disable-linger
ls ${lingerDir} | sort | comm -3 -2 ${lingeringUsersFile} - | xargs -r ${pkgs.systemd}/bin/loginctl enable-linger
fi
'';
# Warn about user accounts with deprecated password hashing schemes
system.activationScripts.hashes = {
deps = [ "users" ];
@ -700,7 +741,8 @@ in {
environment.profiles = [
"$HOME/.nix-profile"
"\${XDG_STATE_HOME:-$HOME/.local/state}/nix/profile"
"\${XDG_STATE_HOME}/nix/profile"
"$HOME/.local/state/nix/profile"
"/etc/profiles/per-user/$USER"
];
@ -750,6 +792,18 @@ in {
{ assertion = !cfg.enforceIdUniqueness || (sdInitrdUidsAreUnique && sdInitrdGidsAreUnique);
message = "systemd initrd UIDs and GIDs must be unique!";
}
{ assertion = usersWithoutExistingGroup == {};
message =
let
errUsers = lib.attrNames usersWithoutExistingGroup;
missingGroups = lib.unique (lib.mapAttrsToList (n: u: u.group) usersWithoutExistingGroup);
mkConfigHint = group: "users.groups.${group} = {};";
in ''
The following users have a primary group that is undefined: ${lib.concatStringsSep " " errUsers}
Hint: Add this to your NixOS configuration:
${lib.concatStringsSep "\n " (map mkConfigHint missingGroups)}
'';
}
{ # If mutableUsers is false, to prevent users creating a
# configuration that locks them out of the system, ensure that
# there is at least one "privileged" account that has a
@ -810,13 +864,17 @@ in {
'';
}
] ++ (map (shell: {
assertion = (user.shell == pkgs.${shell}) -> (config.programs.${shell}.enable == true);
assertion = !user.ignoreShellProgramCheck -> (user.shell == pkgs.${shell}) -> (config.programs.${shell}.enable == true);
message = ''
users.users.${user.name}.shell is set to ${shell}, but
programs.${shell}.enable is not true. This will cause the ${shell}
shell to lack the basic nix directories in its PATH and might make
logging in as that user impossible. You can fix it with:
programs.${shell}.enable = true;
If you know what you're doing and you are fine with the behavior,
set users.users.${user.name}.ignoreShellProgramCheck = true;
instead.
'';
}) [
"fish"

View File

@ -8,13 +8,13 @@ in
{
options.programs.corectrl = {
enable = mkEnableOption (lib.mdDoc ''
A tool to overclock amd graphics cards and processors.
CoreCtrl, a tool to overclock amd graphics cards and processors.
Add your user to the corectrl group to run corectrl without needing to enter your password
'');
gpuOverclock = {
enable = mkEnableOption (lib.mdDoc ''
true
GPU overclocking
'');
ppfeaturemask = mkOption {
type = types.str;

View File

@ -0,0 +1,91 @@
{ lib
, config
, options
, ...
}:
let
inherit (builtins) hasAttr;
inherit (lib) mkIf mdDoc;
cfg = config.hardware.cpu.x86.msr;
opt = options.hardware.cpu.x86.msr;
defaultGroup = "msr";
isDefaultGroup = cfg.group == defaultGroup;
set = "to set for devices of the `msr` kernel subsystem.";
# Generates `foo=bar` parameters to pass to the kernel.
# If `module = baz` is passed, generates `baz.foo=bar`.
# Adds double quotes on demand to handle `foo="bar baz"`.
kernelParam = { module ? null }: name: value:
assert lib.asserts.assertMsg (!lib.strings.hasInfix "=" name) "kernel parameter cannot have '=' in name";
let
key = (if module == null then "" else module + ".") + name;
valueString = lib.generators.mkValueStringDefault {} value;
quotedValueString = if lib.strings.hasInfix " " valueString
then lib.strings.escape ["\""] valueString
else valueString;
in "${key}=${quotedValueString}";
msrKernelParam = kernelParam { module = "msr"; };
in
{
options.hardware.cpu.x86.msr = with lib.options; with lib.types; {
enable = mkEnableOption (mdDoc "the `msr` (Model-Specific Registers) kernel module and configure `udev` rules for its devices (usually `/dev/cpu/*/msr`)");
owner = mkOption {
type = str;
default = "root";
example = "nobody";
description = mdDoc "Owner ${set}";
};
group = mkOption {
type = str;
default = defaultGroup;
example = "nobody";
description = mdDoc "Group ${set}";
};
mode = mkOption {
type = str;
default = "0640";
example = "0660";
description = mdDoc "Mode ${set}";
};
settings = mkOption {
type = submodule {
freeformType = attrsOf (oneOf [ bool int str ]);
options.allow-writes = mkOption {
type = nullOr (enum ["on" "off"]);
default = null;
description = "Whether to allow writes to MSRs (`\"on\"`) or not (`\"off\"`).";
};
};
default = {};
description = "Parameters for the `msr` kernel module.";
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = hasAttr cfg.owner config.users.users;
message = "Owner '${cfg.owner}' set in `${opt.owner}` is not configured via `${options.users.users}.\"${cfg.owner}\"`.";
}
{
assertion = isDefaultGroup || (hasAttr cfg.group config.users.groups);
message = "Group '${cfg.group}' set in `${opt.group}` is not configured via `${options.users.groups}.\"${cfg.group}\"`.";
}
];
boot = {
kernelModules = [ "msr" ];
kernelParams = lib.attrsets.mapAttrsToList msrKernelParam (lib.attrsets.filterAttrs (_: value: value != null) cfg.settings);
};
users.groups.${cfg.group} = mkIf isDefaultGroup { };
services.udev.extraRules = ''
SUBSYSTEM=="msr", OWNER="${cfg.owner}", GROUP="${cfg.group}", MODE="${cfg.mode}"
'';
};
meta = with lib; {
maintainers = with maintainers; [ lorenzleutgeb ];
};
}

View File

@ -66,36 +66,32 @@ let
};
filterDTBs = src: if cfg.filter == null
then "${src}/dtbs"
then src
else
pkgs.runCommand "dtbs-filtered" {} ''
mkdir -p $out
cd ${src}/dtbs
cd ${src}
find . -type f -name '${cfg.filter}' -print0 \
| xargs -0 cp -v --no-preserve=mode --target-directory $out --parents
'';
filteredDTBs = filterDTBs cfg.kernelPackage;
# Compile single Device Tree overlay source
# file (.dts) into its compiled variant (.dtbo)
compileDTS = name: f: pkgs.callPackage({ stdenv, dtc }: stdenv.mkDerivation {
name = "${name}-dtbo";
nativeBuildInputs = [ dtc ];
buildCommand = ''
$CC -E -nostdinc -I${getDev cfg.kernelPackage}/lib/modules/${cfg.kernelPackage.modDirVersion}/source/scripts/dtc/include-prefixes -undef -D__DTS__ -x assembler-with-cpp ${f} | \
dtc -I dts -O dtb -@ -o $out
'';
}) {};
filteredDTBs = filterDTBs cfg.dtbSource;
# Fill in `dtboFile` for each overlay if not set already.
# Existence of one of these is guarded by assertion below
withDTBOs = xs: flip map xs (o: o // { dtboFile =
let
includePaths = ["${getDev cfg.kernelPackage}/lib/modules/${cfg.kernelPackage.modDirVersion}/source/scripts/dtc/include-prefixes"] ++ cfg.dtboBuildExtraIncludePaths;
extraPreprocessorFlags = cfg.dtboBuildExtraPreprocessorFlags;
in
if o.dtboFile == null then
if o.dtsFile != null then compileDTS o.name o.dtsFile
else compileDTS o.name (pkgs.writeText "dts" o.dtsText)
let
dtsFile = if o.dtsFile == null then (pkgs.writeText "dts" o.dtsText) else o.dtsFile;
in
pkgs.deviceTree.compileDTS {
name = "${o.name}-dtbo";
inherit includePaths extraPreprocessorFlags dtsFile;
}
else o.dtboFile; } );
in
@ -121,7 +117,39 @@ in
example = literalExpression "pkgs.linux_latest";
type = types.path;
description = lib.mdDoc ''
Kernel package containing the base device-tree (.dtb) to boot. Uses
Kernel package where device tree include directory is from. Also used as default source of dtb package to apply overlays to
'';
};
dtboBuildExtraPreprocessorFlags = mkOption {
default = [];
example = literalExpression "[ \"-DMY_DTB_DEFINE\" ]";
type = types.listOf types.str;
description = lib.mdDoc ''
Additional flags to pass to the preprocessor during dtbo compilations
'';
};
dtboBuildExtraIncludePaths = mkOption {
default = [];
example = literalExpression ''
[
./my_custom_include_dir_1
./custom_include_dir_2
]
'';
type = types.listOf types.path;
description = lib.mdDoc ''
Additional include paths that will be passed to the preprocessor when creating the final .dts to compile into .dtbo
'';
};
dtbSource = mkOption {
default = "${cfg.kernelPackage}/dtbs";
defaultText = literalExpression "\${cfg.kernelPackage}/dtbs";
type = types.path;
description = lib.mdDoc ''
Path to dtb directory that overlays and other processing will be applied to. Uses
device trees bundled with the Linux kernel by default.
'';
};

View File

@ -11,7 +11,7 @@ in
enable = mkEnableOption (lib.mdDoc ''
i2c devices support. By default access is granted to users in the "i2c"
group (will be created if non-existent) and any user with a seat, meaning
logged on the computer locally.
logged on the computer locally
'');
group = mkOption {

View File

@ -11,7 +11,7 @@ in
non-root access to the firmware of UHK keyboards.
You need it when you want to flash a new firmware on the keyboard.
Access to the keyboard is granted to users in the "input" group.
You may want to install the uhk-agent package.
You may want to install the uhk-agent package
'');
};

View File

@ -11,7 +11,7 @@ in
udev rules for keyboards from ZSA like the ErgoDox EZ, Planck EZ and Moonlander Mark I.
You need it when you want to flash a new configuration on the keyboard
or use their live training in the browser.
You may want to install the wally-cli package.
You may want to install the wally-cli package
'');
};

View File

@ -50,7 +50,7 @@ in
options = {
hardware.openrazer = {
enable = mkEnableOption (lib.mdDoc ''
OpenRazer drivers and userspace daemon.
OpenRazer drivers and userspace daemon
'');
verboseLogging = mkOption {

View File

@ -9,7 +9,7 @@ in
{
options.hardware.tuxedo-keyboard = {
enable = mkEnableOption (lib.mdDoc ''
Enables the tuxedo-keyboard driver.
the tuxedo-keyboard driver.
To configure the driver, pass the options to the {option}`boot.kernelParams` configuration.
There are several parameters you can change. It's best to check at the source code description which options are supported.

View File

@ -24,7 +24,7 @@ in {
options = {
hardware.nvidia = {
datacenter.enable = lib.mkEnableOption (lib.mdDoc ''
Data Center drivers for NVIDIA cards on a NVLink topology.
Data Center drivers for NVIDIA cards on a NVLink topology
'');
datacenter.settings = lib.mkOption {
type = settingsFormat.type;
@ -79,18 +79,18 @@ in {
powerManagement.enable = lib.mkEnableOption (lib.mdDoc ''
experimental power management through systemd. For more information, see
the NVIDIA docs, on Chapter 21. Configuring Power Management Support.
the NVIDIA docs, on Chapter 21. Configuring Power Management Support
'');
powerManagement.finegrained = lib.mkEnableOption (lib.mdDoc ''
experimental power management of PRIME offload. For more information, see
the NVIDIA docs, on Chapter 22. PCI-Express Runtime D3 (RTD3) Power Management.
the NVIDIA docs, on Chapter 22. PCI-Express Runtime D3 (RTD3) Power Management
'');
dynamicBoost.enable = lib.mkEnableOption (lib.mdDoc ''
dynamic Boost balances power between the CPU and the GPU for improved
performance on supported laptops using the nvidia-powerd daemon. For more
information, see the NVIDIA docs, on Chapter 23. Dynamic Boost on Linux.
information, see the NVIDIA docs, on Chapter 23. Dynamic Boost on Linux
'');
modesetting.enable = lib.mkEnableOption (lib.mdDoc ''
@ -99,7 +99,7 @@ in {
Enabling this fixes screen tearing when using Optimus via PRIME (see
{option}`hardware.nvidia.prime.sync.enable`. This is not enabled
by default because it is not officially supported by NVIDIA and would not
work with SLI.
work with SLI
'');
prime.nvidiaBusId = lib.mkOption {
@ -153,11 +153,11 @@ in {
Note that this configuration will only be successful when a display manager
for which the {option}`services.xserver.displayManager.setupCommands`
option is supported is used.
option is supported is used
'');
prime.allowExternalGpu = lib.mkEnableOption (lib.mdDoc ''
configuring X to allow external NVIDIA GPUs when using Prime [Reverse] sync optimus.
configuring X to allow external NVIDIA GPUs when using Prime [Reverse] sync optimus
'');
prime.offload.enable = lib.mkEnableOption (lib.mdDoc ''
@ -166,7 +166,7 @@ in {
If this is enabled, then the bus IDs of the NVIDIA and Intel/AMD GPUs have to
be specified ({option}`hardware.nvidia.prime.nvidiaBusId` and
{option}`hardware.nvidia.prime.intelBusId` or
{option}`hardware.nvidia.prime.amdgpuBusId`).
{option}`hardware.nvidia.prime.amdgpuBusId`)
'');
prime.offload.enableOffloadCmd = lib.mkEnableOption (lib.mdDoc ''
@ -174,7 +174,7 @@ in {
for offloading programs to an nvidia device. To work, should have also enabled
{option}`hardware.nvidia.prime.offload.enable` or {option}`hardware.nvidia.prime.reverseSync.enable`.
Example usage `nvidia-offload sauerbraten_client`.
Example usage `nvidia-offload sauerbraten_client`
'');
prime.reverseSync.enable = lib.mkEnableOption (lib.mdDoc ''
@ -202,25 +202,25 @@ in {
Note that this configuration will only be successful when a display manager
for which the {option}`services.xserver.displayManager.setupCommands`
option is supported is used.
option is supported is used
'');
nvidiaSettings =
(lib.mkEnableOption (lib.mdDoc ''
nvidia-settings, NVIDIA's GUI configuration tool.
nvidia-settings, NVIDIA's GUI configuration tool
''))
// {default = true;};
nvidiaPersistenced = lib.mkEnableOption (lib.mdDoc ''
nvidia-persistenced a update for NVIDIA GPU headless mode, i.e.
It ensures all GPUs stay awake even during headless mode.
It ensures all GPUs stay awake even during headless mode
'');
forceFullCompositionPipeline = lib.mkEnableOption (lib.mdDoc ''
forcefully the full composition pipeline.
This sometimes fixes screen tearing issues.
This has been reported to reduce the performance of some OpenGL applications and may produce issues in WebGL.
It also drastically increases the time the driver needs to clock down after load.
It also drastically increases the time the driver needs to clock down after load
'');
package = lib.mkOption {
@ -269,9 +269,9 @@ in {
services.udev.extraRules =
''
# Create /dev/nvidia-uvm when the nvidia-uvm module is loaded.
KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidiactl c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) 255'"
KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'for i in $$(cat /proc/driver/nvidia/gpus/*/information | grep Minor | cut -d \ -f 4); do mknod -m 666 /dev/nvidia$${i} c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) $${i}; done'"
KERNEL=="nvidia_modeset", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-modeset c $$(grep nvidia-frontend /proc/devices | cut -d \ -f 1) 254'"
KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidiactl c 195 255'"
KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'for i in $$(cat /proc/driver/nvidia/gpus/*/information | grep Minor | cut -d \ -f 4); do mknod -m 666 /dev/nvidia$${i} c 195 $${i}; done'"
KERNEL=="nvidia_modeset", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-modeset c 195 254'"
KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 0'"
KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm-tools c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 1'"
'';

View File

@ -12,7 +12,7 @@ in
{
options.hardware.facetimehd.enable = mkEnableOption (lib.mdDoc "facetimehd kernel module");
options.hardware.facetimehd.enable = mkEnableOption (lib.mdDoc "the facetimehd kernel module");
options.hardware.facetimehd.withCalibration = mkOption {
default = false;

View File

@ -102,22 +102,6 @@ sub cpuManufacturer {
return $cpuinfo =~ /^vendor_id\s*:.* $id$/m;
}
# Determine CPU governor to use
if (-e "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") {
my $governors = read_file("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors");
# ondemand governor is not available on sandy bridge or later Intel CPUs
my @desired_governors = ("ondemand", "powersave");
my $e;
foreach $e (@desired_governors) {
if (index($governors, $e) != -1) {
last if (push @attrs, "powerManagement.cpuFreqGovernor = lib.mkDefault \"$e\";");
}
}
}
# Virtualization support?
push @kernelModules, "kvm-intel" if hasCPUFeature "vmx";
push @kernelModules, "kvm-amd" if hasCPUFeature "svm";

View File

@ -163,15 +163,15 @@ in
# console = {
# font = "Lat2-Terminus16";
# keyMap = "us";
# useXkbConfig = true; # use xkbOptions in tty.
# useXkbConfig = true; # use xkb.options in tty.
# };
$xserverConfig
$desktopConfiguration
# Configure keymap in X11
# services.xserver.layout = "us";
# services.xserver.xkbOptions = "eurosign:e,caps:escape";
# services.xserver.xkb.layout = "us";
# services.xserver.xkb.options = "eurosign:e,caps:escape";
# Enable CUPS to print documents.
# services.printing.enable = true;

View File

@ -69,7 +69,7 @@ in
#dialout = 27; # unused
polkituser = 28;
#utmp = 29; # unused
# ddclient = 30; # software removed
# ddclient = 30; # converted to DynamicUser = true
davfs2 = 31;
disnix = 33;
osgi = 34;
@ -394,7 +394,7 @@ in
dialout = 27;
#polkituser = 28; # currently unused, polkitd doesn't need a group
utmp = 29;
# ddclient = 30; # software removed
# ddclient = 30; # converted to DynamicUser = true
davfs2 = 31;
disnix = 33;
osgi = 34;

View File

@ -4,14 +4,15 @@ with lib;
let
cfg = config.services.locate;
isMLocate = hasPrefix "mlocate" cfg.locate.name;
isPLocate = hasPrefix "plocate" cfg.locate.name;
isMLocate = hasPrefix "mlocate" cfg.package.name;
isPLocate = hasPrefix "plocate" cfg.package.name;
isMorPLocate = isMLocate || isPLocate;
isFindutils = hasPrefix "findutils" cfg.locate.name;
isFindutils = hasPrefix "findutils" cfg.package.name;
in
{
imports = [
(mkRenamedOptionModule [ "services" "locate" "period" ] [ "services" "locate" "interval" ])
(mkRenamedOptionModule [ "services" "locate" "locate" ] [ "services" "locate" "package" ])
(mkRemovedOptionModule [ "services" "locate" "includeStore" ] "Use services.locate.prunePaths")
];
@ -25,10 +26,10 @@ in
'';
};
locate = mkOption {
package = mkOption {
type = package;
default = pkgs.findutils.locate;
defaultText = literalExpression "pkgs.findutils";
defaultText = literalExpression "pkgs.findutils.locate";
example = literalExpression "pkgs.mlocate";
description = lib.mdDoc ''
The locate implementation to use
@ -218,11 +219,11 @@ in
};
mlocate = mkIf isMLocate {
group = "mlocate";
source = "${cfg.locate}/bin/locate";
source = "${cfg.package}/bin/locate";
};
plocate = mkIf isPLocate {
group = "plocate";
source = "${cfg.locate}/bin/plocate";
source = "${cfg.package}/bin/plocate";
};
in
mkIf isMorPLocate {
@ -230,7 +231,7 @@ in
plocate = mkIf isPLocate (mkMerge [ common plocate ]);
};
environment.systemPackages = [ cfg.locate ];
environment.systemPackages = [ cfg.package ];
environment.variables.LOCATE_PATH = cfg.output;
@ -268,13 +269,13 @@ in
args = concatLists (map toFlags [ "pruneFS" "pruneNames" "prunePaths" ]);
in
''
exec ${cfg.locate}/bin/updatedb \
exec ${cfg.package}/bin/updatedb \
--output ${toString cfg.output} ${concatStringsSep " " args} \
--prune-bind-mounts ${if cfg.pruneBindMounts then "yes" else "no"} \
${concatStringsSep " " cfg.extraFlags}
''
else ''
exec ${cfg.locate}/bin/updatedb \
exec ${cfg.package}/bin/updatedb \
${optionalString (cfg.localuser != null && !isMorPLocate) "--localuser=${cfg.localuser}"} \
--output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags}
'';

View File

@ -5,7 +5,7 @@ let
inherit (config.nixops) enableDeprecatedAutoLuks;
in {
options.nixops.enableDeprecatedAutoLuks = lib.mkEnableOption (lib.mdDoc "Enable the deprecated NixOps AutoLuks module");
options.nixops.enableDeprecatedAutoLuks = lib.mkEnableOption (lib.mdDoc "the deprecated NixOps AutoLuks module");
config = {
assertions = [

View File

@ -187,7 +187,7 @@ in
hostPlatform = mkOption {
type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform
example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
example = { system = "aarch64-linux"; };
# Make sure that the final value has all fields for sake of other modules
# referring to this. TODO make `lib.systems` itself use the module system.
apply = lib.systems.elaborate;
@ -205,7 +205,7 @@ in
buildPlatform = mkOption {
type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform
default = cfg.hostPlatform;
example = { system = "x86_64-linux"; config = "x86_64-unknown-linux-gnu"; };
example = { system = "x86_64-linux"; };
# Make sure that the final value has all fields for sake of other modules
# referring to this.
apply = lib.systems.elaborate;
@ -228,7 +228,7 @@ in
localSystem = mkOption {
type = types.attrs; # TODO utilize lib.systems.parsedPlatform
default = { inherit (cfg) system; };
example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
example = { system = "aarch64-linux"; };
# Make sure that the final value has all fields for sake of other modules
# referring to this. TODO make `lib.systems` itself use the module system.
apply = lib.systems.elaborate;
@ -262,7 +262,7 @@ in
crossSystem = mkOption {
type = types.nullOr types.attrs; # TODO utilize lib.systems.parsedPlatform
default = null;
example = { system = "aarch64-linux"; config = "aarch64-unknown-linux-gnu"; };
example = { system = "aarch64-linux"; };
description = lib.mdDoc ''
Systems with a recently generated `hardware-configuration.nix`
may instead specify *only* {option}`nixpkgs.buildPlatform`,

View File

@ -2,11 +2,11 @@
./config/appstream.nix
./config/console.nix
./config/debug-info.nix
./config/fanout.nix
./config/fonts/fontconfig.nix
./config/fonts/fontdir.nix
./config/fonts/ghostscript.nix
./config/fonts/packages.nix
./config/gnu.nix
./config/gtk/gtk-icon-cache.nix
./config/i18n.nix
./config/iproute2.nix
@ -55,6 +55,7 @@
./hardware/cpu/amd-sev.nix
./hardware/cpu/intel-microcode.nix
./hardware/cpu/intel-sgx.nix
./hardware/cpu/x86-msr.nix
./hardware/decklink.nix
./hardware/device-tree.nix
./hardware/digitalbitbox.nix
@ -232,6 +233,7 @@
./programs/pantheon-tweaks.nix
./programs/partition-manager.nix
./programs/plotinus.nix
./programs/projecteur.nix
./programs/proxychains.nix
./programs/qdmr.nix
./programs/qt5ct.nix
@ -266,6 +268,7 @@
./programs/usbtop.nix
./programs/vim.nix
./programs/wavemon.nix
./programs/wayland/cardboard.nix
./programs/wayland/river.nix
./programs/wayland/sway.nix
./programs/wayland/waybar.nix
@ -416,6 +419,7 @@
./services/databases/couchdb.nix
./services/databases/dgraph.nix
./services/databases/dragonflydb.nix
./services/databases/ferretdb.nix
./services/databases/firebird.nix
./services/databases/foundationdb.nix
./services/databases/hbase-standalone.nix
@ -517,6 +521,7 @@
./services/hardware/hddfancontrol.nix
./services/hardware/illum.nix
./services/hardware/interception-tools.nix
./services/hardware/iptsd.nix
./services/hardware/irqbalance.nix
./services/hardware/joycond.nix
./services/hardware/kanata.nix
@ -555,6 +560,7 @@
./services/home-automation/esphome.nix
./services/home-automation/evcc.nix
./services/home-automation/home-assistant.nix
./services/home-automation/homeassistant-satellite.nix
./services/home-automation/zigbee2mqtt.nix
./services/logging/SystemdJournal2Gelf.nix
./services/logging/awstats.nix
@ -620,6 +626,7 @@
./services/matrix/matrix-sliding-sync.nix
./services/matrix/synapse.nix
./services/misc/airsonic.nix
./services/misc/amazon-ssm-agent.nix
./services/misc/ananicy.nix
./services/misc/ankisyncd.nix
./services/misc/apache-kafka.nix
@ -721,6 +728,7 @@
./services/misc/ripple-data-api.nix
./services/misc/rippled.nix
./services/misc/rmfakecloud.nix
./services/misc/rkvm.nix
./services/misc/rshim.nix
./services/misc/safeeyes.nix
./services/misc/sdrplay.nix
@ -729,11 +737,12 @@
./services/misc/signald.nix
./services/misc/siproxd.nix
./services/misc/snapper.nix
./services/misc/soft-serve.nix
./services/misc/sonarr.nix
./services/misc/sourcehut
./services/misc/spice-autorandr.nix
./services/misc/spice-vdagentd.nix
./services/misc/spice-webdavd.nix
./services/misc/ssm-agent.nix
./services/misc/sssd.nix
./services/misc/subsonic.nix
./services/misc/sundtek.nix
@ -775,6 +784,7 @@
./services/monitoring/kapacitor.nix
./services/monitoring/karma.nix
./services/monitoring/kthxbye.nix
./services/monitoring/librenms.nix
./services/monitoring/loki.nix
./services/monitoring/longview.nix
./services/monitoring/mackerel-agent.nix
@ -881,6 +891,8 @@
./services/networking/croc.nix
./services/networking/dae.nix
./services/networking/dante.nix
./services/networking/deconz.nix
./services/networking/ddclient.nix
./services/networking/dhcpcd.nix
./services/networking/dnscache.nix
./services/networking/dnscrypt-proxy2.nix
@ -896,6 +908,7 @@
./services/networking/eternal-terminal.nix
./services/networking/expressvpn.nix
./services/networking/fakeroute.nix
./services/networking/fastnetmon-advanced.nix
./services/networking/ferm.nix
./services/networking/firefox-syncserver.nix
./services/networking/fireqos.nix
@ -985,6 +998,7 @@
./services/networking/ndppd.nix
./services/networking/nebula.nix
./services/networking/netbird.nix
./services/networking/netclient.nix
./services/networking/networkd-dispatcher.nix
./services/networking/networkmanager.nix
./services/networking/nextdns.nix
@ -1035,6 +1049,7 @@
./services/networking/redsocks.nix
./services/networking/resilio.nix
./services/networking/robustirc-bridge.nix
./services/networking/rosenpass.nix
./services/networking/routedns.nix
./services/networking/rpcbind.nix
./services/networking/rxe.nix
@ -1082,6 +1097,7 @@
./services/networking/thelounge.nix
./services/networking/tinc.nix
./services/networking/tinydns.nix
./services/networking/tinyproxy.nix
./services/networking/tmate-ssh-server.nix
./services/networking/tox-bootstrapd.nix
./services/networking/tox-node.nix
@ -1148,6 +1164,7 @@
./services/security/hologram-agent.nix
./services/security/hologram-server.nix
./services/security/infnoise.nix
./services/security/jitterentropy-rngd.nix
./services/security/kanidm.nix
./services/security/munge.nix
./services/security/nginx-sso.nix
@ -1162,6 +1179,7 @@
./services/security/sshguard.nix
./services/security/sslmate-agent.nix
./services/security/step-ca.nix
./services/security/tang.nix
./services/security/tor.nix
./services/security/torify.nix
./services/security/torsocks.nix
@ -1253,6 +1271,7 @@
./services/web-apps/kavita.nix
./services/web-apps/keycloak.nix
./services/web-apps/komga.nix
./services/web-apps/lanraragi.nix
./services/web-apps/lemmy.nix
./services/web-apps/limesurvey.nix
./services/web-apps/mainsail.nix
@ -1261,6 +1280,7 @@
./services/web-apps/mattermost.nix
./services/web-apps/mediawiki.nix
./services/web-apps/meme-bingo-web.nix
./services/web-apps/microbin.nix
./services/web-apps/miniflux.nix
./services/web-apps/monica.nix
./services/web-apps/moodle.nix
@ -1286,6 +1306,7 @@
./services/web-apps/powerdns-admin.nix
./services/web-apps/prosody-filer.nix
./services/web-apps/restya-board.nix
./services/web-apps/rimgo.nix
./services/web-apps/sftpgo.nix
./services/web-apps/rss-bridge.nix
./services/web-apps/selfoss.nix

View File

@ -1,4 +1,4 @@
{ config, lib, ... }:
{ config, lib, options, ... }:
let
keysDirectory = "/var/keys";
@ -163,9 +163,15 @@ in
in
script.overrideAttrs (old: {
pos = __curPos; # sets meta.position to point here; see script binding above for package definition
meta = (old.meta or { }) // {
platforms = lib.platforms.darwin;
};
passthru = (old.passthru or { }) // {
# Let users in the repl inspect the config
nixosConfig = config;
nixosOptions = options;
};
});
system = {

View File

@ -24,7 +24,7 @@ in {
security.wrappers.bandwhich = {
owner = "root";
group = "root";
capabilities = "cap_net_raw,cap_net_admin+ep";
capabilities = "cap_sys_ptrace,cap_dac_read_search,cap_net_raw,cap_net_admin+ep";
source = "${pkgs.bandwhich}/bin/bandwhich";
};
};

View File

@ -27,6 +27,6 @@ with lib;
"opt/brave/native-messaging-hosts/${appId}".source = source "hosts/chromium";
"opt/brave/policies/managed/${appId}".source = source "policies/chromium";
};
programs.firefox.wrapperConfig.enableBrowserpass = true;
programs.firefox.nativeMessagingHosts.packages = [ pkgs.browserpass ];
};
}

View File

@ -8,7 +8,7 @@ in {
options = {
programs.calls = {
enable = mkEnableOption (lib.mdDoc ''
Whether to enable GNOME calls: a phone dialer and call handler.
GNOME calls: a phone dialer and call handler
'');
};
};

View File

@ -8,7 +8,7 @@ in
{
options = {
programs.cnping = {
enable = mkEnableOption (lib.mdDoc "Whether to install a setcap wrapper for cnping");
enable = mkEnableOption (lib.mdDoc "a setcap wrapper for cnping");
};
};

View File

@ -11,7 +11,7 @@ in {
enable = lib.mkEnableOption (lib.mdDoc ''
direnv integration. Takes care of both installation and
setting up the sourcing of the shell. Additionally enables nix-direnv
integration. Note that you need to logout and login for this change to apply.
integration. Note that you need to logout and login for this change to apply
'');
package = lib.mkPackageOptionMD pkgs "direnv" {};

View File

@ -8,9 +8,9 @@ in {
options = {
programs.feedbackd = {
enable = mkEnableOption (lib.mdDoc ''
Whether to enable the feedbackd D-BUS service and udev rules.
the feedbackd D-BUS service and udev rules.
Your user needs to be in the `feedbackd` group to trigger effects.
Your user needs to be in the `feedbackd` group to trigger effects
'');
package = mkOption {
description = lib.mdDoc ''

View File

@ -5,8 +5,6 @@ with lib;
let
cfg = config.programs.firefox;
nmh = cfg.nativeMessagingHosts;
policyFormat = pkgs.formats.json { };
organisationInfo = ''
@ -17,6 +15,50 @@ let
given control of your browser, unless of course they also control your
NixOS configuration.
'';
# deprecated per-native-messaging-host options
nmhOptions = {
browserpass = {
name = "Browserpass";
package = pkgs.browserpass;
};
bukubrow = {
name = "Bukubrow";
package = pkgs.bukubrow;
};
euwebid = {
name = "Web eID";
package = pkgs.web-eid-app;
};
ff2mpv = {
name = "ff2mpv";
package = pkgs.ff2mpv;
};
fxCast = {
name = "fx_cast";
package = pkgs.fx-cast-bridge;
};
gsconnect = {
name = "GSConnect";
package = pkgs.gnomeExtensions.gsconnect;
};
jabref = {
name = "JabRef";
package = pkgs.jabref;
};
passff = {
name = "PassFF";
package = pkgs.passff-host;
};
tridactyl = {
name = "Tridactyl";
package = pkgs.tridactyl-native;
};
ugetIntegrator = {
name = "Uget Integrator";
package = pkgs.uget-integrator;
};
};
in
{
options.programs.firefox = {
@ -204,50 +246,32 @@ in
'';
};
nativeMessagingHosts = mapAttrs (_: v: mkEnableOption (mdDoc v)) {
browserpass = "Browserpass support";
bukubrow = "Bukubrow support";
euwebid = "Web eID support";
ff2mpv = "ff2mpv support";
fxCast = "fx_cast support";
gsconnect = "GSConnect support";
jabref = "JabRef support";
passff = "PassFF support";
tridactyl = "Tridactyl support";
ugetIntegrator = "Uget Integrator support";
};
nativeMessagingHosts = ({
packages = mkOption {
type = types.listOf types.package;
default = [];
description = mdDoc ''
Additional packages containing native messaging hosts that should be made available to Firefox extensions.
'';
};
}) // (mapAttrs (k: v: mkEnableOption (mdDoc "${v.name} support")) nmhOptions);
};
config = mkIf cfg.enable {
environment.systemPackages = [
(cfg.package.override {
extraPrefs = cfg.autoConfig;
extraNativeMessagingHosts = with pkgs; optionals nmh.ff2mpv [
ff2mpv
] ++ optionals nmh.euwebid [
web-eid-app
] ++ optionals nmh.gsconnect [
gnomeExtensions.gsconnect
] ++ optionals nmh.jabref [
jabref
] ++ optionals nmh.passff [
passff-host
];
cfg = let
# copy-pasted from the wrapper; TODO: figure out fix
applicationName = cfg.package.binaryName or (lib.getName cfg.package);
config = let
forEachEnabledNmh = fn: flatten (mapAttrsToList (k: v: lib.optional cfg.nativeMessagingHosts.${k} (fn k v)) nmhOptions);
in mkIf cfg.enable {
warnings = forEachEnabledNmh (k: v:
"The `programs.firefox.nativeMessagingHosts.${k}` option is deprecated, " +
"please add `${v.package.pname}` to `programs.firefox.nativeMessagingHosts.packages` instead."
);
programs.firefox.nativeMessagingHosts.packages = forEachEnabledNmh (_: v: v.package);
nixpkgsConfig = pkgs.config.${applicationName} or {};
optionConfig = cfg.wrapperConfig;
nmhConfig = {
enableBrowserpass = nmh.browserpass;
enableBukubrow = nmh.bukubrow;
enableTridactylNative = nmh.tridactyl;
enableUgetIntegrator = nmh.ugetIntegrator;
enableFXCastBridge = nmh.fxCast;
};
in nixpkgsConfig // optionConfig // nmhConfig;
})
environment.systemPackages = [
(cfg.package.override (old: {
extraPrefsFiles = old.extraPrefsFiles or [] ++ [(pkgs.writeText "firefox-autoconfig.js" cfg.autoConfig)];
nativeMessagingHosts = old.nativeMessagingHosts or [] ++ cfg.nativeMessagingHosts.packages;
cfg = (old.cfg or {}) // cfg.wrapperConfig;
}))
];
environment.etc =

View File

@ -208,7 +208,7 @@ in
end
# if we haven't sourced the login config, do it
status --is-login; and not set -q __fish_nixos_login_config_sourced
status is-login; and not set -q __fish_nixos_login_config_sourced
and begin
${sourceEnv "loginShellInit"}
@ -220,7 +220,7 @@ in
end
# if we haven't sourced the interactive config, do it
status --is-interactive; and not set -q __fish_nixos_interactive_config_sourced
status is-interactive; and not set -q __fish_nixos_interactive_config_sourced
and begin
${fishAbbrs}
${fishAliases}

View File

@ -6,6 +6,10 @@ let
cfg = config.programs.gnupg;
agentSettingsFormat = pkgs.formats.keyValue {
mkKeyValue = lib.generators.mkKeyValueDefault { } " ";
};
xserverCfg = config.services.xserver;
defaultPinentryFlavor =
@ -82,6 +86,18 @@ in
'';
};
agent.settings = mkOption {
type = agentSettingsFormat.type;
default = { };
example = {
default-cache-ttl = 600;
};
description = lib.mdDoc ''
Configuration for /etc/gnupg/gpg-agent.conf.
See {manpage}`gpg-agent(1)` for supported options.
'';
};
dirmngr.enable = mkOption {
type = types.bool;
default = false;
@ -92,10 +108,13 @@ in
};
config = mkIf cfg.agent.enable {
environment.etc."gnupg/gpg-agent.conf".text =
lib.optionalString (cfg.agent.pinentryFlavor != null) ''
pinentry-program ${pkgs.pinentry.${cfg.agent.pinentryFlavor}}/bin/pinentry
'';
programs.gnupg.agent.settings = {
pinentry-program = lib.mkIf (cfg.agent.pinentryFlavor != null)
"${pkgs.pinentry.${cfg.agent.pinentryFlavor}}/bin/pinentry";
};
environment.etc."gnupg/gpg-agent.conf".source =
agentSettingsFormat.generate "gpg-agent.conf" cfg.agent.settings;
# This overrides the systemd user unit shipped with the gnupg package
systemd.user.services.gpg-agent = {

View File

@ -9,7 +9,7 @@ with lib;
1714 to 1764 as they are needed for it to function properly.
You can use the {option}`package` to use
`gnomeExtensions.gsconnect` as an alternative
implementation if you use Gnome.
implementation if you use Gnome
'');
package = mkOption {
default = pkgs.plasma5Packages.kdeconnect-kde;

View File

@ -29,7 +29,7 @@ in
syntaxHighlight = lib.mkOption {
type = lib.types.bool;
default = false;
default = true;
description = lib.mdDoc "Whether to enable syntax highlight for various languages.";
};
};
@ -40,6 +40,7 @@ in
etc.nanorc.text = (lib.optionalString cfg.syntaxHighlight ''
# load syntax highlighting files
include "${cfg.package}/share/nano/*.nanorc"
include "${cfg.package}/share/nano/extra/*.nanorc"
'') + cfg.nanorc;
systemPackages = [ cfg.package ];
};

View File

@ -8,11 +8,23 @@ in
{
options.programs.openvpn3 = {
enable = mkEnableOption (lib.mdDoc "the openvpn3 client");
package = mkOption {
type = types.package;
default = pkgs.openvpn3.override {
enableSystemdResolved = config.services.resolved.enable;
};
defaultText = literalExpression ''pkgs.openvpn3.override {
enableSystemdResolved = config.services.resolved.enable;
}'';
description = lib.mdDoc ''
Which package to use for `openvpn3`.
'';
};
};
config = mkIf cfg.enable {
services.dbus.packages = with pkgs; [
openvpn3
services.dbus.packages = [
cfg.package
];
users.users.openvpn = {
@ -25,8 +37,8 @@ in
gid = config.ids.gids.openvpn;
};
environment.systemPackages = with pkgs; [
openvpn3
environment.systemPackages = [
cfg.package
];
};

View File

@ -0,0 +1,20 @@
{ config, lib, pkgs, ... }:
let
cfg = config.programs.projecteur;
in
{
options.programs.projecteur = {
enable = lib.mkEnableOption (lib.mdDoc "projecteur");
package = lib.mkPackageOptionMD pkgs "projecteur" { };
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
services.udev.packages = [ cfg.package ];
};
meta = {
maintainers = with lib.maintainers; [ benneti drupol ];
};
}

View File

@ -36,6 +36,19 @@ in
'';
};
cageArgs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "-s" ];
example = lib.literalExpression
''
[ "-s" "-m" "last" ]
'';
description = lib.mdDoc ''
Additional arguments to be passed to
[cage](https://github.com/cage-kiosk/cage).
'';
};
extraCss = lib.mkOption {
type = lib.types.either lib.types.path lib.types.lines;
default = "";
@ -50,7 +63,7 @@ in
config = lib.mkIf cfg.enable {
services.greetd = {
enable = lib.mkDefault true;
settings.default_session.command = lib.mkDefault "${pkgs.dbus}/bin/dbus-run-session ${lib.getExe pkgs.cage} -s -- ${lib.getExe cfg.package}";
settings.default_session.command = lib.mkDefault "${pkgs.dbus}/bin/dbus-run-session ${lib.getExe pkgs.cage} ${lib.escapeShellArgs cfg.cageArgs} -- ${lib.getExe cfg.package}";
};
environment.etc = {

View File

@ -0,0 +1,16 @@
{ config, lib, pkgs, ... }:
let
cfg = config.programs.virt-manager;
in {
options.programs.virt-manager = {
enable = lib.mkEnableOption "virt-manager, an UI for managing virtual machines in libvirt";
package = lib.mkPackageOption pkgs "virt-manager" {};
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
programs.dconf.enable = true;
};
}

View File

@ -0,0 +1,24 @@
{ config, lib, pkgs, ... }:
let
cfg = config.programs.cardboard;
in
{
meta.maintainers = with lib.maintainers; [ AndersonTorres ];
options.programs.cardboard = {
enable = lib.mkEnableOption (lib.mdDoc "cardboard");
package = lib.mkPackageOptionMD pkgs "cardboard" { };
};
config = lib.mkIf cfg.enable (lib.mkMerge [
{
environment.systemPackages = [ cfg.package ];
# To make a cardboard session available for certain DMs like SDDM
services.xserver.displayManager.sessionPackages = [ cfg.package ];
}
(import ./wayland-session.nix { inherit lib pkgs; })
]);
}

View File

@ -42,6 +42,11 @@ in {
<https://github.com/swaywm/sway/wiki> and
"man 5 sway" for more information'');
enableRealtime = mkEnableOption (lib.mdDoc ''
add CAP_SYS_NICE capability on `sway` binary for realtime scheduling
privileges. This may improve latency and reduce stuttering, specially in
high load scenarios'') // { default = true; };
package = mkOption {
type = with types; nullOr package;
default = defaultSwayPackage;
@ -149,6 +154,14 @@ in {
"sway/config".source = mkOptionDefault "${cfg.package}/etc/sway/config";
};
};
security.wrappers = mkIf (cfg.enableRealtime && cfg.package != null) {
sway = {
owner = "root";
group = "root";
source = "${cfg.package}/bin/sway";
capabilities = "cap_sys_nice+ep";
};
};
# To make a Sway session available if a display manager like SDDM is enabled:
services.xserver.displayManager.sessionPackages = optionals (cfg.package != null) [ cfg.package ]; }
(import ./wayland-session.nix { inherit lib pkgs; })

View File

@ -6,7 +6,7 @@ in
meta.maintainers = with lib.maintainers; [ rewine ];
options.programs.wayfire = {
enable = lib.mkEnableOption (lib.mdDoc "Wayfire, a wayland compositor based on wlroots.");
enable = lib.mkEnableOption (lib.mdDoc "Wayfire, a wayland compositor based on wlroots");
package = lib.mkPackageOptionMD pkgs "wayfire" { };

View File

@ -54,7 +54,6 @@ in
(mkRemovedOptionModule [ "services" "chronos" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "couchpotato" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "dd-agent" ] "dd-agent was removed from nixpkgs in favor of the newer datadog-agent.")
(mkRemovedOptionModule [ "services" "ddclient" ] "ddclient has been removed on the request of the upstream maintainer because it is unmaintained and has bugs. Please switch to a different software like `inadyn` or `knsupdate`.") # Added 2023-07-04
(mkRemovedOptionModule [ "services" "dnscrypt-proxy" ] "Use services.dnscrypt-proxy2 instead")
(mkRemovedOptionModule [ "services" "exhibitor" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "firefox" "syncserver" ] "The corresponding package was removed from nixpkgs.")

View File

@ -184,6 +184,7 @@ let
certToConfig = cert: data: let
acmeServer = data.server;
useDns = data.dnsProvider != null;
useDnsOrS3 = useDns || data.s3Bucket != null;
destPath = "/var/lib/acme/${cert}";
selfsignedDeps = optionals (cfg.preliminarySelfsigned) [ "acme-selfsigned-${cert}.service" ];
@ -219,7 +220,8 @@ let
[ "--dns" data.dnsProvider ]
++ optionals (!data.dnsPropagationCheck) [ "--dns.disable-cp" ]
++ optionals (data.dnsResolver != null) [ "--dns.resolvers" data.dnsResolver ]
) else if data.listenHTTP != null then [ "--http" "--http.port" data.listenHTTP ]
) else if data.s3Bucket != null then [ "--http" "--http.s3-bucket" data.s3Bucket ]
else if data.listenHTTP != null then [ "--http" "--http.port" data.listenHTTP ]
else [ "--http" "--http.webroot" data.webroot ];
commonOpts = [
@ -362,13 +364,12 @@ let
"/var/lib/acme/.lego/${cert}/${certDir}:/tmp/certificates"
];
# Only try loading the environmentFile if the dns challenge is enabled
EnvironmentFile = mkIf useDns data.environmentFile;
EnvironmentFile = mkIf useDnsOrS3 data.environmentFile;
Environment = mkIf useDns
Environment = mkIf useDnsOrS3
(mapAttrsToList (k: v: ''"${k}=%d/${k}"'') data.credentialFiles);
LoadCredential = mkIf useDns
LoadCredential = mkIf useDnsOrS3
(mapAttrsToList (k: v: "${k}:${v}") data.credentialFiles);
# Run as root (Prefixed with +)
@ -592,7 +593,7 @@ let
description = lib.mdDoc ''
Key type to use for private keys.
For an up to date list of supported values check the --key-type option
at <https://go-acme.github.io/lego/usage/cli/#usage>.
at <https://go-acme.github.io/lego/usage/cli/options/>.
'';
};
@ -755,6 +756,15 @@ let
'';
};
s3Bucket = mkOption {
type = types.nullOr types.str;
default = null;
example = "acme";
description = lib.mdDoc ''
S3 bucket name to use for HTTP-01 based challenges. Challenges will be written to the S3 bucket.
'';
};
inheritDefaults = mkOption {
default = true;
example = true;
@ -929,32 +939,19 @@ in {
'';
}
{
assertion = data.dnsProvider == null || data.webroot == null;
assertion = lib.length (lib.filter (x: x != null) [
data.dnsProvider
data.webroot
data.listenHTTP
data.s3Bucket
]) != 1;
message = ''
Options `security.acme.certs.${cert}.dnsProvider` and
`security.acme.certs.${cert}.webroot` are mutually exclusive.
'';
}
{
assertion = data.webroot == null || data.listenHTTP == null;
message = ''
Options `security.acme.certs.${cert}.webroot` and
`security.acme.certs.${cert}.listenHTTP` are mutually exclusive.
'';
}
{
assertion = data.listenHTTP == null || data.dnsProvider == null;
message = ''
Options `security.acme.certs.${cert}.listenHTTP` and
`security.acme.certs.${cert}.dnsProvider` are mutually exclusive.
'';
}
{
assertion = data.dnsProvider != null || data.webroot != null || data.listenHTTP != null;
message = ''
One of `security.acme.certs.${cert}.dnsProvider`,
`security.acme.certs.${cert}.webroot`, or
`security.acme.certs.${cert}.listenHTTP` must be provided.
Exactly one of the options
`security.acme.certs.${cert}.dnsProvider`,
`security.acme.certs.${cert}.webroot`,
`security.acme.certs.${cert}.listenHTTP` and
`security.acme.certs.${cert}.s3Bucket`
is required.
'';
}
{

View File

@ -2,10 +2,4 @@
let apparmor = config.security.apparmor; in
{
config.security.apparmor.packages = [ pkgs.apparmor-profiles ];
config.security.apparmor.policies."bin.ping".profile = lib.mkIf apparmor.policies."bin.ping".enable ''
include "${pkgs.iputils.apparmor}/bin.ping"
include "${pkgs.inetutils.apparmor}/bin.ping"
# Note that including those two profiles in the same profile
# would not work if the second one were to re-include <tunables/global>.
'';
}

View File

@ -6,6 +6,92 @@
with lib;
let
mkRulesTypeOption = type: mkOption {
# These options are experimental and subject to breaking changes without notice.
description = lib.mdDoc ''
PAM `${type}` rules for this service.
Attribute keys are the name of each rule.
'';
type = types.attrsOf (types.submodule ({ name, config, ... }: {
options = {
name = mkOption {
type = types.str;
description = lib.mdDoc ''
Name of this rule.
'';
internal = true;
readOnly = true;
};
enable = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Whether this rule is added to the PAM service config file.
'';
};
order = mkOption {
type = types.int;
description = lib.mdDoc ''
Order of this rule in the service file. Rules are arranged in ascending order of this value.
::: {.warning}
The `order` values for the built-in rules are subject to change. If you assign a constant value to this option, a system update could silently reorder your rule. You could be locked out of your system, or your system could be left wide open. When using this option, set it to a relative offset from another rule's `order` value:
```nix
{
security.pam.services.login.rules.auth.foo.order =
config.security.pam.services.login.rules.auth.unix.order + 10;
}
```
:::
'';
};
control = mkOption {
type = types.str;
description = lib.mdDoc ''
Indicates the behavior of the PAM-API should the module fail to succeed in its authentication task. See `control` in {manpage}`pam.conf(5)` for details.
'';
};
modulePath = mkOption {
type = types.str;
description = lib.mdDoc ''
Either the full filename of the PAM to be used by the application (it begins with a '/'), or a relative pathname from the default module location. See `module-path` in {manpage}`pam.conf(5)` for details.
'';
};
args = mkOption {
type = types.listOf types.str;
description = lib.mdDoc ''
Tokens that can be used to modify the specific behavior of the given PAM. Such arguments will be documented for each individual module. See `module-arguments` in {manpage}`pam.conf(5)` for details.
Escaping rules for spaces and square brackets are automatically applied.
{option}`settings` are automatically added as {option}`args`. It's recommended to use the {option}`settings` option whenever possible so that arguments can be overridden.
'';
};
settings = mkOption {
type = with types; attrsOf (nullOr (oneOf [ bool str int pathInStore ]));
default = {};
description = lib.mdDoc ''
Settings to add as `module-arguments`.
Boolean values render just the key if true, and nothing if false. Null values are ignored. All other values are rendered as key-value pairs.
'';
};
};
config = {
inherit name;
# Formats an attrset of settings as args for use as `module-arguments`.
args = concatLists (flip mapAttrsToList config.settings (name: value:
if isBool value
then optional value name
else optional (value != null) "${name}=${toString value}"
));
};
}));
};
parentConfig = config;
pamOpts = { config, name, ... }: let cfg = config; in let config = parentConfig; in {
@ -18,6 +104,28 @@ let
description = lib.mdDoc "Name of the PAM service.";
};
rules = mkOption {
# This option is experimental and subject to breaking changes without notice.
visible = false;
description = lib.mdDoc ''
PAM rules for this service.
::: {.warning}
This option and its suboptions are experimental and subject to breaking changes without notice.
If you use this option in your system configuration, you will need to manually monitor this module for any changes. Otherwise, failure to adjust your configuration properly could lead to you being locked out of your system, or worse, your system could be left wide open to attackers.
If you share configuration examples that use this option, you MUST include this warning so that users are informed.
You may freely use this option within `nixpkgs`, and future changes will account for those use sites.
:::
'';
type = types.submodule {
options = genAttrs [ "account" "auth" "password" "session" ] mkRulesTypeOption;
};
};
unixAuth = mkOption {
default = true;
type = types.bool;
@ -470,90 +578,114 @@ let
setLoginUid = mkDefault cfg.startSession;
limits = mkDefault config.security.pam.loginLimits;
text = let
ensureUniqueOrder = type: rules:
let
checkPair = a: b: assert assertMsg (a.order != b.order) "security.pam.services.${name}.rules.${type}: rules '${a.name}' and '${b.name}' cannot have the same order value (${toString a.order})"; b;
checked = zipListsWith checkPair rules (drop 1 rules);
in take 1 rules ++ checked;
# Formats a string for use in `module-arguments`. See `man pam.conf`.
formatModuleArgument = token:
if hasInfix " " token
then "[${replaceStrings ["]"] ["\\]"] token}]"
else token;
formatRules = type: pipe cfg.rules.${type} [
attrValues
(filter (rule: rule.enable))
(sort (a: b: a.order < b.order))
(ensureUniqueOrder type)
(map (rule: concatStringsSep " " (
[ type rule.control rule.modulePath ]
++ map formatModuleArgument rule.args
++ [ "# ${rule.name} (order ${toString rule.order})" ]
)))
(concatStringsSep "\n")
];
in mkDefault ''
# Account management.
${formatRules "account"}
# Authentication management.
${formatRules "auth"}
# Password management.
${formatRules "password"}
# Session management.
${formatRules "session"}
'';
# !!! TODO: move the LDAP stuff to the LDAP module, and the
# Samba stuff to the Samba module. This requires that the PAM
# module provides the right hooks.
text = mkDefault
(
''
# Account management.
'' +
optionalString use_ldap ''
account sufficient ${pam_ldap}/lib/security/pam_ldap.so
'' +
optionalString cfg.mysqlAuth ''
account sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
'' +
optionalString (config.services.kanidm.enablePam) ''
account sufficient ${pkgs.kanidm}/lib/pam_kanidm.so ignore_unknown_user
'' +
optionalString (config.services.sssd.enable && cfg.sssdStrictAccess==false) ''
account sufficient ${pkgs.sssd}/lib/security/pam_sss.so
'' +
optionalString (config.services.sssd.enable && cfg.sssdStrictAccess) ''
account [default=bad success=ok user_unknown=ignore] ${pkgs.sssd}/lib/security/pam_sss.so
'' +
optionalString config.security.pam.krb5.enable ''
account sufficient ${pam_krb5}/lib/security/pam_krb5.so
'' +
optionalString cfg.googleOsLoginAccountVerification ''
account [success=ok ignore=ignore default=die] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so
account [success=ok default=ignore] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so
'' +
optionalString config.services.homed.enable ''
account sufficient ${config.systemd.package}/lib/security/pam_systemd_home.so
'' +
rules = let
autoOrderRules = flip pipe [
(imap1 (index: rule: rule // { order = mkDefault (10000 + index * 100); } ))
(map (rule: nameValuePair rule.name (removeAttrs rule [ "name" ])))
listToAttrs
];
in {
account = autoOrderRules [
{ name = "ldap"; enable = use_ldap; control = "sufficient"; modulePath = "${pam_ldap}/lib/security/pam_ldap.so"; }
{ name = "mysql"; enable = cfg.mysqlAuth; control = "sufficient"; modulePath = "${pkgs.pam_mysql}/lib/security/pam_mysql.so"; settings = {
config_file = "/etc/security/pam_mysql.conf";
}; }
{ name = "kanidm"; enable = config.services.kanidm.enablePam; control = "sufficient"; modulePath = "${pkgs.kanidm}/lib/pam_kanidm.so"; settings = {
ignore_unknown_user = true;
}; }
{ name = "sss"; enable = config.services.sssd.enable; control = if cfg.sssdStrictAccess then "[default=bad success=ok user_unknown=ignore]" else "sufficient"; modulePath = "${pkgs.sssd}/lib/security/pam_sss.so"; }
{ name = "krb5"; enable = config.security.pam.krb5.enable; control = "sufficient"; modulePath = "${pam_krb5}/lib/security/pam_krb5.so"; }
{ name = "oslogin_login"; enable = cfg.googleOsLoginAccountVerification; control = "[success=ok ignore=ignore default=die]"; modulePath = "${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so"; }
{ name = "oslogin_admin"; enable = cfg.googleOsLoginAccountVerification; control = "[success=ok default=ignore]"; modulePath = "${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so"; }
{ name = "systemd_home"; enable = config.services.homed.enable; control = "sufficient"; modulePath = "${config.systemd.package}/lib/security/pam_systemd_home.so"; }
# The required pam_unix.so module has to come after all the sufficient modules
# because otherwise, the account lookup will fail if the user does not exist
# locally, for example with MySQL- or LDAP-auth.
''
account required pam_unix.so
{ name = "unix"; control = "required"; modulePath = "pam_unix.so"; }
];
# Authentication management.
'' +
optionalString cfg.googleOsLoginAuthentication ''
auth [success=done perm_denied=die default=ignore] ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so
'' +
optionalString cfg.rootOK ''
auth sufficient pam_rootok.so
'' +
optionalString cfg.requireWheel ''
auth required pam_wheel.so use_uid
'' +
optionalString cfg.logFailures ''
auth required pam_faillock.so
'' +
optionalString cfg.mysqlAuth ''
auth sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
'' +
optionalString (config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth) ''
auth sufficient ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so file=${lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles}
'' +
(let p11 = config.security.pam.p11; in optionalString cfg.p11Auth ''
auth ${p11.control} ${pkgs.pam_p11}/lib/security/pam_p11.so ${pkgs.opensc}/lib/opensc-pkcs11.so
'') +
(let u2f = config.security.pam.u2f; in optionalString cfg.u2fAuth (''
auth ${u2f.control} ${pkgs.pam_u2f}/lib/security/pam_u2f.so ${optionalString u2f.debug "debug"} ${optionalString (u2f.authFile != null) "authfile=${u2f.authFile}"} ''
+ ''${optionalString u2f.interactive "interactive"} ${optionalString u2f.cue "cue"} ${optionalString (u2f.appId != null) "appid=${u2f.appId}"} ${optionalString (u2f.origin != null) "origin=${u2f.origin}"}
'')) +
optionalString cfg.usbAuth ''
auth sufficient ${pkgs.pam_usb}/lib/security/pam_usb.so
'' +
(let ussh = config.security.pam.ussh; in optionalString (config.security.pam.ussh.enable && cfg.usshAuth) ''
auth ${ussh.control} ${pkgs.pam_ussh}/lib/security/pam_ussh.so ${optionalString (ussh.caFile != null) "ca_file=${ussh.caFile}"} ${optionalString (ussh.authorizedPrincipals != null) "authorized_principals=${ussh.authorizedPrincipals}"} ${optionalString (ussh.authorizedPrincipalsFile != null) "authorized_principals_file=${ussh.authorizedPrincipalsFile}"} ${optionalString (ussh.group != null) "group=${ussh.group}"}
'') +
(let oath = config.security.pam.oath; in optionalString cfg.oathAuth ''
auth requisite ${pkgs.oath-toolkit}/lib/security/pam_oath.so window=${toString oath.window} usersfile=${toString oath.usersFile} digits=${toString oath.digits}
'') +
(let yubi = config.security.pam.yubico; in optionalString cfg.yubicoAuth ''
auth ${yubi.control} ${pkgs.yubico-pam}/lib/security/pam_yubico.so mode=${toString yubi.mode} ${optionalString (yubi.challengeResponsePath != null) "chalresp_path=${yubi.challengeResponsePath}"} ${optionalString (yubi.mode == "client") "id=${toString yubi.id}"} ${optionalString yubi.debug "debug"}
'') +
(let dp9ik = config.security.pam.dp9ik; in optionalString dp9ik.enable ''
auth ${dp9ik.control} ${pkgs.pam_dp9ik}/lib/security/pam_p9.so ${dp9ik.authserver}
'') +
optionalString cfg.fprintAuth ''
auth sufficient ${pkgs.fprintd}/lib/security/pam_fprintd.so
'' +
auth = autoOrderRules ([
{ name = "oslogin_login"; enable = cfg.googleOsLoginAuthentication; control = "[success=done perm_denied=die default=ignore]"; modulePath = "${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so"; }
{ name = "rootok"; enable = cfg.rootOK; control = "sufficient"; modulePath = "pam_rootok.so"; }
{ name = "wheel"; enable = cfg.requireWheel; control = "required"; modulePath = "pam_wheel.so"; settings = {
use_uid = true;
}; }
{ name = "faillock"; enable = cfg.logFailures; control = "required"; modulePath = "pam_faillock.so"; }
{ name = "mysql"; enable = cfg.mysqlAuth; control = "sufficient"; modulePath = "${pkgs.pam_mysql}/lib/security/pam_mysql.so"; settings = {
config_file = "/etc/security/pam_mysql.conf";
}; }
{ name = "ssh_agent_auth"; enable = config.security.pam.enableSSHAgentAuth && cfg.sshAgentAuth; control = "sufficient"; modulePath = "${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so"; settings = {
file = lib.concatStringsSep ":" config.services.openssh.authorizedKeysFiles;
}; }
(let p11 = config.security.pam.p11; in { name = "p11"; enable = cfg.p11Auth; control = p11.control; modulePath = "${pkgs.pam_p11}/lib/security/pam_p11.so"; args = [
"${pkgs.opensc}/lib/opensc-pkcs11.so"
]; })
(let u2f = config.security.pam.u2f; in { name = "u2f"; enable = cfg.u2fAuth; control = u2f.control; modulePath = "${pkgs.pam_u2f}/lib/security/pam_u2f.so"; settings = {
inherit (u2f) debug interactive cue origin;
authfile = u2f.authFile;
appid = u2f.appId;
}; })
{ name = "usb"; enable = cfg.usbAuth; control = "sufficient"; modulePath = "${pkgs.pam_usb}/lib/security/pam_usb.so"; }
(let ussh = config.security.pam.ussh; in { name = "ussh"; enable = config.security.pam.ussh.enable && cfg.usshAuth; control = ussh.control; modulePath = "${pkgs.pam_ussh}/lib/security/pam_ussh.so"; settings = {
ca_file = ussh.caFile;
authorized_principals = ussh.authorizedPrincipals;
authorized_principals_file = ussh.authorizedPrincipalsFile;
inherit (ussh) group;
}; })
(let oath = config.security.pam.oath; in { name = "oath"; enable = cfg.oathAuth; control = "requisite"; modulePath = "${pkgs.oath-toolkit}/lib/security/pam_oath.so"; settings = {
inherit (oath) window digits;
usersfile = oath.usersFile;
}; })
(let yubi = config.security.pam.yubico; in { name = "yubico"; enable = cfg.yubicoAuth; control = yubi.control; modulePath = "${pkgs.yubico-pam}/lib/security/pam_yubico.so"; settings = {
inherit (yubi) mode debug;
chalresp_path = yubi.challengeResponsePath;
id = mkIf (yubi.mode == "client") yubi.id;
}; })
(let dp9ik = config.security.pam.dp9ik; in { name = "p9"; enable = dp9ik.enable; control = dp9ik.control; modulePath = "${pkgs.pam_dp9ik}/lib/security/pam_p9.so"; args = [
dp9ik.authserver
]; })
{ name = "fprintd"; enable = cfg.fprintAuth; control = "sufficient"; modulePath = "${pkgs.fprintd}/lib/security/pam_fprintd.so"; }
] ++
# Modules in this block require having the password set in PAM_AUTHTOK.
# pam_unix is marked as 'sufficient' on NixOS which means nothing will run
# after it succeeds. Certain modules need to run after pam_unix
@ -562,7 +694,7 @@ let
# We use try_first_pass the second time to avoid prompting password twice.
#
# The same principle applies to systemd-homed
(optionalString ((cfg.unixAuth || config.services.homed.enable) &&
(optionals ((cfg.unixAuth || config.services.homed.enable) &&
(config.security.pam.enableEcryptfs
|| config.security.pam.enableFscrypt
|| cfg.pamMount
@ -573,199 +705,173 @@ let
|| cfg.failDelay.enable
|| cfg.duoSecurity.enable
|| cfg.zfs))
(
optionalString config.services.homed.enable ''
auth optional ${config.systemd.package}/lib/security/pam_systemd_home.so
'' +
optionalString cfg.unixAuth ''
auth optional pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth
'' +
optionalString config.security.pam.enableEcryptfs ''
auth optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so unwrap
'' +
optionalString config.security.pam.enableFscrypt ''
auth optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
'' +
optionalString cfg.zfs ''
auth optional ${config.boot.zfs.package}/lib/security/pam_zfs_key.so homes=${config.security.pam.zfs.homes}
'' +
optionalString cfg.pamMount ''
auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
'' +
optionalString cfg.enableKwallet ''
auth optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
'' +
optionalString cfg.enableGnomeKeyring ''
auth optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so
'' +
optionalString cfg.gnupg.enable ''
auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"}
'' +
optionalString cfg.failDelay.enable ''
auth optional ${pkgs.pam}/lib/security/pam_faildelay.so delay=${toString cfg.failDelay.delay}
'' +
optionalString cfg.googleAuthenticator.enable ''
auth required ${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so no_increment_hotp
'' +
optionalString cfg.duoSecurity.enable ''
auth required ${pkgs.duo-unix}/lib/security/pam_duo.so
''
)) +
optionalString config.services.homed.enable ''
auth sufficient ${config.systemd.package}/lib/security/pam_systemd_home.so
'' +
optionalString cfg.unixAuth ''
auth sufficient pam_unix.so ${optionalString cfg.allowNullPassword "nullok"} ${optionalString cfg.nodelay "nodelay"} likeauth try_first_pass
'' +
optionalString cfg.otpwAuth ''
auth sufficient ${pkgs.otpw}/lib/security/pam_otpw.so
'' +
optionalString use_ldap ''
auth sufficient ${pam_ldap}/lib/security/pam_ldap.so use_first_pass
'' +
optionalString config.services.kanidm.enablePam ''
auth sufficient ${pkgs.kanidm}/lib/pam_kanidm.so ignore_unknown_user use_first_pass
'' +
optionalString config.services.sssd.enable ''
auth sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_first_pass
'' +
optionalString config.security.pam.krb5.enable ''
auth [default=ignore success=1 service_err=reset] ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
auth [default=die success=done] ${pam_ccreds}/lib/security/pam_ccreds.so action=validate use_first_pass
auth sufficient ${pam_ccreds}/lib/security/pam_ccreds.so action=store use_first_pass
'' +
''
auth required pam_deny.so
[
{ name = "systemd_home-early"; enable = config.services.homed.enable; control = "optional"; modulePath = "${config.systemd.package}/lib/security/pam_systemd_home.so"; }
{ name = "unix-early"; enable = cfg.unixAuth; control = "optional"; modulePath = "pam_unix.so"; settings = {
nullok = cfg.allowNullPassword;
inherit (cfg) nodelay;
likeauth = true;
}; }
{ name = "ecryptfs"; enable = config.security.pam.enableEcryptfs; control = "optional"; modulePath = "${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"; settings = {
unwrap = true;
}; }
{ name = "fscrypt"; enable = config.security.pam.enableFscrypt; control = "optional"; modulePath = "${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so"; }
{ name = "zfs_key"; enable = cfg.zfs; control = "optional"; modulePath = "${config.boot.zfs.package}/lib/security/pam_zfs_key.so"; settings = {
inherit (config.security.pam.zfs) homes;
}; }
{ name = "mount"; enable = cfg.pamMount; control = "optional"; modulePath = "${pkgs.pam_mount}/lib/security/pam_mount.so"; settings = {
disable_interactive = true;
}; }
{ name = "kwallet5"; enable = cfg.enableKwallet; control = "optional"; modulePath = "${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so"; settings = {
kwalletd = "${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5";
}; }
{ name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so"; }
{ name = "gnupg"; enable = cfg.gnupg.enable; control = "optional"; modulePath = "${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"; settings = {
store-only = cfg.gnupg.storeOnly;
}; }
{ name = "faildelay"; enable = cfg.failDelay.enable; control = "optional"; modulePath = "${pkgs.pam}/lib/security/pam_faildelay.so"; settings = {
inherit (cfg.failDelay) delay;
}; }
{ name = "google_authenticator"; enable = cfg.googleAuthenticator.enable; control = "required"; modulePath = "${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so"; settings = {
no_increment_hotp = true;
}; }
{ name = "duo"; enable = cfg.duoSecurity.enable; control = "required"; modulePath = "${pkgs.duo-unix}/lib/security/pam_duo.so"; }
]) ++ [
{ name = "systemd_home"; enable = config.services.homed.enable; control = "sufficient"; modulePath = "${config.systemd.package}/lib/security/pam_systemd_home.so"; }
{ name = "unix"; enable = cfg.unixAuth; control = "sufficient"; modulePath = "pam_unix.so"; settings = {
nullok = cfg.allowNullPassword;
inherit (cfg) nodelay;
likeauth = true;
try_first_pass = true;
}; }
{ name = "otpw"; enable = cfg.otpwAuth; control = "sufficient"; modulePath = "${pkgs.otpw}/lib/security/pam_otpw.so"; }
{ name = "ldap"; enable = use_ldap; control = "sufficient"; modulePath = "${pam_ldap}/lib/security/pam_ldap.so"; settings = {
use_first_pass = true;
}; }
{ name = "kanidm"; enable = config.services.kanidm.enablePam; control = "sufficient"; modulePath = "${pkgs.kanidm}/lib/pam_kanidm.so"; settings = {
ignore_unknown_user = true;
use_first_pass = true;
}; }
{ name = "sss"; enable = config.services.sssd.enable; control = "sufficient"; modulePath = "${pkgs.sssd}/lib/security/pam_sss.so"; settings = {
use_first_pass = true;
}; }
{ name = "krb5"; enable = config.security.pam.krb5.enable; control = "[default=ignore success=1 service_err=reset]"; modulePath = "${pam_krb5}/lib/security/pam_krb5.so"; settings = {
use_first_pass = true;
}; }
{ name = "ccreds-validate"; enable = config.security.pam.krb5.enable; control = "[default=die success=done]"; modulePath = "${pam_ccreds}/lib/security/pam_ccreds.so"; settings = {
action = "validate";
use_first_pass = true;
}; }
{ name = "ccreds-store"; enable = config.security.pam.krb5.enable; control = "sufficient"; modulePath = "${pam_ccreds}/lib/security/pam_ccreds.so"; settings = {
action = "store";
use_first_pass = true;
}; }
{ name = "deny"; control = "required"; modulePath = "pam_deny.so"; }
]);
# Password management.
'' +
optionalString config.services.homed.enable ''
password sufficient ${config.systemd.package}/lib/security/pam_systemd_home.so
'' + ''
password sufficient pam_unix.so nullok yescrypt
'' +
optionalString config.security.pam.enableEcryptfs ''
password optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
'' +
optionalString config.security.pam.enableFscrypt ''
password optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
'' +
optionalString cfg.zfs ''
password optional ${config.boot.zfs.package}/lib/security/pam_zfs_key.so homes=${config.security.pam.zfs.homes}
'' +
optionalString cfg.pamMount ''
password optional ${pkgs.pam_mount}/lib/security/pam_mount.so
'' +
optionalString use_ldap ''
password sufficient ${pam_ldap}/lib/security/pam_ldap.so
'' +
optionalString cfg.mysqlAuth ''
password sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
'' +
optionalString config.services.kanidm.enablePam ''
password sufficient ${pkgs.kanidm}/lib/pam_kanidm.so
'' +
optionalString config.services.sssd.enable ''
password sufficient ${pkgs.sssd}/lib/security/pam_sss.so
'' +
optionalString config.security.pam.krb5.enable ''
password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
'' +
optionalString cfg.enableGnomeKeyring ''
password optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so use_authtok
'' +
''
password = autoOrderRules [
{ name = "systemd_home"; enable = config.services.homed.enable; control = "sufficient"; modulePath = "${config.systemd.package}/lib/security/pam_systemd_home.so"; }
{ name = "unix"; control = "sufficient"; modulePath = "pam_unix.so"; settings = {
nullok = true;
yescrypt = true;
}; }
{ name = "ecryptfs"; enable = config.security.pam.enableEcryptfs; control = "optional"; modulePath = "${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"; }
{ name = "fscrypt"; enable = config.security.pam.enableFscrypt; control = "optional"; modulePath = "${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so"; }
{ name = "zfs_key"; enable = cfg.zfs; control = "optional"; modulePath = "${config.boot.zfs.package}/lib/security/pam_zfs_key.so"; settings = {
inherit (config.security.pam.zfs) homes;
}; }
{ name = "mount"; enable = cfg.pamMount; control = "optional"; modulePath = "${pkgs.pam_mount}/lib/security/pam_mount.so"; }
{ name = "ldap"; enable = use_ldap; control = "sufficient"; modulePath = "${pam_ldap}/lib/security/pam_ldap.so"; }
{ name = "mysql"; enable = cfg.mysqlAuth; control = "sufficient"; modulePath = "${pkgs.pam_mysql}/lib/security/pam_mysql.so"; settings = {
config_file = "/etc/security/pam_mysql.conf";
}; }
{ name = "kanidm"; enable = config.services.kanidm.enablePam; control = "sufficient"; modulePath = "${pkgs.kanidm}/lib/pam_kanidm.so"; }
{ name = "sss"; enable = config.services.sssd.enable; control = "sufficient"; modulePath = "${pkgs.sssd}/lib/security/pam_sss.so"; }
{ name = "krb5"; enable = config.security.pam.krb5.enable; control = "sufficient"; modulePath = "${pam_krb5}/lib/security/pam_krb5.so"; settings = {
use_first_pass = true;
}; }
{ name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so"; settings = {
use_authtok = true;
}; }
];
# Session management.
'' +
optionalString cfg.setEnvironment ''
session required pam_env.so conffile=/etc/pam/environment readenv=0
'' +
''
session required pam_unix.so
'' +
optionalString cfg.setLoginUid ''
session ${if config.boot.isContainer then "optional" else "required"} pam_loginuid.so
'' +
optionalString cfg.ttyAudit.enable (concatStringsSep " \\\n " ([
"session required ${pkgs.pam}/lib/security/pam_tty_audit.so"
] ++ optional cfg.ttyAudit.openOnly "open_only"
++ optional (cfg.ttyAudit.enablePattern != null) "enable=${cfg.ttyAudit.enablePattern}"
++ optional (cfg.ttyAudit.disablePattern != null) "disable=${cfg.ttyAudit.disablePattern}"
)) +
optionalString config.services.homed.enable ''
session required ${config.systemd.package}/lib/security/pam_systemd_home.so
'' +
optionalString cfg.makeHomeDir ''
session required ${pkgs.pam}/lib/security/pam_mkhomedir.so silent skel=${config.security.pam.makeHomeDir.skelDirectory} umask=${config.security.pam.makeHomeDir.umask}
'' +
optionalString cfg.updateWtmp ''
session required ${pkgs.pam}/lib/security/pam_lastlog.so silent
'' +
optionalString config.security.pam.enableEcryptfs ''
session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so
'' +
optionalString config.security.pam.enableFscrypt ''
# Work around https://github.com/systemd/systemd/issues/8598
# Skips the pam_fscrypt module for systemd-user sessions which do not have a password
# anyways.
# See also https://github.com/google/fscrypt/issues/95
session [success=1 default=ignore] pam_succeed_if.so service = systemd-user
session optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
'' +
optionalString cfg.zfs ''
session [success=1 default=ignore] pam_succeed_if.so service = systemd-user
session optional ${config.boot.zfs.package}/lib/security/pam_zfs_key.so homes=${config.security.pam.zfs.homes} ${optionalString config.security.pam.zfs.noUnmount "nounmount"}
'' +
optionalString cfg.pamMount ''
session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
'' +
optionalString use_ldap ''
session optional ${pam_ldap}/lib/security/pam_ldap.so
'' +
optionalString cfg.mysqlAuth ''
session optional ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
'' +
optionalString config.services.kanidm.enablePam ''
session optional ${pkgs.kanidm}/lib/pam_kanidm.so
'' +
optionalString config.services.sssd.enable ''
session optional ${pkgs.sssd}/lib/security/pam_sss.so
'' +
optionalString config.security.pam.krb5.enable ''
session optional ${pam_krb5}/lib/security/pam_krb5.so
'' +
optionalString cfg.otpwAuth ''
session optional ${pkgs.otpw}/lib/security/pam_otpw.so
'' +
optionalString cfg.startSession ''
session optional ${config.systemd.package}/lib/security/pam_systemd.so
'' +
optionalString cfg.forwardXAuth ''
session optional pam_xauth.so xauthpath=${pkgs.xorg.xauth}/bin/xauth systemuser=99
'' +
optionalString (cfg.limits != []) ''
session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}
'' +
optionalString (cfg.showMotd && (config.users.motd != null || config.users.motdFile != null)) ''
session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}
'' +
optionalString (cfg.enableAppArmor && config.security.apparmor.enable) ''
session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug
'' +
optionalString (cfg.enableKwallet) ''
session optional ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so kwalletd=${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5
'' +
optionalString (cfg.enableGnomeKeyring) ''
session optional ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so auto_start
'' +
optionalString cfg.gnupg.enable ''
session optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.noAutostart " no-autostart"}
'' +
optionalString (config.virtualisation.lxc.lxcfs.enable) ''
session optional ${pkgs.lxc}/lib/security/pam_cgfs.so -c all
''
);
session = autoOrderRules [
{ name = "env"; enable = cfg.setEnvironment; control = "required"; modulePath = "pam_env.so"; settings = {
conffile = "/etc/pam/environment";
readenv = 0;
}; }
{ name = "unix"; control = "required"; modulePath = "pam_unix.so"; }
{ name = "loginuid"; enable = cfg.setLoginUid; control = if config.boot.isContainer then "optional" else "required"; modulePath = "pam_loginuid.so"; }
{ name = "tty_audit"; enable = cfg.ttyAudit.enable; control = "required"; modulePath = "${pkgs.pam}/lib/security/pam_tty_audit.so"; settings = {
open_only = cfg.ttyAudit.openOnly;
enable = cfg.ttyAudit.enablePattern;
disable = cfg.ttyAudit.disablePattern;
}; }
{ name = "systemd_home"; enable = config.services.homed.enable; control = "required"; modulePath = "${config.systemd.package}/lib/security/pam_systemd_home.so"; }
{ name = "mkhomedir"; enable = cfg.makeHomeDir; control = "required"; modulePath = "${pkgs.pam}/lib/security/pam_mkhomedir.so"; settings = {
silent = true;
skel = config.security.pam.makeHomeDir.skelDirectory;
inherit (config.security.pam.makeHomeDir) umask;
}; }
{ name = "lastlog"; enable = cfg.updateWtmp; control = "required"; modulePath = "${pkgs.pam}/lib/security/pam_lastlog.so"; settings = {
silent = true;
}; }
{ name = "ecryptfs"; enable = config.security.pam.enableEcryptfs; control = "optional"; modulePath = "${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"; }
# Work around https://github.com/systemd/systemd/issues/8598
# Skips the pam_fscrypt module for systemd-user sessions which do not have a password
# anyways.
# See also https://github.com/google/fscrypt/issues/95
{ name = "fscrypt-skip-systemd"; enable = config.security.pam.enableFscrypt; control = "[success=1 default=ignore]"; modulePath = "pam_succeed_if.so"; args = [
"service" "=" "systemd-user"
]; }
{ name = "fscrypt"; enable = config.security.pam.enableFscrypt; control = "optional"; modulePath = "${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so"; }
{ name = "zfs_key-skip-systemd"; enable = cfg.zfs; control = "[success=1 default=ignore]"; modulePath = "pam_succeed_if.so"; args = [
"service" "=" "systemd-user"
]; }
{ name = "zfs_key"; enable = cfg.zfs; control = "optional"; modulePath = "${config.boot.zfs.package}/lib/security/pam_zfs_key.so"; settings = {
inherit (config.security.pam.zfs) homes;
nounmount = config.security.pam.zfs.noUnmount;
}; }
{ name = "mount"; enable = cfg.pamMount; control = "optional"; modulePath = "${pkgs.pam_mount}/lib/security/pam_mount.so"; settings = {
disable_interactive = true;
}; }
{ name = "ldap"; enable = use_ldap; control = "optional"; modulePath = "${pam_ldap}/lib/security/pam_ldap.so"; }
{ name = "mysql"; enable = cfg.mysqlAuth; control = "optional"; modulePath = "${pkgs.pam_mysql}/lib/security/pam_mysql.so"; settings = {
config_file = "/etc/security/pam_mysql.conf";
}; }
{ name = "kanidm"; enable = config.services.kanidm.enablePam; control = "optional"; modulePath = "${pkgs.kanidm}/lib/pam_kanidm.so"; }
{ name = "sss"; enable = config.services.sssd.enable; control = "optional"; modulePath = "${pkgs.sssd}/lib/security/pam_sss.so"; }
{ name = "krb5"; enable = config.security.pam.krb5.enable; control = "optional"; modulePath = "${pam_krb5}/lib/security/pam_krb5.so"; }
{ name = "otpw"; enable = cfg.otpwAuth; control = "optional"; modulePath = "${pkgs.otpw}/lib/security/pam_otpw.so"; }
{ name = "systemd"; enable = cfg.startSession; control = "optional"; modulePath = "${config.systemd.package}/lib/security/pam_systemd.so"; }
{ name = "xauth"; enable = cfg.forwardXAuth; control = "optional"; modulePath = "pam_xauth.so"; settings = {
xauthpath = "${pkgs.xorg.xauth}/bin/xauth";
systemuser = 99;
}; }
{ name = "limits"; enable = cfg.limits != []; control = "required"; modulePath = "${pkgs.pam}/lib/security/pam_limits.so"; settings = {
conf = "${makeLimitsConf cfg.limits}";
}; }
{ name = "motd"; enable = cfg.showMotd && (config.users.motd != null || config.users.motdFile != null); control = "optional"; modulePath = "${pkgs.pam}/lib/security/pam_motd.so"; settings = {
inherit motd;
}; }
{ name = "apparmor"; enable = cfg.enableAppArmor && config.security.apparmor.enable; control = "optional"; modulePath = "${pkgs.apparmor-pam}/lib/security/pam_apparmor.so"; settings = {
order = "user,group,default";
debug = true;
}; }
{ name = "kwallet5"; enable = cfg.enableKwallet; control = "optional"; modulePath = "${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so"; settings = {
kwalletd = "${pkgs.plasma5Packages.kwallet.bin}/bin/kwalletd5";
}; }
{ name = "gnome_keyring"; enable = cfg.enableGnomeKeyring; control = "optional"; modulePath = "${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so"; settings = {
auto_start = true;
}; }
{ name = "gnupg"; enable = cfg.gnupg.enable; control = "optional"; modulePath = "${pkgs.pam_gnupg}/lib/security/pam_gnupg.so"; settings = {
no-autostart = cfg.gnupg.noAutostart;
}; }
{ name = "cgfs"; enable = config.virtualisation.lxc.lxcfs.enable; control = "optional"; modulePath = "${pkgs.lxc}/lib/security/pam_cgfs.so"; args = [
"-c" "all"
]; }
];
};
};
};
@ -841,6 +947,8 @@ in
{
meta.maintainers = [ maintainers.majiir ];
imports = [
(mkRenamedOptionModule [ "security" "pam" "enableU2F" ] [ "security" "pam" "u2f" "enable" ])
];
@ -1402,9 +1510,7 @@ in
fscrypt = {};
};
security.apparmor.includes."abstractions/pam" = let
isEnabled = test: fold or false (map test (attrValues config.security.pam.services));
in
security.apparmor.includes."abstractions/pam" =
lib.concatMapStrings
(name: "r ${config.environment.etc."pam.d/${name}".source},\n")
(attrNames config.security.pam.services) +
@ -1413,88 +1519,18 @@ in
mr ${getLib pkgs.pam}/lib/security/pam_*.so,
r ${getLib pkgs.pam}/lib/security/,
'' +
optionalString use_ldap ''
mr ${pam_ldap}/lib/security/pam_ldap.so,
'' +
optionalString config.services.kanidm.enablePam ''
mr ${pkgs.kanidm}/lib/pam_kanidm.so,
'' +
optionalString config.services.sssd.enable ''
mr ${pkgs.sssd}/lib/security/pam_sss.so,
'' +
optionalString config.security.pam.krb5.enable ''
mr ${pam_krb5}/lib/security/pam_krb5.so,
mr ${pam_ccreds}/lib/security/pam_ccreds.so,
'' +
optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_admin.so,
'' +
optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication)) ''
mr ${pkgs.google-guest-oslogin}/lib/security/pam_oslogin_login.so,
'' +
optionalString (config.security.pam.enableSSHAgentAuth
&& isEnabled (cfg: cfg.sshAgentAuth)) ''
mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so,
'' +
optionalString (isEnabled (cfg: cfg.fprintAuth)) ''
mr ${pkgs.fprintd}/lib/security/pam_fprintd.so,
'' +
optionalString (isEnabled (cfg: cfg.u2fAuth)) ''
mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so,
'' +
optionalString (isEnabled (cfg: cfg.usbAuth)) ''
mr ${pkgs.pam_usb}/lib/security/pam_usb.so,
'' +
optionalString (isEnabled (cfg: cfg.usshAuth)) ''
mr ${pkgs.pam_ussh}/lib/security/pam_ussh.so,
'' +
optionalString (isEnabled (cfg: cfg.oathAuth)) ''
"mr ${pkgs.oath-toolkit}/lib/security/pam_oath.so,
'' +
optionalString (isEnabled (cfg: cfg.mysqlAuth)) ''
mr ${pkgs.pam_mysql}/lib/security/pam_mysql.so,
'' +
optionalString (isEnabled (cfg: cfg.yubicoAuth)) ''
mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so,
'' +
optionalString (isEnabled (cfg: cfg.duoSecurity.enable)) ''
mr ${pkgs.duo-unix}/lib/security/pam_duo.so,
'' +
optionalString (isEnabled (cfg: cfg.otpwAuth)) ''
mr ${pkgs.otpw}/lib/security/pam_otpw.so,
'' +
optionalString config.security.pam.enableEcryptfs ''
mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so,
'' +
optionalString config.security.pam.enableFscrypt ''
mr ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so,
'' +
optionalString (isEnabled (cfg: cfg.pamMount)) ''
mr ${pkgs.pam_mount}/lib/security/pam_mount.so,
'' +
optionalString (isEnabled (cfg: cfg.enableGnomeKeyring)) ''
mr ${pkgs.gnome.gnome-keyring}/lib/security/pam_gnome_keyring.so,
'' +
optionalString (isEnabled (cfg: cfg.startSession)) ''
mr ${config.systemd.package}/lib/security/pam_systemd.so,
'' +
optionalString (isEnabled (cfg: cfg.enableAppArmor)
&& config.security.apparmor.enable) ''
mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so,
'' +
optionalString (isEnabled (cfg: cfg.enableKwallet)) ''
mr ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so,
'' +
optionalString config.virtualisation.lxc.lxcfs.enable ''
mr ${pkgs.lxc}/lib/security/pam_cgfs.so,
'' +
optionalString (isEnabled (cfg: cfg.zfs)) ''
mr ${config.boot.zfs.package}/lib/security/pam_zfs_key.so,
'' +
optionalString config.services.homed.enable ''
mr ${config.systemd.package}/lib/security/pam_systemd_home.so
'';
(with lib; pipe config.security.pam.services [
attrValues
(catAttrs "rules")
(concatMap attrValues)
(concatMap attrValues)
(filter (rule: rule.enable))
(catAttrs "modulePath")
(filter (hasPrefix "/"))
unique
(map (module: "mr ${module},"))
concatLines
]);
};
}

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