Project import generated by Copybara.
GitOrigin-RevId: 395879c28386e1abf20c7ecacd45880759548391
This commit is contained in:
parent
576896970a
commit
3cbfd2b52c
1939 changed files with 41662 additions and 38968 deletions
6
third_party/nixpkgs/.github/CODEOWNERS
vendored
6
third_party/nixpkgs/.github/CODEOWNERS
vendored
|
@ -39,7 +39,7 @@
|
||||||
/pkgs/top-level/stage.nix @nbp @Ericson2314 @matthewbauer
|
/pkgs/top-level/stage.nix @nbp @Ericson2314 @matthewbauer
|
||||||
/pkgs/top-level/splice.nix @Ericson2314 @matthewbauer
|
/pkgs/top-level/splice.nix @Ericson2314 @matthewbauer
|
||||||
/pkgs/top-level/release-cross.nix @Ericson2314 @matthewbauer
|
/pkgs/top-level/release-cross.nix @Ericson2314 @matthewbauer
|
||||||
/pkgs/stdenv/generic @Ericson2314 @matthewbauer
|
/pkgs/stdenv/generic @Ericson2314 @matthewbauer @cab404
|
||||||
/pkgs/stdenv/cross @Ericson2314 @matthewbauer
|
/pkgs/stdenv/cross @Ericson2314 @matthewbauer
|
||||||
/pkgs/build-support/cc-wrapper @Ericson2314 @orivej
|
/pkgs/build-support/cc-wrapper @Ericson2314 @orivej
|
||||||
/pkgs/build-support/bintools-wrapper @Ericson2314 @orivej
|
/pkgs/build-support/bintools-wrapper @Ericson2314 @orivej
|
||||||
|
@ -219,9 +219,9 @@
|
||||||
# Podman, CRI-O modules and related
|
# Podman, CRI-O modules and related
|
||||||
/nixos/modules/virtualisation/containers.nix @NixOS/podman @zowoq @adisbladis
|
/nixos/modules/virtualisation/containers.nix @NixOS/podman @zowoq @adisbladis
|
||||||
/nixos/modules/virtualisation/cri-o.nix @NixOS/podman @zowoq @adisbladis
|
/nixos/modules/virtualisation/cri-o.nix @NixOS/podman @zowoq @adisbladis
|
||||||
/nixos/modules/virtualisation/podman.nix @NixOS/podman @zowoq @adisbladis
|
/nixos/modules/virtualisation/podman @NixOS/podman @zowoq @adisbladis
|
||||||
/nixos/tests/cri-o.nix @NixOS/podman @zowoq @adisbladis
|
/nixos/tests/cri-o.nix @NixOS/podman @zowoq @adisbladis
|
||||||
/nixos/tests/podman.nix @NixOS/podman @zowoq @adisbladis
|
/nixos/tests/podman @NixOS/podman @zowoq @adisbladis
|
||||||
|
|
||||||
# Docker tools
|
# Docker tools
|
||||||
/pkgs/build-support/docker @roberth @utdemir
|
/pkgs/build-support/docker @roberth @utdemir
|
||||||
|
|
|
@ -31,7 +31,8 @@ jobs:
|
||||||
- uses: cachix/install-nix-action@v16
|
- uses: cachix/install-nix-action@v16
|
||||||
with:
|
with:
|
||||||
# nixpkgs commit is pinned so that it doesn't break
|
# nixpkgs commit is pinned so that it doesn't break
|
||||||
nix_path: nixpkgs=https://github.com/NixOS/nixpkgs/archive/f93ecc4f6bc60414d8b73dbdf615ceb6a2c604df.tar.gz
|
# editorconfig-checker 2.4.0
|
||||||
|
nix_path: nixpkgs=https://github.com/NixOS/nixpkgs/archive/c473cc8714710179df205b153f4e9fa007107ff9.tar.gz
|
||||||
- name: install editorconfig-checker
|
- name: install editorconfig-checker
|
||||||
run: nix-env -iA editorconfig-checker -f '<nixpkgs>'
|
run: nix-env -iA editorconfig-checker -f '<nixpkgs>'
|
||||||
- name: Checking EditorConfig
|
- name: Checking EditorConfig
|
||||||
|
|
|
@ -72,7 +72,18 @@ The `dotnetCorePackages.sdk` contains both a runtime and the full sdk of a given
|
||||||
To package Dotnet applications, you can use `buildDotnetModule`. This has similar arguments to `stdenv.mkDerivation`, with the following additions:
|
To package Dotnet applications, you can use `buildDotnetModule`. This has similar arguments to `stdenv.mkDerivation`, with the following additions:
|
||||||
|
|
||||||
* `projectFile` has to be used for specifying the dotnet project file relative to the source root. These usually have `.sln` or `.csproj` file extensions. This can be an array of multiple projects as well.
|
* `projectFile` has to be used for specifying the dotnet project file relative to the source root. These usually have `.sln` or `.csproj` file extensions. This can be an array of multiple projects as well.
|
||||||
* `nugetDeps` has to be used to specify the NuGet dependency file. Unfortunately, these cannot be deterministically fetched without a lockfile. This file should be generated using `nuget-to-nix` tool, which is available in nixpkgs.
|
* `nugetDeps` has to be used to specify the NuGet dependency file. Unfortunately, these cannot be deterministically fetched without a lockfile. A script to fetch these is available as `passthru.fetch-deps`. This file can also be generated manually using `nuget-to-nix` tool, which is available in nixpkgs.
|
||||||
|
* `packNupkg` is used to pack project as a `nupkg`, and installs it to `$out/share`. If set to `true`, the derivation can be used as a dependency for another dotnet project by adding it to `projectReferences`.
|
||||||
|
* `projectReferences` can be used to resolve `ProjectReference` project items. Referenced projects can be packed with `buildDotnetModule` by setting the `packNupkg = true` attribute and passing a list of derivations to `projectReferences`. Since we are sharing referenced projects as NuGets they must be added to csproj/fsproj files as `PackageReference` as well.
|
||||||
|
For example, your project has a local dependency:
|
||||||
|
```xml
|
||||||
|
<ProjectReference Include="../foo/bar.fsproj" />
|
||||||
|
```
|
||||||
|
To enable discovery through `projectReferences` you would need to add:
|
||||||
|
```xml
|
||||||
|
<ProjectReference Include="../foo/bar.fsproj" />
|
||||||
|
<PackageReference Include="bar" Version="*" Condition=" '$(ContinuousIntegrationBuild)'=='true' "/>
|
||||||
|
```
|
||||||
* `executables` is used to specify which executables get wrapped to `$out/bin`, relative to `$out/lib/$pname`. If this is unset, all executables generated will get installed. If you do not want to install any, set this to `[]`.
|
* `executables` is used to specify which executables get wrapped to `$out/bin`, relative to `$out/lib/$pname`. If this is unset, all executables generated will get installed. If you do not want to install any, set this to `[]`.
|
||||||
* `runtimeDeps` is used to wrap libraries into `LD_LIBRARY_PATH`. This is how dotnet usually handles runtime dependencies.
|
* `runtimeDeps` is used to wrap libraries into `LD_LIBRARY_PATH`. This is how dotnet usually handles runtime dependencies.
|
||||||
* `buildType` is used to change the type of build. Possible values are `Release`, `Debug`, etc. By default, this is set to `Release`.
|
* `buildType` is used to change the type of build. Possible values are `Release`, `Debug`, etc. By default, this is set to `Release`.
|
||||||
|
@ -83,22 +94,29 @@ To package Dotnet applications, you can use `buildDotnetModule`. This has simila
|
||||||
* `disabledTests` is used to disable running specific unit tests. This gets passed as: `dotnet test --filter "FullyQualifiedName!={}"`, to ensure compatibility with all unit test frameworks.
|
* `disabledTests` is used to disable running specific unit tests. This gets passed as: `dotnet test --filter "FullyQualifiedName!={}"`, to ensure compatibility with all unit test frameworks.
|
||||||
* `dotnetRestoreFlags` can be used to pass flags to `dotnet restore`.
|
* `dotnetRestoreFlags` can be used to pass flags to `dotnet restore`.
|
||||||
* `dotnetBuildFlags` can be used to pass flags to `dotnet build`.
|
* `dotnetBuildFlags` can be used to pass flags to `dotnet build`.
|
||||||
* `dotnetTestFlags` can be used to pass flags to `dotnet test`.
|
* `dotnetTestFlags` can be used to pass flags to `dotnet test`. Used only if `doCheck` is set to `true`.
|
||||||
* `dotnetInstallFlags` can be used to pass flags to `dotnet install`.
|
* `dotnetInstallFlags` can be used to pass flags to `dotnet install`.
|
||||||
|
* `dotnetPackFlags` can be used to pass flags to `dotnet pack`. Used only if `packNupkg` is set to `true`.
|
||||||
* `dotnetFlags` can be used to pass flags to all of the above phases.
|
* `dotnetFlags` can be used to pass flags to all of the above phases.
|
||||||
|
|
||||||
|
When packaging a new application, you need to fetch it's dependencies. You can set `nugetDeps` to an empty string to make the derivation temporarily evaluate, and then run `nix-build -A package.passthru.fetch-deps` to generate it's dependency fetching script. After running the script, you should have the location of the generated lockfile printed to the console. This can be copied to a stable directory. Note that if either `projectFile` or `nugetDeps` are unset, this script cannot be generated!
|
||||||
|
|
||||||
Here is an example `default.nix`, using some of the previously discussed arguments:
|
Here is an example `default.nix`, using some of the previously discussed arguments:
|
||||||
```nix
|
```nix
|
||||||
{ lib, buildDotnetModule, dotnetCorePackages, ffmpeg }:
|
{ lib, buildDotnetModule, dotnetCorePackages, ffmpeg }:
|
||||||
|
|
||||||
buildDotnetModule rec {
|
let
|
||||||
|
referencedProject = import ../../bar { ... };
|
||||||
|
in buildDotnetModule rec {
|
||||||
pname = "someDotnetApplication";
|
pname = "someDotnetApplication";
|
||||||
version = "0.1";
|
version = "0.1";
|
||||||
|
|
||||||
src = ./.;
|
src = ./.;
|
||||||
|
|
||||||
projectFile = "src/project.sln";
|
projectFile = "src/project.sln";
|
||||||
nugetDeps = ./deps.nix; # File generated with `nuget-to-nix path/to/src > deps.nix`.
|
nugetDeps = ./deps.nix; # File generated with `nix-build -A package.passthru.fetch-deps`.
|
||||||
|
|
||||||
|
projectReferences = [ referencedProject ]; # `referencedProject` must contain `nupkg` in the folder structure.
|
||||||
|
|
||||||
dotnet-sdk = dotnetCorePackages.sdk_3_1;
|
dotnet-sdk = dotnetCorePackages.sdk_3_1;
|
||||||
dotnet-runtime = dotnetCorePackages.net_5_0;
|
dotnet-runtime = dotnetCorePackages.net_5_0;
|
||||||
|
@ -107,6 +125,8 @@ buildDotnetModule rec {
|
||||||
executables = [ "foo" ]; # This wraps "$out/lib/$pname/foo" to `$out/bin/foo`.
|
executables = [ "foo" ]; # This wraps "$out/lib/$pname/foo" to `$out/bin/foo`.
|
||||||
executables = []; # Don't install any executables.
|
executables = []; # Don't install any executables.
|
||||||
|
|
||||||
|
packNupkg = true; # This packs the project as "foo-0.1.nupkg" at `$out/share`.
|
||||||
|
|
||||||
runtimeDeps = [ ffmpeg ]; # This will wrap ffmpeg's library path into `LD_LIBRARY_PATH`.
|
runtimeDeps = [ ffmpeg ]; # This will wrap ffmpeg's library path into `LD_LIBRARY_PATH`.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -92,7 +92,7 @@ For convenience, it also adds `dconf.lib` for a GIO module implementing a GSetti
|
||||||
|
|
||||||
- []{#ssec-gnome-hooks-glib} `glib` setup hook will populate `GSETTINGS_SCHEMAS_PATH` and then `wrapGAppsHook` will prepend it to `XDG_DATA_DIRS`.
|
- []{#ssec-gnome-hooks-glib} `glib` setup hook will populate `GSETTINGS_SCHEMAS_PATH` and then `wrapGAppsHook` will prepend it to `XDG_DATA_DIRS`.
|
||||||
|
|
||||||
- []{#ssec-gnome-hooks-gdk-pixbuf} `gdk-pixbuf` setup hook will populate `GDK_PIXBUF_MODULE_FILE` with the path to biggest `loaders.cache` file from the dependencies containing [GdkPixbuf loaders](ssec-gnome-gdk-pixbuf-loaders). This works fine when there are only two packages containing loaders (`gdk-pixbuf` and e.g. `librsvg`) – it will choose the second one, reasonably expecting that it will be bigger since it describes extra loader in addition to the default ones. But when there are more than two loader packages, this logic will break. One possible solution would be constructing a custom cache file for each package containing a program like `services/x11/gdk-pixbuf.nix` NixOS module does. `wrapGAppsHook` copies the `GDK_PIXBUF_MODULE_FILE` environment variable into the produced wrapper.
|
- []{#ssec-gnome-hooks-gdk-pixbuf} `gdk-pixbuf` setup hook will populate `GDK_PIXBUF_MODULE_FILE` with the path to biggest `loaders.cache` file from the dependencies containing [GdkPixbuf loaders](#ssec-gnome-gdk-pixbuf-loaders). This works fine when there are only two packages containing loaders (`gdk-pixbuf` and e.g. `librsvg`) – it will choose the second one, reasonably expecting that it will be bigger since it describes extra loader in addition to the default ones. But when there are more than two loader packages, this logic will break. One possible solution would be constructing a custom cache file for each package containing a program like `services/x11/gdk-pixbuf.nix` NixOS module does. `wrapGAppsHook` copies the `GDK_PIXBUF_MODULE_FILE` environment variable into the produced wrapper.
|
||||||
|
|
||||||
- []{#ssec-gnome-hooks-gtk-drop-icon-theme-cache} One of `gtk3`’s setup hooks will remove `icon-theme.cache` files from package’s icon theme directories to avoid conflicts. Icon theme packages should prevent this with `dontDropIconThemeCache = true;`.
|
- []{#ssec-gnome-hooks-gtk-drop-icon-theme-cache} One of `gtk3`’s setup hooks will remove `icon-theme.cache` files from package’s icon theme directories to avoid conflicts. Icon theme packages should prevent this with `dontDropIconThemeCache = true;`.
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ Let's present the luarocks way first and the manual one in a second time.
|
||||||
|
|
||||||
### Packaging a library on luarocks {#packaging-a-library-on-luarocks}
|
### Packaging a library on luarocks {#packaging-a-library-on-luarocks}
|
||||||
|
|
||||||
[Luarocks.org](www.luarocks.org) is the main repository of lua packages.
|
[Luarocks.org](https://luarocks.org/) is the main repository of lua packages.
|
||||||
The site proposes two types of packages, the rockspec and the src.rock
|
The site proposes two types of packages, the rockspec and the src.rock
|
||||||
(equivalent of a [rockspec](https://github.com/luarocks/luarocks/wiki/Rockspec-format) but with the source).
|
(equivalent of a [rockspec](https://github.com/luarocks/luarocks/wiki/Rockspec-format) but with the source).
|
||||||
These packages can have different build types such as `cmake`, `builtin` etc .
|
These packages can have different build types such as `cmake`, `builtin` etc .
|
||||||
|
|
|
@ -995,18 +995,18 @@ called with `callPackage` and passed `python` or `pythonPackages` (possibly
|
||||||
specifying an interpreter version), like this:
|
specifying an interpreter version), like this:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ lib, python3Packages }:
|
{ lib, python3 }:
|
||||||
|
|
||||||
python3Packages.buildPythonApplication rec {
|
python3.pkgs.buildPythonApplication rec {
|
||||||
pname = "luigi";
|
pname = "luigi";
|
||||||
version = "2.7.9";
|
version = "2.7.9";
|
||||||
|
|
||||||
src = python3Packages.fetchPypi {
|
src = python3.pkgs.fetchPypi {
|
||||||
inherit pname version;
|
inherit pname version;
|
||||||
sha256 = "035w8gqql36zlan0xjrzz9j4lh9hs0qrsgnbyw07qs7lnkvbdv9x";
|
sha256 = "035w8gqql36zlan0xjrzz9j4lh9hs0qrsgnbyw07qs7lnkvbdv9x";
|
||||||
};
|
};
|
||||||
|
|
||||||
propagatedBuildInputs = with python3Packages; [ tornado_4 python-daemon ];
|
propagatedBuildInputs = with python3.pkgs; [ tornado python-daemon ];
|
||||||
|
|
||||||
meta = with lib; {
|
meta = with lib; {
|
||||||
...
|
...
|
||||||
|
@ -1632,3 +1632,25 @@ would be:
|
||||||
```ShellSession
|
```ShellSession
|
||||||
$ maintainers/scripts/update-python-libraries --target minor --commit --use-pkgs-prefix pkgs/development/python-modules/**/default.nix
|
$ maintainers/scripts/update-python-libraries --target minor --commit --use-pkgs-prefix pkgs/development/python-modules/**/default.nix
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## CPython Update Schedule
|
||||||
|
|
||||||
|
With [PEP 602](https://www.python.org/dev/peps/pep-0602/), CPython now
|
||||||
|
follows a yearly release cadence. In nixpkgs, all supported interpreters
|
||||||
|
are made available, but only the most recent two
|
||||||
|
interpreters package sets are built; this is a compromise between being
|
||||||
|
the latest interpreter, and what the majority of the Python packages support.
|
||||||
|
|
||||||
|
New CPython interpreters are released in October. Generally, it takes some
|
||||||
|
time for the majority of active Python projects to support the latest stable
|
||||||
|
interpreter. To help ease the migration for Nixpkgs users
|
||||||
|
between Python interpreters the schedule below will be used:
|
||||||
|
|
||||||
|
| When | Event |
|
||||||
|
| --- | --- |
|
||||||
|
| After YY.11 Release | Bump CPython package set window. The latest and previous latest stable should now be built. |
|
||||||
|
| After YY.05 Release | Bump default CPython interpreter to latest stable. |
|
||||||
|
|
||||||
|
In practice, this means that the Python community will have had a stable interpreter
|
||||||
|
for ~2 months before attempting to update the package set. And this will
|
||||||
|
allow for ~7 months for Python applications to support the latest interpreter.
|
||||||
|
|
|
@ -201,6 +201,19 @@ $ nix-shell --run 'ruby -rpg -e "puts PG.library_version"'
|
||||||
|
|
||||||
Of course for this use-case one could also use overlays since the configuration for `pg` depends on the `postgresql` alias, but for demonstration purposes this has to suffice.
|
Of course for this use-case one could also use overlays since the configuration for `pg` depends on the `postgresql` alias, but for demonstration purposes this has to suffice.
|
||||||
|
|
||||||
|
### Platform-specific gems
|
||||||
|
|
||||||
|
Right now, bundix has some issues with pre-built, platform-specific gems: [bundix PR #68](https://github.com/nix-community/bundix/pull/68).
|
||||||
|
Until this is solved, you can tell bundler to not use platform-specific gems and instead build them from source each time:
|
||||||
|
- globally (will be set in `~/.config/.bundle/config`):
|
||||||
|
```shell
|
||||||
|
$ bundle config set force_ruby_platform true
|
||||||
|
```
|
||||||
|
- locally (will be set in `<project-root>/.bundle/config`):
|
||||||
|
```shell
|
||||||
|
$ bundle config set --local force_ruby_platform true
|
||||||
|
```
|
||||||
|
|
||||||
### Adding a gem to the default gemset {#adding-a-gem-to-the-default-gemset}
|
### Adding a gem to the default gemset {#adding-a-gem-to-the-default-gemset}
|
||||||
|
|
||||||
Now that you know how to get a working Ruby environment with Nix, it's time to go forward and start actually developing with Ruby. We will first have a look at how Ruby gems are packaged on Nix. Then, we will look at how you can use development mode with your code.
|
Now that you know how to get a working Ruby environment with Nix, it's time to go forward and start actually developing with Ruby. We will first have a look at how Ruby gems are packaged on Nix. Then, we will look at how you can use development mode with your code.
|
||||||
|
|
|
@ -293,7 +293,7 @@ Test flags, e.g., `--package foo`, can be passed to `cargo test` via the
|
||||||
|
|
||||||
Another attribute, called `checkFlags`, is used to pass arguments to the test
|
Another attribute, called `checkFlags`, is used to pass arguments to the test
|
||||||
binary itself, as stated
|
binary itself, as stated
|
||||||
(here)[https://doc.rust-lang.org/cargo/commands/cargo-test.html].
|
[here](https://doc.rust-lang.org/cargo/commands/cargo-test.html).
|
||||||
|
|
||||||
#### Tests relying on the structure of the `target/` directory {#tests-relying-on-the-structure-of-the-target-directory}
|
#### Tests relying on the structure of the `target/` directory {#tests-relying-on-the-structure-of-the-target-directory}
|
||||||
|
|
||||||
|
|
|
@ -309,9 +309,9 @@ Sample output2:
|
||||||
|
|
||||||
## Adding new plugins to nixpkgs {#adding-new-plugins-to-nixpkgs}
|
## Adding new plugins to nixpkgs {#adding-new-plugins-to-nixpkgs}
|
||||||
|
|
||||||
Nix expressions for Vim plugins are stored in [pkgs/misc/vim-plugins](/pkgs/misc/vim-plugins). For the vast majority of plugins, Nix expressions are automatically generated by running [`./update.py`](/pkgs/misc/vim-plugins/update.py). This creates a [generated.nix](/pkgs/misc/vim-plugins/generated.nix) file based on the plugins listed in [vim-plugin-names](/pkgs/misc/vim-plugins/vim-plugin-names). Plugins are listed in alphabetical order in `vim-plugin-names` using the format `[github username]/[repository]@[gitref]`. For example https://github.com/scrooloose/nerdtree becomes `scrooloose/nerdtree`.
|
Nix expressions for Vim plugins are stored in [pkgs/misc/vim-plugins](https://github.com/NixOS/nixpkgs/tree/master/pkgs/misc/vim-plugins). For the vast majority of plugins, Nix expressions are automatically generated by running [`./update.py`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/update.py). This creates a [generated.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/generated.nix) file based on the plugins listed in [vim-plugin-names](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/vim-plugin-names). Plugins are listed in alphabetical order in `vim-plugin-names` using the format `[github username]/[repository]@[gitref]`. For example https://github.com/scrooloose/nerdtree becomes `scrooloose/nerdtree`.
|
||||||
|
|
||||||
Some plugins require overrides in order to function properly. Overrides are placed in [overrides.nix](/pkgs/misc/vim-plugins/overrides.nix). Overrides are most often required when a plugin requires some dependencies, or extra steps are required during the build process. For example `deoplete-fish` requires both `deoplete-nvim` and `vim-fish`, and so the following override was added:
|
Some plugins require overrides in order to function properly. Overrides are placed in [overrides.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/overrides.nix). Overrides are most often required when a plugin requires some dependencies, or extra steps are required during the build process. For example `deoplete-fish` requires both `deoplete-nvim` and `vim-fish`, and so the following override was added:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
deoplete-fish = super.deoplete-fish.overrideAttrs(old: {
|
deoplete-fish = super.deoplete-fish.overrideAttrs(old: {
|
||||||
|
|
12
third_party/nixpkgs/doc/stdenv/stdenv.chapter.md
vendored
12
third_party/nixpkgs/doc/stdenv/stdenv.chapter.md
vendored
|
@ -796,7 +796,7 @@ The standard environment provides a number of useful functions.
|
||||||
|
|
||||||
### `makeWrapper` \<executable\> \<wrapperfile\> \<args\> {#fun-makeWrapper}
|
### `makeWrapper` \<executable\> \<wrapperfile\> \<args\> {#fun-makeWrapper}
|
||||||
|
|
||||||
Constructs a wrapper for a program with various possible arguments. For example:
|
Constructs a wrapper for a program with various possible arguments. It is defined as part of 2 setup-hooks named `makeWrapper` and `makeBinaryWrapper` that implement the same bash functions. Hence, to use it you have to add `makeWrapper` to your `nativeBuildInputs`. Here's an example usage:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# adds `FOOBAR=baz` to `$out/bin/foo`’s environment
|
# adds `FOOBAR=baz` to `$out/bin/foo`’s environment
|
||||||
|
@ -808,9 +808,11 @@ makeWrapper $out/bin/foo $wrapperfile --set FOOBAR baz
|
||||||
makeWrapper $out/bin/foo $wrapperfile --prefix PATH : ${lib.makeBinPath [ hello git ]}
|
makeWrapper $out/bin/foo $wrapperfile --prefix PATH : ${lib.makeBinPath [ hello git ]}
|
||||||
```
|
```
|
||||||
|
|
||||||
There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-wrapper.sh`.
|
There’s many more kinds of arguments, they are documented in `nixpkgs/pkgs/build-support/setup-hooks/make-wrapper.sh` for the `makeWrapper` implementation and in `nixpkgs/pkgs/build-support/setup-hooks/make-binary-wrapper.sh` for the `makeBinaryWrapper` implementation.
|
||||||
|
|
||||||
`wrapProgram` is a convenience function you probably want to use most of the time.
|
`wrapProgram` is a convenience function you probably want to use most of the time, implemented by both `makeWrapper` and `makeBinaryWrapper`.
|
||||||
|
|
||||||
|
Using the `makeBinaryWrapper` implementation is usually preferred, as it creates a tiny _compiled_ wrapper executable, that can be used as a shebang interpreter. This is needed mostly on Darwin, where shebangs cannot point to scripts, [due to a limitation with the `execve`-syscall](https://stackoverflow.com/questions/67100831/macos-shebang-with-absolute-path-not-working). Compiled wrappers generated by `makeBinaryWrapper` can be inspected with `less <path-to-wrapper>` - by scrolling past the binary data you should be able to see the shell command that generated the executable and there see the environment variables that were injected into the wrapper.
|
||||||
|
|
||||||
### `substitute` \<infile\> \<outfile\> \<subs\> {#fun-substitute}
|
### `substitute` \<infile\> \<outfile\> \<subs\> {#fun-substitute}
|
||||||
|
|
||||||
|
@ -885,9 +887,9 @@ someVar=$(stripHash $name)
|
||||||
|
|
||||||
### `wrapProgram` \<executable\> \<makeWrapperArgs\> {#fun-wrapProgram}
|
### `wrapProgram` \<executable\> \<makeWrapperArgs\> {#fun-wrapProgram}
|
||||||
|
|
||||||
Convenience function for `makeWrapper` that automatically creates a sane wrapper file. It takes all the same arguments as `makeWrapper`, except for `--argv0`.
|
Convenience function for `makeWrapper` that replaces `<\executable\>` with a wrapper that executes the original program. It takes all the same arguments as `makeWrapper`, except for `--inherit-argv0` (used by the `makeBinaryWrapper` implementation) and `--argv0` (used by both `makeWrapper` and `makeBinaryWrapper` wrapper implementations).
|
||||||
|
|
||||||
It cannot be applied multiple times, since it will overwrite the wrapper file.
|
If you will apply it multiple times, it will overwrite the wrapper file and you will end up with double wrapping, which should be avoided.
|
||||||
|
|
||||||
## Package setup hooks {#ssec-setup-hooks}
|
## Package setup hooks {#ssec-setup-hooks}
|
||||||
|
|
||||||
|
|
2
third_party/nixpkgs/lib/default.nix
vendored
2
third_party/nixpkgs/lib/default.nix
vendored
|
@ -105,7 +105,7 @@ let
|
||||||
makeScope makeScopeWithSplicing;
|
makeScope makeScopeWithSplicing;
|
||||||
inherit (self.meta) addMetaAttrs dontDistribute setName updateName
|
inherit (self.meta) addMetaAttrs dontDistribute setName updateName
|
||||||
appendToName mapDerivationAttrset setPrio lowPrio lowPrioSet hiPrio
|
appendToName mapDerivationAttrset setPrio lowPrio lowPrioSet hiPrio
|
||||||
hiPrioSet;
|
hiPrioSet getLicenseFromSpdxId;
|
||||||
inherit (self.sources) pathType pathIsDirectory cleanSourceFilter
|
inherit (self.sources) pathType pathIsDirectory cleanSourceFilter
|
||||||
cleanSource sourceByRegex sourceFilesBySuffices
|
cleanSource sourceByRegex sourceFilesBySuffices
|
||||||
commitIdFromGitRepo cleanSourceWith pathHasContext
|
commitIdFromGitRepo cleanSourceWith pathHasContext
|
||||||
|
|
27
third_party/nixpkgs/lib/meta.nix
vendored
27
third_party/nixpkgs/lib/meta.nix
vendored
|
@ -99,4 +99,31 @@ rec {
|
||||||
availableOn = platform: pkg:
|
availableOn = platform: pkg:
|
||||||
lib.any (platformMatch platform) pkg.meta.platforms &&
|
lib.any (platformMatch platform) pkg.meta.platforms &&
|
||||||
lib.all (elem: !platformMatch platform elem) (pkg.meta.badPlatforms or []);
|
lib.all (elem: !platformMatch platform elem) (pkg.meta.badPlatforms or []);
|
||||||
|
|
||||||
|
/* Get the corresponding attribute in lib.licenses
|
||||||
|
from the SPDX ID.
|
||||||
|
For SPDX IDs, see
|
||||||
|
https://spdx.org/licenses
|
||||||
|
|
||||||
|
Type:
|
||||||
|
getLicenseFromSpdxId :: str -> AttrSet
|
||||||
|
|
||||||
|
Example:
|
||||||
|
lib.getLicenseFromSpdxId "MIT" == lib.licenses.mit
|
||||||
|
=> true
|
||||||
|
lib.getLicenseFromSpdxId "mIt" == lib.licenses.mit
|
||||||
|
=> true
|
||||||
|
lib.getLicenseFromSpdxId "MY LICENSE"
|
||||||
|
=> trace: warning: getLicenseFromSpdxId: No license matches the given SPDX ID: MY LICENSE
|
||||||
|
=> { shortName = "MY LICENSE"; }
|
||||||
|
*/
|
||||||
|
getLicenseFromSpdxId =
|
||||||
|
let
|
||||||
|
spdxLicenses = lib.mapAttrs (id: ls: assert lib.length ls == 1; builtins.head ls)
|
||||||
|
(lib.groupBy (l: lib.toLower l.spdxId) (lib.filter (l: l ? spdxId) (lib.attrValues lib.licenses)));
|
||||||
|
in licstr:
|
||||||
|
spdxLicenses.${ lib.toLower licstr } or (
|
||||||
|
lib.warn "getLicenseFromSpdxId: No license matches the given SPDX ID: ${licstr}"
|
||||||
|
{ shortName = licstr; }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
65
third_party/nixpkgs/lib/modules.nix
vendored
65
third_party/nixpkgs/lib/modules.nix
vendored
|
@ -13,8 +13,6 @@ let
|
||||||
elem
|
elem
|
||||||
filter
|
filter
|
||||||
findFirst
|
findFirst
|
||||||
flip
|
|
||||||
foldl
|
|
||||||
foldl'
|
foldl'
|
||||||
getAttrFromPath
|
getAttrFromPath
|
||||||
head
|
head
|
||||||
|
@ -101,9 +99,31 @@ rec {
|
||||||
check ? true
|
check ? true
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
|
withWarnings = x:
|
||||||
|
lib.warnIf (evalModulesArgs?args) "The args argument to evalModules is deprecated. Please set config._module.args instead."
|
||||||
|
lib.warnIf (evalModulesArgs?check) "The check argument to evalModules is deprecated. Please set config._module.check instead."
|
||||||
|
x;
|
||||||
|
|
||||||
|
legacyModules =
|
||||||
|
optional (evalModulesArgs?args) {
|
||||||
|
config = {
|
||||||
|
_module.args = args;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
++ optional (evalModulesArgs?check) {
|
||||||
|
config = {
|
||||||
|
_module.check = mkDefault check;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
regularModules = modules ++ legacyModules;
|
||||||
|
|
||||||
# This internal module declare internal options under the `_module'
|
# This internal module declare internal options under the `_module'
|
||||||
# attribute. These options are fragile, as they are used by the
|
# attribute. These options are fragile, as they are used by the
|
||||||
# module system to change the interpretation of modules.
|
# module system to change the interpretation of modules.
|
||||||
|
#
|
||||||
|
# When extended with extendModules or moduleType, a fresh instance of
|
||||||
|
# this module is used, to avoid conflicts and allow chaining of
|
||||||
|
# extendModules.
|
||||||
internalModule = rec {
|
internalModule = rec {
|
||||||
_file = ./modules.nix;
|
_file = ./modules.nix;
|
||||||
|
|
||||||
|
@ -125,7 +145,7 @@ rec {
|
||||||
_module.check = mkOption {
|
_module.check = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
internal = true;
|
internal = true;
|
||||||
default = check;
|
default = true;
|
||||||
description = "Whether to check whether all option definitions have matching declarations.";
|
description = "Whether to check whether all option definitions have matching declarations.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -151,14 +171,14 @@ rec {
|
||||||
_module.args = {
|
_module.args = {
|
||||||
inherit extendModules;
|
inherit extendModules;
|
||||||
moduleType = type;
|
moduleType = type;
|
||||||
} // args;
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
merged =
|
merged =
|
||||||
let collected = collectModules
|
let collected = collectModules
|
||||||
(specialArgs.modulesPath or "")
|
(specialArgs.modulesPath or "")
|
||||||
(modules ++ [ internalModule ])
|
(regularModules ++ [ internalModule ])
|
||||||
({ inherit lib options config specialArgs; } // specialArgs);
|
({ inherit lib options config specialArgs; } // specialArgs);
|
||||||
in mergeModules prefix (reverseList collected);
|
in mergeModules prefix (reverseList collected);
|
||||||
|
|
||||||
|
@ -222,7 +242,7 @@ rec {
|
||||||
prefix ? [],
|
prefix ? [],
|
||||||
}:
|
}:
|
||||||
evalModules (evalModulesArgs // {
|
evalModules (evalModulesArgs // {
|
||||||
modules = evalModulesArgs.modules ++ modules;
|
modules = regularModules ++ modules;
|
||||||
specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
|
specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
|
||||||
prefix = extendArgs.prefix or evalModulesArgs.prefix;
|
prefix = extendArgs.prefix or evalModulesArgs.prefix;
|
||||||
});
|
});
|
||||||
|
@ -231,7 +251,7 @@ rec {
|
||||||
inherit modules specialArgs;
|
inherit modules specialArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
result = {
|
result = withWarnings {
|
||||||
options = checked options;
|
options = checked options;
|
||||||
config = checked (removeAttrs config [ "_module" ]);
|
config = checked (removeAttrs config [ "_module" ]);
|
||||||
_module = checked (config._module);
|
_module = checked (config._module);
|
||||||
|
@ -452,7 +472,7 @@ rec {
|
||||||
[{ inherit (module) file; inherit value; }]
|
[{ inherit (module) file; inherit value; }]
|
||||||
) configs;
|
) configs;
|
||||||
|
|
||||||
resultsByName = flip mapAttrs declsByName (name: decls:
|
resultsByName = mapAttrs (name: decls:
|
||||||
# We're descending into attribute ‘name’.
|
# We're descending into attribute ‘name’.
|
||||||
let
|
let
|
||||||
loc = prefix ++ [name];
|
loc = prefix ++ [name];
|
||||||
|
@ -473,7 +493,7 @@ rec {
|
||||||
in
|
in
|
||||||
throw "The option `${showOption loc}' in `${firstOption._file}' is a prefix of options in `${firstNonOption._file}'."
|
throw "The option `${showOption loc}' in `${firstOption._file}' is a prefix of options in `${firstNonOption._file}'."
|
||||||
else
|
else
|
||||||
mergeModules' loc decls defns);
|
mergeModules' loc decls defns) declsByName;
|
||||||
|
|
||||||
matchedOptions = mapAttrs (n: v: v.matchedOptions) resultsByName;
|
matchedOptions = mapAttrs (n: v: v.matchedOptions) resultsByName;
|
||||||
|
|
||||||
|
@ -487,12 +507,19 @@ rec {
|
||||||
inherit matchedOptions;
|
inherit matchedOptions;
|
||||||
|
|
||||||
# Transforms unmatchedDefnsByName into a list of definitions
|
# Transforms unmatchedDefnsByName into a list of definitions
|
||||||
unmatchedDefns = concatLists (mapAttrsToList (name: defs:
|
unmatchedDefns =
|
||||||
map (def: def // {
|
if configs == []
|
||||||
# Set this so we know when the definition first left unmatched territory
|
then
|
||||||
prefix = [name] ++ (def.prefix or []);
|
# When no config values exist, there can be no unmatched config, so
|
||||||
}) defs
|
# we short circuit and avoid evaluating more _options_ than necessary.
|
||||||
) unmatchedDefnsByName);
|
[]
|
||||||
|
else
|
||||||
|
concatLists (mapAttrsToList (name: defs:
|
||||||
|
map (def: def // {
|
||||||
|
# Set this so we know when the definition first left unmatched territory
|
||||||
|
prefix = [name] ++ (def.prefix or []);
|
||||||
|
}) defs
|
||||||
|
) unmatchedDefnsByName);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Merge multiple option declarations into a single declaration. In
|
/* Merge multiple option declarations into a single declaration. In
|
||||||
|
@ -587,6 +614,8 @@ rec {
|
||||||
definitions = map (def: def.value) res.defsFinal;
|
definitions = map (def: def.value) res.defsFinal;
|
||||||
files = map (def: def.file) res.defsFinal;
|
files = map (def: def.file) res.defsFinal;
|
||||||
inherit (res) isDefined;
|
inherit (res) isDefined;
|
||||||
|
# This allows options to be correctly displayed using `${options.path.to.it}`
|
||||||
|
__toString = _: showOption loc;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Merge definitions of a value of a given type.
|
# Merge definitions of a value of a given type.
|
||||||
|
@ -906,7 +935,7 @@ rec {
|
||||||
mkMergedOptionModule = from: to: mergeFn:
|
mkMergedOptionModule = from: to: mergeFn:
|
||||||
{ config, options, ... }:
|
{ config, options, ... }:
|
||||||
{
|
{
|
||||||
options = foldl recursiveUpdate {} (map (path: setAttrByPath path (mkOption {
|
options = foldl' recursiveUpdate {} (map (path: setAttrByPath path (mkOption {
|
||||||
visible = false;
|
visible = false;
|
||||||
# To use the value in mergeFn without triggering errors
|
# To use the value in mergeFn without triggering errors
|
||||||
default = "_mkMergedOptionModule";
|
default = "_mkMergedOptionModule";
|
||||||
|
@ -1010,7 +1039,7 @@ rec {
|
||||||
|
|
||||||
/* Use this function to import a JSON file as NixOS configuration.
|
/* Use this function to import a JSON file as NixOS configuration.
|
||||||
|
|
||||||
importJSON -> path -> attrs
|
modules.importJSON :: path -> attrs
|
||||||
*/
|
*/
|
||||||
importJSON = file: {
|
importJSON = file: {
|
||||||
_file = file;
|
_file = file;
|
||||||
|
@ -1019,7 +1048,7 @@ rec {
|
||||||
|
|
||||||
/* Use this function to import a TOML file as NixOS configuration.
|
/* Use this function to import a TOML file as NixOS configuration.
|
||||||
|
|
||||||
importTOML -> path -> attrs
|
modules.importTOML :: path -> attrs
|
||||||
*/
|
*/
|
||||||
importTOML = file: {
|
importTOML = file: {
|
||||||
_file = file;
|
_file = file;
|
||||||
|
|
4
third_party/nixpkgs/lib/systems/doubles.nix
vendored
4
third_party/nixpkgs/lib/systems/doubles.nix
vendored
|
@ -39,8 +39,8 @@ let
|
||||||
"riscv32-netbsd" "riscv64-netbsd" "x86_64-netbsd"
|
"riscv32-netbsd" "riscv64-netbsd" "x86_64-netbsd"
|
||||||
|
|
||||||
# none
|
# none
|
||||||
"aarch64-none" "arm-none" "armv6l-none" "avr-none" "i686-none"
|
"aarch64_be-none" "aarch64-none" "arm-none" "armv6l-none" "avr-none" "i686-none"
|
||||||
"msp430-none" "or1k-none" "m68k-none" "powerpc-none"
|
"msp430-none" "or1k-none" "m68k-none" "powerpc-none" "powerpcle-none"
|
||||||
"riscv32-none" "riscv64-none" "s390-none" "s390x-none" "vc4-none"
|
"riscv32-none" "riscv64-none" "s390-none" "s390x-none" "vc4-none"
|
||||||
"x86_64-none"
|
"x86_64-none"
|
||||||
|
|
||||||
|
|
1
third_party/nixpkgs/lib/systems/examples.nix
vendored
1
third_party/nixpkgs/lib/systems/examples.nix
vendored
|
@ -290,6 +290,7 @@ rec {
|
||||||
libc = "nblibc";
|
libc = "nblibc";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# this is broken and never worked fully
|
||||||
x86_64-netbsd-llvm = {
|
x86_64-netbsd-llvm = {
|
||||||
config = "x86_64-unknown-netbsd";
|
config = "x86_64-unknown-netbsd";
|
||||||
libc = "nblibc";
|
libc = "nblibc";
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
{ lib }:
|
{ lib }:
|
||||||
rec {
|
rec {
|
||||||
# List of systems that are built by Hydra.
|
# List of systems that are built by Hydra.
|
||||||
hydra = tier1 ++ tier2 ++ tier3;
|
hydra = tier1 ++ tier2 ++ tier3 ++ [
|
||||||
|
"aarch64-darwin"
|
||||||
|
];
|
||||||
|
|
||||||
tier1 = [
|
tier1 = [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
|
@ -16,7 +18,6 @@ rec {
|
||||||
];
|
];
|
||||||
|
|
||||||
tier3 = [
|
tier3 = [
|
||||||
"aarch64-darwin"
|
|
||||||
"armv6l-linux"
|
"armv6l-linux"
|
||||||
"armv7l-linux"
|
"armv7l-linux"
|
||||||
"i686-linux"
|
"i686-linux"
|
||||||
|
|
2
third_party/nixpkgs/lib/tests/misc.nix
vendored
2
third_party/nixpkgs/lib/tests/misc.nix
vendored
|
@ -496,7 +496,7 @@ runTests {
|
||||||
|
|
||||||
testToPretty =
|
testToPretty =
|
||||||
let
|
let
|
||||||
deriv = derivation { name = "test"; builder = "/bin/sh"; system = builtins.currentSystem; };
|
deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; };
|
||||||
in {
|
in {
|
||||||
expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec {
|
expr = mapAttrs (const (generators.toPretty { multiline = false; })) rec {
|
||||||
int = 42;
|
int = 42;
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
{ lib, ... }: {
|
{ lib, ... }:
|
||||||
|
let
|
||||||
|
deathtrapArgs = lib.mapAttrs
|
||||||
|
(k: _: throw "The module system is too strict, accessing an unused option's ${k} mkOption-attribute.")
|
||||||
|
(lib.functionArgs lib.mkOption);
|
||||||
|
in
|
||||||
|
{
|
||||||
options.value = lib.mkOption {
|
options.value = lib.mkOption {
|
||||||
type = lib.types.attrsOf lib.types.str;
|
type = lib.types.attrsOf lib.types.str;
|
||||||
default = {};
|
default = {};
|
||||||
};
|
};
|
||||||
|
options.testing-laziness-so-don't-read-me = lib.mkOption deathtrapArgs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
{ lib, ... }: {
|
{ lib, ... }:
|
||||||
|
let
|
||||||
|
deathtrapArgs = lib.mapAttrs
|
||||||
|
(k: _: throw "The module system is too strict, accessing an unused option's ${k} mkOption-attribute.")
|
||||||
|
(lib.functionArgs lib.mkOption);
|
||||||
|
in
|
||||||
|
{
|
||||||
options.nest.foo = lib.mkOption {
|
options.nest.foo = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
};
|
};
|
||||||
|
options.nest.unused = lib.mkOption deathtrapArgs;
|
||||||
config.nest.bar = "bar";
|
config.nest.bar = "bar";
|
||||||
}
|
}
|
||||||
|
|
|
@ -278,6 +278,12 @@
|
||||||
githubId = 1250775;
|
githubId = 1250775;
|
||||||
name = "Adolfo E. García Castro";
|
name = "Adolfo E. García Castro";
|
||||||
};
|
};
|
||||||
|
AdsonCicilioti = {
|
||||||
|
name = "Adson Cicilioti";
|
||||||
|
email = "adson.cicilioti@live.com";
|
||||||
|
github = "AdsonCicilioti";
|
||||||
|
githubId = 6278398;
|
||||||
|
};
|
||||||
adsr = {
|
adsr = {
|
||||||
email = "as@php.net";
|
email = "as@php.net";
|
||||||
github = "adsr";
|
github = "adsr";
|
||||||
|
@ -351,10 +357,10 @@
|
||||||
name = "AmirHossein Roozbahani";
|
name = "AmirHossein Roozbahani";
|
||||||
};
|
};
|
||||||
ahuzik = {
|
ahuzik = {
|
||||||
email = "ales.guzik@gmail.com";
|
email = "ah1990au@gmail.com";
|
||||||
github = "alesguzik";
|
github = "alesya-h";
|
||||||
githubId = 209175;
|
githubId = 209175;
|
||||||
name = "Ales Huzik";
|
name = "Alesya Huzik";
|
||||||
};
|
};
|
||||||
aij = {
|
aij = {
|
||||||
email = "aij+git@mrph.org";
|
email = "aij+git@mrph.org";
|
||||||
|
@ -1408,6 +1414,12 @@
|
||||||
githubId = 251106;
|
githubId = 251106;
|
||||||
name = "Daniel Bergey";
|
name = "Daniel Bergey";
|
||||||
};
|
};
|
||||||
|
bergkvist = {
|
||||||
|
email = "tobias@bergkv.ist";
|
||||||
|
github = "bergkvist";
|
||||||
|
githubId = 410028;
|
||||||
|
name = "Tobias Bergkvist";
|
||||||
|
};
|
||||||
betaboon = {
|
betaboon = {
|
||||||
email = "betaboon@0x80.ninja";
|
email = "betaboon@0x80.ninja";
|
||||||
github = "betaboon";
|
github = "betaboon";
|
||||||
|
@ -3683,6 +3695,7 @@
|
||||||
};
|
};
|
||||||
evils = {
|
evils = {
|
||||||
email = "evils.devils@protonmail.com";
|
email = "evils.devils@protonmail.com";
|
||||||
|
matrix = "@evils:nixos.dev";
|
||||||
github = "evils";
|
github = "evils";
|
||||||
githubId = 30512529;
|
githubId = 30512529;
|
||||||
name = "Evils";
|
name = "Evils";
|
||||||
|
@ -4856,6 +4869,16 @@
|
||||||
githubId = 12491746;
|
githubId = 12491746;
|
||||||
name = "Masato Yonekawa";
|
name = "Masato Yonekawa";
|
||||||
};
|
};
|
||||||
|
hyshka = {
|
||||||
|
name = "Bryan Hyshka";
|
||||||
|
email = "bryan@hyshka.com";
|
||||||
|
github = "hyshka";
|
||||||
|
githubId = 2090758;
|
||||||
|
keys = [{
|
||||||
|
longkeyid = "rsa2048/0xDB2D93D1BFAAA6EA";
|
||||||
|
fingerprint = "24F4 1925 28C4 8797 E539 F247 DB2D 93D1 BFAA A6EA";
|
||||||
|
}];
|
||||||
|
};
|
||||||
hyzual = {
|
hyzual = {
|
||||||
email = "hyzual@gmail.com";
|
email = "hyzual@gmail.com";
|
||||||
github = "Hyzual";
|
github = "Hyzual";
|
||||||
|
@ -7665,6 +7688,12 @@
|
||||||
githubId = 21156022;
|
githubId = 21156022;
|
||||||
name = "Michal Minář";
|
name = "Michal Minář";
|
||||||
};
|
};
|
||||||
|
michzappa = {
|
||||||
|
email = "me@michzappa.com";
|
||||||
|
github = "michzappa";
|
||||||
|
githubId = 59343378;
|
||||||
|
name = "Michael Zappa";
|
||||||
|
};
|
||||||
mickours = {
|
mickours = {
|
||||||
email = "mickours@gmail.com<";
|
email = "mickours@gmail.com<";
|
||||||
github = "mickours";
|
github = "mickours";
|
||||||
|
@ -9015,6 +9044,12 @@
|
||||||
githubId = 116740;
|
githubId = 116740;
|
||||||
name = "Paweł Pacana";
|
name = "Paweł Pacana";
|
||||||
};
|
};
|
||||||
|
pb- = {
|
||||||
|
email = "pbaecher@gmail.com";
|
||||||
|
github = "pb-";
|
||||||
|
githubId = 84886;
|
||||||
|
name = "Paul Baecher";
|
||||||
|
};
|
||||||
pbogdan = {
|
pbogdan = {
|
||||||
email = "ppbogdan@gmail.com";
|
email = "ppbogdan@gmail.com";
|
||||||
github = "pbogdan";
|
github = "pbogdan";
|
||||||
|
@ -12095,6 +12130,12 @@
|
||||||
githubId = 122319;
|
githubId = 122319;
|
||||||
name = "Renato Alves";
|
name = "Renato Alves";
|
||||||
};
|
};
|
||||||
|
unrooted = {
|
||||||
|
name = "Konrad Klawikowski";
|
||||||
|
email = "konrad.root.klawikowski@gmail.com";
|
||||||
|
github = "unrooted";
|
||||||
|
githubId = 30440603;
|
||||||
|
};
|
||||||
uralbash = {
|
uralbash = {
|
||||||
email = "root@uralbash.ru";
|
email = "root@uralbash.ru";
|
||||||
github = "uralbash";
|
github = "uralbash";
|
||||||
|
@ -12544,6 +12585,12 @@
|
||||||
githubId = 78392041;
|
githubId = 78392041;
|
||||||
name = "Winter";
|
name = "Winter";
|
||||||
};
|
};
|
||||||
|
wintrmvte = {
|
||||||
|
name = "Jakub Lutczyn";
|
||||||
|
email = "kubalutczyn@gmail.com";
|
||||||
|
github = "wintrmvte";
|
||||||
|
githubId = 41823252;
|
||||||
|
};
|
||||||
wirew0rm = {
|
wirew0rm = {
|
||||||
email = "alex@wirew0rm.de";
|
email = "alex@wirew0rm.de";
|
||||||
github = "wirew0rm";
|
github = "wirew0rm";
|
||||||
|
@ -12622,6 +12669,12 @@
|
||||||
githubId = 28888242;
|
githubId = 28888242;
|
||||||
name = "WORLDofPEACE";
|
name = "WORLDofPEACE";
|
||||||
};
|
};
|
||||||
|
wr0belj = {
|
||||||
|
name = "Jakub Wróbel";
|
||||||
|
email = "wrobel.jakub@protonmail.com";
|
||||||
|
github = "wr0belj";
|
||||||
|
githubId = 40501814;
|
||||||
|
};
|
||||||
wscott = {
|
wscott = {
|
||||||
email = "wsc9tt@gmail.com";
|
email = "wsc9tt@gmail.com";
|
||||||
github = "wscott";
|
github = "wscott";
|
||||||
|
@ -12799,6 +12852,12 @@
|
||||||
githubId = 11229748;
|
githubId = 11229748;
|
||||||
name = "Lin Yinfeng";
|
name = "Lin Yinfeng";
|
||||||
};
|
};
|
||||||
|
ylecornec = {
|
||||||
|
email = "yves.stan.lecornec@tweag.io";
|
||||||
|
github = "ylecornec";
|
||||||
|
githubId = 5978566;
|
||||||
|
name = "Yves-Stan Le Cornec";
|
||||||
|
};
|
||||||
ylwghst = {
|
ylwghst = {
|
||||||
email = "ylwghst@onionmail.info";
|
email = "ylwghst@onionmail.info";
|
||||||
github = "ylwghst";
|
github = "ylwghst";
|
||||||
|
@ -13367,4 +13426,10 @@
|
||||||
github = "vdot0x23";
|
github = "vdot0x23";
|
||||||
githubId = 40716069;
|
githubId = 40716069;
|
||||||
};
|
};
|
||||||
|
jpagex = {
|
||||||
|
name = "Jérémy Pagé";
|
||||||
|
email = "contact@jeremypage.me";
|
||||||
|
github = "jpagex";
|
||||||
|
githubId = 635768;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,20 +4,19 @@
|
||||||
# Example how to work with the `lib.maintainers` attrset.
|
# Example how to work with the `lib.maintainers` attrset.
|
||||||
# Can be used to check whether all user handles are still valid.
|
# Can be used to check whether all user handles are still valid.
|
||||||
|
|
||||||
set -e
|
set -o errexit -o noclobber -o nounset -o pipefail
|
||||||
|
shopt -s failglob inherit_errexit
|
||||||
# nixpkgs='<nixpkgs>'
|
|
||||||
# if [ -n "$1" ]; then
|
|
||||||
|
|
||||||
function checkCommits {
|
function checkCommits {
|
||||||
local user="$1"
|
local ret status tmp user
|
||||||
local tmp=$(mktemp)
|
user="$1"
|
||||||
|
tmp=$(mktemp)
|
||||||
curl --silent -w "%{http_code}" \
|
curl --silent -w "%{http_code}" \
|
||||||
"https://github.com/NixOS/nixpkgs/commits?author=$user" \
|
"https://github.com/NixOS/nixpkgs/commits?author=$user" \
|
||||||
> "$tmp"
|
> "$tmp"
|
||||||
# the last line of tmp contains the http status
|
# the last line of tmp contains the http status
|
||||||
local status=$(tail -n1 "$tmp")
|
status=$(tail -n1 "$tmp")
|
||||||
local ret=
|
ret=
|
||||||
case $status in
|
case $status in
|
||||||
200) if <"$tmp" grep -i "no commits found" > /dev/null; then
|
200) if <"$tmp" grep -i "no commits found" > /dev/null; then
|
||||||
ret=1
|
ret=1
|
||||||
|
@ -31,7 +30,7 @@ function checkCommits {
|
||||||
checkCommits "$user"
|
checkCommits "$user"
|
||||||
ret=$?
|
ret=$?
|
||||||
;;
|
;;
|
||||||
*) printf "BAD STATUS: $(tail -n1 $tmp) for %s\n" "$user"; ret=1
|
*) printf "BAD STATUS: $(tail -n1 "$tmp") for %s\n" "$user"; ret=1
|
||||||
ret=1
|
ret=1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -63,4 +62,5 @@ nix-instantiate -A lib.maintainers --eval --strict --json \
|
||||||
| jq -r '.[]|.github|select(.)' \
|
| jq -r '.[]|.github|select(.)' \
|
||||||
| parallel -j5 checkUser
|
| parallel -j5 checkUser
|
||||||
|
|
||||||
|
# To check some arbitrary users:
|
||||||
# parallel -j100 checkUser ::: "eelco" "profpatsch" "Profpatsch" "a"
|
# parallel -j100 checkUser ::: "eelco" "profpatsch" "Profpatsch" "a"
|
||||||
|
|
|
@ -385,7 +385,7 @@ def check_results(
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
def parse_plugin_line(line: str) -> PluginDesc:
|
def parse_plugin_line(line: str) -> PluginDesc:
|
||||||
branch = "master"
|
branch = "HEAD"
|
||||||
alias = None
|
alias = None
|
||||||
name, repo = line.split("/")
|
name, repo = line.split("/")
|
||||||
if " as " in repo:
|
if " as " in repo:
|
||||||
|
|
30
third_party/nixpkgs/maintainers/team-list.nix
vendored
30
third_party/nixpkgs/maintainers/team-list.nix
vendored
|
@ -29,6 +29,20 @@ with lib.maintainers; {
|
||||||
scope = "Maintain ACME-related packages and modules.";
|
scope = "Maintain ACME-related packages and modules.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bazel = {
|
||||||
|
members = [
|
||||||
|
mboes
|
||||||
|
marsam
|
||||||
|
uri-canva
|
||||||
|
cbley
|
||||||
|
olebedev
|
||||||
|
groodt
|
||||||
|
aherrmann
|
||||||
|
ylecornec
|
||||||
|
];
|
||||||
|
scope = "Bazel build tool & related tools https://bazel.build/";
|
||||||
|
};
|
||||||
|
|
||||||
beam = {
|
beam = {
|
||||||
members = [
|
members = [
|
||||||
ankhers
|
ankhers
|
||||||
|
@ -233,6 +247,15 @@ with lib.maintainers; {
|
||||||
scope = "Maintain Podman and CRI-O related packages and modules.";
|
scope = "Maintain Podman and CRI-O related packages and modules.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
redcodelabs = {
|
||||||
|
members = [
|
||||||
|
unrooted
|
||||||
|
wr0belj
|
||||||
|
wintrmvte
|
||||||
|
];
|
||||||
|
scope = "Maintain Red Code Labs related packages and modules.";
|
||||||
|
};
|
||||||
|
|
||||||
sage = {
|
sage = {
|
||||||
members = [
|
members = [
|
||||||
timokau
|
timokau
|
||||||
|
@ -259,4 +282,11 @@ with lib.maintainers; {
|
||||||
];
|
];
|
||||||
scope = "coqui-ai TTS (formerly Mozilla TTS) and leaf packages";
|
scope = "coqui-ai TTS (formerly Mozilla TTS) and leaf packages";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
xfce = {
|
||||||
|
members = [
|
||||||
|
romildo
|
||||||
|
];
|
||||||
|
scope = "Maintain Xfce desktop environment and related packages.";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ containers.database =
|
||||||
{ config =
|
{ config =
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
{ services.postgresql.enable = true;
|
{ services.postgresql.enable = true;
|
||||||
services.postgresql.package = pkgs.postgresql_9_6;
|
services.postgresql.package = pkgs.postgresql_10;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
|
@ -161,7 +161,7 @@ let
|
||||||
in rec {
|
in rec {
|
||||||
inherit generatedSources;
|
inherit generatedSources;
|
||||||
|
|
||||||
inherit (optionsDoc) optionsJSON optionsXML optionsDocBook;
|
inherit (optionsDoc) optionsJSON optionsDocBook;
|
||||||
|
|
||||||
# Generate the NixOS manual.
|
# Generate the NixOS manual.
|
||||||
manualHTML = runCommand "nixos-manual-html"
|
manualHTML = runCommand "nixos-manual-html"
|
||||||
|
|
|
@ -11,7 +11,7 @@ containers.database =
|
||||||
{ config =
|
{ config =
|
||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
{ services.postgresql.enable = true;
|
{ services.postgresql.enable = true;
|
||||||
services.postgresql.package = pkgs.postgresql_9_6;
|
services.postgresql.package = pkgs.postgresql_10;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
|
|
@ -273,6 +273,13 @@
|
||||||
<link xlink:href="options.html#opt-services.peertube.enable">services.peertube</link>.
|
<link xlink:href="options.html#opt-services.peertube.enable">services.peertube</link>.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<link xlink:href="https://maddy.email">maddy</link>, a
|
||||||
|
composable all-in-one mail server. Available as
|
||||||
|
<link xlink:href="options.html#opt-services.maddy.enable">services.maddy</link>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<link xlink:href="https://sr.ht">sourcehut</link>, a
|
<link xlink:href="https://sr.ht">sourcehut</link>, a
|
||||||
|
|
|
@ -19,8 +19,31 @@
|
||||||
</section>
|
</section>
|
||||||
<section xml:id="sec-release-22.05-new-services">
|
<section xml:id="sec-release-22.05-new-services">
|
||||||
<title>New Services</title>
|
<title>New Services</title>
|
||||||
<para>
|
<itemizedlist>
|
||||||
</para>
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<link xlink:href="https://github.com/intel/linux-sgx#install-the-intelr-sgx-psw">aesmd</link>,
|
||||||
|
the Intel SGX Architectural Enclave Service Manager. Available
|
||||||
|
as
|
||||||
|
<link linkend="opt-services.aesmd.enable">services.aesmd</link>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<link xlink:href="https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-overview.html">filebeat</link>,
|
||||||
|
a lightweight shipper for forwarding and centralizing log
|
||||||
|
data. Available as
|
||||||
|
<link linkend="opt-services.filebeat.enable">services.filebeat</link>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<link xlink:href="https://github.com/ngoduykhanh/PowerDNS-Admin">PowerDNS-Admin</link>,
|
||||||
|
a web interface for the PowerDNS server. Available at
|
||||||
|
<link xlink:href="options.html#opt-services.powerdns-admin.enable">services.powerdns-admin</link>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
<section xml:id="sec-release-22.05-incompatibilities">
|
<section xml:id="sec-release-22.05-incompatibilities">
|
||||||
<title>Backward Incompatibilities</title>
|
<title>Backward Incompatibilities</title>
|
||||||
|
@ -75,11 +98,85 @@
|
||||||
release based on GTK+3 and Python 3.
|
release based on GTK+3 and Python 3.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <literal>writers.writePython2</literal> and corresponding
|
||||||
|
<literal>writers.writePython2Bin</literal> convenience
|
||||||
|
functions to create executable Python 2 scripts in the store
|
||||||
|
were removed in preparation of removal of the Python 2
|
||||||
|
interpreter. Scripts have to be converted to Python 3 for use
|
||||||
|
with <literal>writers.writePython3</literal> or
|
||||||
|
<literal>writers.writePyPy2</literal> needs to be used.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
<section xml:id="sec-release-22.05-notable-changes">
|
<section xml:id="sec-release-22.05-notable-changes">
|
||||||
<title>Other Notable Changes</title>
|
<title>Other Notable Changes</title>
|
||||||
<para>
|
<itemizedlist>
|
||||||
</para>
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The option
|
||||||
|
<link linkend="opt-services.redis.servers">services.redis.servers</link>
|
||||||
|
was added to support per-application
|
||||||
|
<literal>redis-server</literal> which is more secure since
|
||||||
|
Redis databases are only mere key prefixes without any
|
||||||
|
configuration or ACL of their own. Backward-compatibility is
|
||||||
|
preserved by mapping old
|
||||||
|
<literal>services.redis.settings</literal> to
|
||||||
|
<literal>services.redis.servers."".settings</literal>,
|
||||||
|
but you are strongly encouraged to name each
|
||||||
|
<literal>redis-server</literal> instance after the application
|
||||||
|
using it, instead of keeping that nameless one. Except for the
|
||||||
|
nameless
|
||||||
|
<literal>services.redis.servers.""</literal> still
|
||||||
|
accessible at <literal>127.0.0.1:6379</literal>, and to the
|
||||||
|
members of the Unix group <literal>redis</literal> through the
|
||||||
|
Unix socket <literal>/run/redis/redis.sock</literal>, all
|
||||||
|
other <literal>services.redis.servers.${serverName}</literal>
|
||||||
|
are only accessible by default to the members of the Unix
|
||||||
|
group <literal>redis-${serverName}</literal> through the Unix
|
||||||
|
socket <literal>/run/redis-${serverName}/redis.sock</literal>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The
|
||||||
|
<literal>writers.writePyPy2</literal>/<literal>writers.writePyPy3</literal>
|
||||||
|
and corresponding
|
||||||
|
<literal>writers.writePyPy2Bin</literal>/<literal>writers.writePyPy3Bin</literal>
|
||||||
|
convenience functions to create executable Python 2/3 scripts
|
||||||
|
using the PyPy interpreter were added.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <literal>influxdb2</literal> package was split into
|
||||||
|
<literal>influxdb2-server</literal> and
|
||||||
|
<literal>influxdb2-cli</literal>, matching the split that took
|
||||||
|
place upstream. A combined <literal>influxdb2</literal>
|
||||||
|
package is still provided in this release for backwards
|
||||||
|
compatibilty, but will be removed at a later date.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <literal>services.unifi.openPorts</literal> option default
|
||||||
|
value of <literal>true</literal> is now deprecated and will be
|
||||||
|
changed to <literal>false</literal> in 22.11. Configurations
|
||||||
|
using this default will print a warning when rebuilt.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The option
|
||||||
|
<link linkend="opt-services.ssh.enableAskPassword">services.ssh.enableAskPassword</link>
|
||||||
|
was added, decoupling the setting of
|
||||||
|
<literal>SSH_ASKPASS</literal> from
|
||||||
|
<literal>services.xserver.enable</literal>. This allows easy
|
||||||
|
usage in non-X11 environments, e.g. Wayland.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -74,6 +74,8 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||||
|
|
||||||
- [PeerTube](https://joinpeertube.org/), developed by Framasoft, is the free and decentralized alternative to video platforms. Available at [services.peertube](options.html#opt-services.peertube.enable).
|
- [PeerTube](https://joinpeertube.org/), developed by Framasoft, is the free and decentralized alternative to video platforms. Available at [services.peertube](options.html#opt-services.peertube.enable).
|
||||||
|
|
||||||
|
- [maddy](https://maddy.email), a composable all-in-one mail server. Available as [services.maddy](options.html#opt-services.maddy.enable).
|
||||||
|
|
||||||
- [sourcehut](https://sr.ht), a collection of tools useful for software development. Available as [services.sourcehut](options.html#opt-services.sourcehut.enable).
|
- [sourcehut](https://sr.ht), a collection of tools useful for software development. Available as [services.sourcehut](options.html#opt-services.sourcehut.enable).
|
||||||
|
|
||||||
- [ucarp](https://download.pureftpd.org/pub/ucarp/README), an userspace implementation of the Common Address Redundancy Protocol (CARP). Available as [networking.ucarp](options.html#opt-networking.ucarp.enable).
|
- [ucarp](https://download.pureftpd.org/pub/ucarp/README), an userspace implementation of the Common Address Redundancy Protocol (CARP). Available as [networking.ucarp](options.html#opt-networking.ucarp.enable).
|
||||||
|
|
|
@ -8,6 +8,12 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||||
|
|
||||||
## New Services {#sec-release-22.05-new-services}
|
## New Services {#sec-release-22.05-new-services}
|
||||||
|
|
||||||
|
- [aesmd](https://github.com/intel/linux-sgx#install-the-intelr-sgx-psw), the Intel SGX Architectural Enclave Service Manager. Available as [services.aesmd](#opt-services.aesmd.enable).
|
||||||
|
|
||||||
|
- [filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-overview.html), a lightweight shipper for forwarding and centralizing log data. Available as [services.filebeat](#opt-services.filebeat.enable).
|
||||||
|
|
||||||
|
- [PowerDNS-Admin](https://github.com/ngoduykhanh/PowerDNS-Admin), a web interface for the PowerDNS server. Available at [services.powerdns-admin](options.html#opt-services.powerdns-admin.enable).
|
||||||
|
|
||||||
## Backward Incompatibilities {#sec-release-22.05-incompatibilities}
|
## Backward Incompatibilities {#sec-release-22.05-incompatibilities}
|
||||||
|
|
||||||
- `pkgs.ghc` now refers to `pkgs.targetPackages.haskellPackages.ghc`.
|
- `pkgs.ghc` now refers to `pkgs.targetPackages.haskellPackages.ghc`.
|
||||||
|
@ -32,4 +38,39 @@ In addition to numerous new and upgraded packages, this release has the followin
|
||||||
- `pkgs.claws-mail-gtk2`, representing Claws Mail's older release version three, was removed in order to get rid of Python 2.
|
- `pkgs.claws-mail-gtk2`, representing Claws Mail's older release version three, was removed in order to get rid of Python 2.
|
||||||
Please switch to `claws-mail`, which is Claws Mail's latest release based on GTK+3 and Python 3.
|
Please switch to `claws-mail`, which is Claws Mail's latest release based on GTK+3 and Python 3.
|
||||||
|
|
||||||
|
- The `writers.writePython2` and corresponding `writers.writePython2Bin` convenience functions to create executable Python 2 scripts in the store were removed in preparation of removal of the Python 2 interpreter.
|
||||||
|
Scripts have to be converted to Python 3 for use with `writers.writePython3` or `writers.writePyPy2` needs to be used.
|
||||||
|
|
||||||
## Other Notable Changes {#sec-release-22.05-notable-changes}
|
## Other Notable Changes {#sec-release-22.05-notable-changes}
|
||||||
|
|
||||||
|
- The option [services.redis.servers](#opt-services.redis.servers) was added
|
||||||
|
to support per-application `redis-server` which is more secure since Redis databases
|
||||||
|
are only mere key prefixes without any configuration or ACL of their own.
|
||||||
|
Backward-compatibility is preserved by mapping old `services.redis.settings`
|
||||||
|
to `services.redis.servers."".settings`, but you are strongly encouraged
|
||||||
|
to name each `redis-server` instance after the application using it,
|
||||||
|
instead of keeping that nameless one.
|
||||||
|
Except for the nameless `services.redis.servers.""`
|
||||||
|
still accessible at `127.0.0.1:6379`,
|
||||||
|
and to the members of the Unix group `redis`
|
||||||
|
through the Unix socket `/run/redis/redis.sock`,
|
||||||
|
all other `services.redis.servers.${serverName}`
|
||||||
|
are only accessible by default
|
||||||
|
to the members of the Unix group `redis-${serverName}`
|
||||||
|
through the Unix socket `/run/redis-${serverName}/redis.sock`.
|
||||||
|
|
||||||
|
- The `writers.writePyPy2`/`writers.writePyPy3` and corresponding `writers.writePyPy2Bin`/`writers.writePyPy3Bin` convenience functions to create executable Python 2/3 scripts using the PyPy interpreter were added.
|
||||||
|
|
||||||
|
- The `influxdb2` package was split into `influxdb2-server` and
|
||||||
|
`influxdb2-cli`, matching the split that took place upstream. A
|
||||||
|
combined `influxdb2` package is still provided in this release for
|
||||||
|
backwards compatibilty, but will be removed at a later date.
|
||||||
|
|
||||||
|
- The `services.unifi.openPorts` option default value of `true` is now deprecated and will be changed to `false` in 22.11.
|
||||||
|
Configurations using this default will print a warning when rebuilt.
|
||||||
|
|
||||||
|
- The option
|
||||||
|
[services.ssh.enableAskPassword](#opt-services.ssh.enableAskPassword) was
|
||||||
|
added, decoupling the setting of `SSH_ASKPASS` from
|
||||||
|
`services.xserver.enable`. This allows easy usage in non-X11 environments,
|
||||||
|
e.g. Wayland.
|
||||||
|
|
50
third_party/nixpkgs/nixos/lib/eval-config.nix
vendored
50
third_party/nixpkgs/nixos/lib/eval-config.nix
vendored
|
@ -8,6 +8,7 @@
|
||||||
# as subcomponents (e.g. the container feature, or nixops if network
|
# as subcomponents (e.g. the container feature, or nixops if network
|
||||||
# expressions are ever made modular at the top level) can just use
|
# expressions are ever made modular at the top level) can just use
|
||||||
# types.submodule instead of using eval-config.nix
|
# types.submodule instead of using eval-config.nix
|
||||||
|
evalConfigArgs@
|
||||||
{ # !!! system can be set modularly, would be nice to remove
|
{ # !!! system can be set modularly, would be nice to remove
|
||||||
system ? builtins.currentSystem
|
system ? builtins.currentSystem
|
||||||
, # !!! is this argument needed any more? The pkgs argument can
|
, # !!! is this argument needed any more? The pkgs argument can
|
||||||
|
@ -28,7 +29,7 @@
|
||||||
in if e == "" then [] else [(import e)]
|
in if e == "" then [] else [(import e)]
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let extraArgs_ = extraArgs; pkgs_ = pkgs;
|
let pkgs_ = pkgs;
|
||||||
in
|
in
|
||||||
|
|
||||||
let
|
let
|
||||||
|
@ -51,28 +52,49 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
noUserModules = lib.evalModules {
|
withWarnings = x:
|
||||||
inherit prefix check;
|
lib.warnIf (evalConfigArgs?extraArgs) "The extraArgs argument to eval-config.nix is deprecated. Please set config._module.args instead."
|
||||||
modules = baseModules ++ extraModules ++ [ pkgsModule ];
|
lib.warnIf (evalConfigArgs?check) "The check argument to eval-config.nix is deprecated. Please set config._module.check instead."
|
||||||
args = extraArgs;
|
x;
|
||||||
|
|
||||||
|
legacyModules =
|
||||||
|
lib.optional (evalConfigArgs?extraArgs) {
|
||||||
|
config = {
|
||||||
|
_module.args = extraArgs;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
++ lib.optional (evalConfigArgs?check) {
|
||||||
|
config = {
|
||||||
|
_module.check = lib.mkDefault check;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
allUserModules = modules ++ legacyModules;
|
||||||
|
|
||||||
|
noUserModules = lib.evalModules ({
|
||||||
|
inherit prefix;
|
||||||
|
modules = baseModules ++ extraModules ++ [ pkgsModule modulesModule ];
|
||||||
specialArgs =
|
specialArgs =
|
||||||
{ modulesPath = builtins.toString ../modules; } // specialArgs;
|
{ modulesPath = builtins.toString ../modules; } // specialArgs;
|
||||||
|
});
|
||||||
|
|
||||||
|
# Extra arguments that are useful for constructing a similar configuration.
|
||||||
|
modulesModule = {
|
||||||
|
config = {
|
||||||
|
_module.args = {
|
||||||
|
inherit noUserModules baseModules extraModules modules;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# These are the extra arguments passed to every module. In
|
nixosWithUserModules = noUserModules.extendModules { modules = allUserModules; };
|
||||||
# particular, Nixpkgs is passed through the "pkgs" argument.
|
|
||||||
extraArgs = extraArgs_ // {
|
|
||||||
inherit noUserModules baseModules extraModules modules;
|
|
||||||
};
|
|
||||||
|
|
||||||
in rec {
|
in withWarnings {
|
||||||
|
|
||||||
# Merge the option definitions in all modules, forming the full
|
# Merge the option definitions in all modules, forming the full
|
||||||
# system configuration.
|
# system configuration.
|
||||||
inherit (noUserModules.extendModules { inherit modules; })
|
inherit (nixosWithUserModules) config options _module type;
|
||||||
config options _module type;
|
|
||||||
|
|
||||||
inherit extraArgs;
|
inherit extraArgs;
|
||||||
|
|
||||||
inherit (_module.args) pkgs;
|
inherit (nixosWithUserModules._module.args) pkgs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,18 +24,25 @@
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
# Replace functions by the string <function>
|
# Make a value safe for JSON. Functions are replaced by the string "<function>",
|
||||||
substFunction = x:
|
# derivations are replaced with an attrset
|
||||||
if builtins.isAttrs x then lib.mapAttrs (name: substFunction) x
|
# { _type = "derivation"; name = <name of that derivation>; }.
|
||||||
else if builtins.isList x then map substFunction x
|
# We need to handle derivations specially because consumers want to know about them,
|
||||||
|
# but we can't easily use the type,name subset of keys (since type is often used as
|
||||||
|
# a module option and might cause confusion). Use _type,name instead to the same
|
||||||
|
# effect, since _type is already used by the module system.
|
||||||
|
substSpecial = x:
|
||||||
|
if lib.isDerivation x then { _type = "derivation"; name = x.name; }
|
||||||
|
else if builtins.isAttrs x then lib.mapAttrs (name: substSpecial) x
|
||||||
|
else if builtins.isList x then map substSpecial x
|
||||||
else if lib.isFunction x then "<function>"
|
else if lib.isFunction x then "<function>"
|
||||||
else x;
|
else x;
|
||||||
|
|
||||||
optionsListDesc = lib.flip map optionsListVisible
|
optionsList = lib.flip map optionsListVisible
|
||||||
(opt: transformOptions opt
|
(opt: transformOptions opt
|
||||||
// lib.optionalAttrs (opt ? example) { example = substFunction opt.example; }
|
// lib.optionalAttrs (opt ? example) { example = substSpecial opt.example; }
|
||||||
// lib.optionalAttrs (opt ? default) { default = substFunction opt.default; }
|
// lib.optionalAttrs (opt ? default) { default = substSpecial opt.default; }
|
||||||
// lib.optionalAttrs (opt ? type) { type = substFunction opt.type; }
|
// lib.optionalAttrs (opt ? type) { type = substSpecial opt.type; }
|
||||||
// lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages opt.name; }
|
// lib.optionalAttrs (opt ? relatedPackages && opt.relatedPackages != []) { relatedPackages = genRelatedPackages opt.relatedPackages opt.name; }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -69,96 +76,25 @@ let
|
||||||
+ "</listitem>";
|
+ "</listitem>";
|
||||||
in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>";
|
in "<itemizedlist>${lib.concatStringsSep "\n" (map (p: describe (unpack p)) packages)}</itemizedlist>";
|
||||||
|
|
||||||
# Custom "less" that pushes up all the things ending in ".enable*"
|
|
||||||
# and ".package*"
|
|
||||||
optionLess = a: b:
|
|
||||||
let
|
|
||||||
ise = lib.hasPrefix "enable";
|
|
||||||
isp = lib.hasPrefix "package";
|
|
||||||
cmp = lib.splitByAndCompare ise lib.compare
|
|
||||||
(lib.splitByAndCompare isp lib.compare lib.compare);
|
|
||||||
in lib.compareLists cmp a.loc b.loc < 0;
|
|
||||||
|
|
||||||
# Remove invisible and internal options.
|
# Remove invisible and internal options.
|
||||||
optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options);
|
optionsListVisible = lib.filter (opt: opt.visible && !opt.internal) (lib.optionAttrSetToDocList options);
|
||||||
|
|
||||||
# Customly sort option list for the man page.
|
|
||||||
# Always ensure that the sort order matches sortXML.py!
|
|
||||||
optionsList = lib.sort optionLess optionsListDesc;
|
|
||||||
|
|
||||||
# Convert the list of options into an XML file.
|
|
||||||
# This file is *not* sorted sorted to save on eval time, since the docbook XML
|
|
||||||
# and the manpage depend on it and thus we evaluate this on every system rebuild.
|
|
||||||
optionsXML = builtins.toFile "options.xml" (builtins.toXML optionsListDesc);
|
|
||||||
|
|
||||||
optionsNix = builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList);
|
optionsNix = builtins.listToAttrs (map (o: { name = o.name; value = removeAttrs o ["name" "visible" "internal"]; }) optionsList);
|
||||||
|
|
||||||
# TODO: declarations: link to github
|
in rec {
|
||||||
singleAsciiDoc = name: value: ''
|
|
||||||
== ${name}
|
|
||||||
|
|
||||||
${value.description}
|
|
||||||
|
|
||||||
[discrete]
|
|
||||||
=== details
|
|
||||||
|
|
||||||
Type:: ${value.type}
|
|
||||||
${ if lib.hasAttr "default" value
|
|
||||||
then ''
|
|
||||||
Default::
|
|
||||||
+
|
|
||||||
----
|
|
||||||
${builtins.toJSON value.default}
|
|
||||||
----
|
|
||||||
''
|
|
||||||
else "No Default:: {blank}"
|
|
||||||
}
|
|
||||||
${ if value.readOnly
|
|
||||||
then "Read Only:: {blank}"
|
|
||||||
else ""
|
|
||||||
}
|
|
||||||
${ if lib.hasAttr "example" value
|
|
||||||
then ''
|
|
||||||
Example::
|
|
||||||
+
|
|
||||||
----
|
|
||||||
${builtins.toJSON value.example}
|
|
||||||
----
|
|
||||||
''
|
|
||||||
else "No Example:: {blank}"
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
|
|
||||||
singleMDDoc = name: value: ''
|
|
||||||
## ${lib.escape [ "<" ">" ] name}
|
|
||||||
${value.description}
|
|
||||||
|
|
||||||
${lib.optionalString (value ? type) ''
|
|
||||||
*_Type_*:
|
|
||||||
${value.type}
|
|
||||||
''}
|
|
||||||
|
|
||||||
${lib.optionalString (value ? default) ''
|
|
||||||
*_Default_*
|
|
||||||
```
|
|
||||||
${builtins.toJSON value.default}
|
|
||||||
```
|
|
||||||
''}
|
|
||||||
|
|
||||||
${lib.optionalString (value ? example) ''
|
|
||||||
*_Example_*
|
|
||||||
```
|
|
||||||
${builtins.toJSON value.example}
|
|
||||||
```
|
|
||||||
''}
|
|
||||||
'';
|
|
||||||
|
|
||||||
in {
|
|
||||||
inherit optionsNix;
|
inherit optionsNix;
|
||||||
|
|
||||||
optionsAsciiDoc = lib.concatStringsSep "\n" (lib.mapAttrsToList singleAsciiDoc optionsNix);
|
optionsAsciiDoc = pkgs.runCommand "options.adoc" {} ''
|
||||||
|
${pkgs.python3Minimal}/bin/python ${./generateAsciiDoc.py} \
|
||||||
|
< ${optionsJSON}/share/doc/nixos/options.json \
|
||||||
|
> $out
|
||||||
|
'';
|
||||||
|
|
||||||
optionsMDDoc = lib.concatStringsSep "\n" (lib.mapAttrsToList singleMDDoc optionsNix);
|
optionsCommonMark = pkgs.runCommand "options.md" {} ''
|
||||||
|
${pkgs.python3Minimal}/bin/python ${./generateCommonMark.py} \
|
||||||
|
< ${optionsJSON}/share/doc/nixos/options.json \
|
||||||
|
> $out
|
||||||
|
'';
|
||||||
|
|
||||||
optionsJSON = pkgs.runCommand "options.json"
|
optionsJSON = pkgs.runCommand "options.json"
|
||||||
{ meta.description = "List of NixOS options in JSON format";
|
{ meta.description = "List of NixOS options in JSON format";
|
||||||
|
@ -176,7 +112,19 @@ in {
|
||||||
mkdir -p $out/nix-support
|
mkdir -p $out/nix-support
|
||||||
echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products
|
echo "file json $dst/options.json" >> $out/nix-support/hydra-build-products
|
||||||
echo "file json-br $dst/options.json.br" >> $out/nix-support/hydra-build-products
|
echo "file json-br $dst/options.json.br" >> $out/nix-support/hydra-build-products
|
||||||
''; # */
|
'';
|
||||||
|
|
||||||
|
# Convert options.json into an XML file.
|
||||||
|
# The actual generation of the xml file is done in nix purely for the convenience
|
||||||
|
# of not having to generate the xml some other way
|
||||||
|
optionsXML = pkgs.runCommand "options.xml" {} ''
|
||||||
|
export NIX_STORE_DIR=$TMPDIR/store
|
||||||
|
export NIX_STATE_DIR=$TMPDIR/state
|
||||||
|
${pkgs.nix}/bin/nix-instantiate \
|
||||||
|
--eval --xml --strict ${./optionsJSONtoXML.nix} \
|
||||||
|
--argstr file ${optionsJSON}/share/doc/nixos/options.json \
|
||||||
|
> "$out"
|
||||||
|
'';
|
||||||
|
|
||||||
optionsDocBook = pkgs.runCommand "options-docbook.xml" {} ''
|
optionsDocBook = pkgs.runCommand "options-docbook.xml" {} ''
|
||||||
optionsXML=${optionsXML}
|
optionsXML=${optionsXML}
|
||||||
|
|
37
third_party/nixpkgs/nixos/lib/make-options-doc/generateAsciiDoc.py
vendored
Normal file
37
third_party/nixpkgs/nixos/lib/make-options-doc/generateAsciiDoc.py
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
options = json.load(sys.stdin)
|
||||||
|
# TODO: declarations: link to github
|
||||||
|
for (name, value) in options.items():
|
||||||
|
print(f'== {name}')
|
||||||
|
print()
|
||||||
|
print(value['description'])
|
||||||
|
print()
|
||||||
|
print('[discrete]')
|
||||||
|
print('=== details')
|
||||||
|
print()
|
||||||
|
print(f'Type:: {value["type"]}')
|
||||||
|
if 'default' in value:
|
||||||
|
print('Default::')
|
||||||
|
print('+')
|
||||||
|
print('----')
|
||||||
|
print(json.dumps(value['default'], ensure_ascii=False, separators=(',', ':')))
|
||||||
|
print('----')
|
||||||
|
print()
|
||||||
|
else:
|
||||||
|
print('No Default:: {blank}')
|
||||||
|
if value['readOnly']:
|
||||||
|
print('Read Only:: {blank}')
|
||||||
|
else:
|
||||||
|
print()
|
||||||
|
if 'example' in value:
|
||||||
|
print('Example::')
|
||||||
|
print('+')
|
||||||
|
print('----')
|
||||||
|
print(json.dumps(value['example'], ensure_ascii=False, separators=(',', ':')))
|
||||||
|
print('----')
|
||||||
|
print()
|
||||||
|
else:
|
||||||
|
print('No Example:: {blank}')
|
||||||
|
print()
|
27
third_party/nixpkgs/nixos/lib/make-options-doc/generateCommonMark.py
vendored
Normal file
27
third_party/nixpkgs/nixos/lib/make-options-doc/generateCommonMark.py
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
options = json.load(sys.stdin)
|
||||||
|
for (name, value) in options.items():
|
||||||
|
print('##', name.replace('<', '\\<').replace('>', '\\>'))
|
||||||
|
print(value['description'])
|
||||||
|
print()
|
||||||
|
if 'type' in value:
|
||||||
|
print('*_Type_*:')
|
||||||
|
print(value['type'])
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
if 'default' in value:
|
||||||
|
print('*_Default_*')
|
||||||
|
print('```')
|
||||||
|
print(json.dumps(value['default'], ensure_ascii=False, separators=(',', ':')))
|
||||||
|
print('```')
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
if 'example' in value:
|
||||||
|
print('*_Example_*')
|
||||||
|
print('```')
|
||||||
|
print(json.dumps(value['example'], ensure_ascii=False, separators=(',', ':')))
|
||||||
|
print('```')
|
||||||
|
print()
|
||||||
|
print()
|
|
@ -189,7 +189,7 @@
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
|
|
||||||
<xsl:template match="derivation">
|
<xsl:template match="attrs[attr[@name = '_type' and string[@value = 'derivation']]]">
|
||||||
<replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
|
<replaceable>(build of <xsl:value-of select="attr[@name = 'name']/string/@value" />)</replaceable>
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
|
|
6
third_party/nixpkgs/nixos/lib/make-options-doc/optionsJSONtoXML.nix
vendored
Normal file
6
third_party/nixpkgs/nixos/lib/make-options-doc/optionsJSONtoXML.nix
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{ file }:
|
||||||
|
|
||||||
|
builtins.attrValues
|
||||||
|
(builtins.mapAttrs
|
||||||
|
(name: def: def // { inherit name; })
|
||||||
|
(builtins.fromJSON (builtins.readFile file)))
|
|
@ -19,7 +19,6 @@ def sortKey(opt):
|
||||||
for p in opt.findall('attr[@name="loc"]/list/string')
|
for p in opt.findall('attr[@name="loc"]/list/string')
|
||||||
]
|
]
|
||||||
|
|
||||||
# always ensure that the sort order matches the order used in the nix expression!
|
|
||||||
options.sort(key=sortKey)
|
options.sort(key=sortKey)
|
||||||
|
|
||||||
doc = ET.Element("expr")
|
doc = ET.Element("expr")
|
||||||
|
|
|
@ -21,8 +21,15 @@ stdenv.mkDerivation {
|
||||||
# for nix-store --load-db.
|
# for nix-store --load-db.
|
||||||
cp $closureInfo/registration nix-path-registration
|
cp $closureInfo/registration nix-path-registration
|
||||||
|
|
||||||
|
# 64 cores on i686 does not work
|
||||||
|
# fails with FATAL ERROR: mangle2:: xz compress failed with error code 5
|
||||||
|
if ((NIX_BUILD_CORES > 48)); then
|
||||||
|
NIX_BUILD_CORES=48
|
||||||
|
fi
|
||||||
|
|
||||||
# Generate the squashfs image.
|
# Generate the squashfs image.
|
||||||
mksquashfs nix-path-registration $(cat $closureInfo/store-paths) $out \
|
mksquashfs nix-path-registration $(cat $closureInfo/store-paths) $out \
|
||||||
-no-hardlinks -keep-as-directory -all-root -b 1048576 -comp ${comp}
|
-no-hardlinks -keep-as-directory -all-root -b 1048576 -comp ${comp} \
|
||||||
|
-processors $NIX_BUILD_CORES
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ config, lib }:
|
{ lib, systemdUtils }:
|
||||||
|
|
||||||
|
with systemdUtils.lib;
|
||||||
with lib;
|
with lib;
|
||||||
with import ./systemd-lib.nix { inherit config lib pkgs; };
|
|
||||||
|
|
||||||
let
|
let
|
||||||
checkService = checkUnitConfig "Service" [
|
checkService = checkUnitConfig "Service" [
|
32
third_party/nixpkgs/nixos/lib/test-driver/default.nix
vendored
Normal file
32
third_party/nixpkgs/nixos/lib/test-driver/default.nix
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{ lib
|
||||||
|
, python3Packages
|
||||||
|
, enableOCR ? false
|
||||||
|
, qemu_pkg ? qemu_test
|
||||||
|
, coreutils
|
||||||
|
, imagemagick_light
|
||||||
|
, libtiff
|
||||||
|
, netpbm
|
||||||
|
, qemu_test
|
||||||
|
, socat
|
||||||
|
, tesseract4
|
||||||
|
, vde2
|
||||||
|
}:
|
||||||
|
|
||||||
|
python3Packages.buildPythonApplication rec {
|
||||||
|
pname = "nixos-test-driver";
|
||||||
|
version = "1.0";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
propagatedBuildInputs = [ coreutils netpbm python3Packages.colorama python3Packages.ptpython qemu_pkg socat vde2 ]
|
||||||
|
++ (lib.optionals enableOCR [ imagemagick_light tesseract4 ]);
|
||||||
|
|
||||||
|
doCheck = true;
|
||||||
|
checkInputs = with python3Packages; [ mypy pylint black ];
|
||||||
|
checkPhase = ''
|
||||||
|
mypy --disallow-untyped-defs \
|
||||||
|
--no-implicit-optional \
|
||||||
|
--ignore-missing-imports ${src}/test_driver
|
||||||
|
pylint --errors-only ${src}/test_driver
|
||||||
|
black --check --diff ${src}/test_driver
|
||||||
|
'';
|
||||||
|
}
|
13
third_party/nixpkgs/nixos/lib/test-driver/setup.py
vendored
Normal file
13
third_party/nixpkgs/nixos/lib/test-driver/setup.py
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="nixos-test-driver",
|
||||||
|
version='1.0',
|
||||||
|
packages=find_packages(),
|
||||||
|
entry_points={
|
||||||
|
"console_scripts": [
|
||||||
|
"nixos-test-driver=test_driver:main",
|
||||||
|
"generate-driver-symbols=test_driver:generate_driver_symbols"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
100
third_party/nixpkgs/nixos/lib/test-driver/test_driver/__init__.py
vendored
Executable file
100
third_party/nixpkgs/nixos/lib/test-driver/test_driver/__init__.py
vendored
Executable file
|
@ -0,0 +1,100 @@
|
||||||
|
from pathlib import Path
|
||||||
|
import argparse
|
||||||
|
import ptpython.repl
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
from test_driver.logger import rootlog
|
||||||
|
from test_driver.driver import Driver
|
||||||
|
|
||||||
|
|
||||||
|
class EnvDefault(argparse.Action):
|
||||||
|
"""An argpars Action that takes values from the specified
|
||||||
|
environment variable as the flags default value.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, envvar, required=False, default=None, nargs=None, **kwargs): # type: ignore
|
||||||
|
if not default and envvar:
|
||||||
|
if envvar in os.environ:
|
||||||
|
if nargs is not None and (nargs.isdigit() or nargs in ["*", "+"]):
|
||||||
|
default = os.environ[envvar].split()
|
||||||
|
else:
|
||||||
|
default = os.environ[envvar]
|
||||||
|
kwargs["help"] = (
|
||||||
|
kwargs["help"] + f" (default from environment: {default})"
|
||||||
|
)
|
||||||
|
if required and default:
|
||||||
|
required = False
|
||||||
|
super(EnvDefault, self).__init__(
|
||||||
|
default=default, required=required, nargs=nargs, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None): # type: ignore
|
||||||
|
setattr(namespace, self.dest, values)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
arg_parser = argparse.ArgumentParser(prog="nixos-test-driver")
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"-K",
|
||||||
|
"--keep-vm-state",
|
||||||
|
help="re-use a VM state coming from a previous run",
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"-I",
|
||||||
|
"--interactive",
|
||||||
|
help="drop into a python repl and run the tests interactively",
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"--start-scripts",
|
||||||
|
metavar="START-SCRIPT",
|
||||||
|
action=EnvDefault,
|
||||||
|
envvar="startScripts",
|
||||||
|
nargs="*",
|
||||||
|
help="start scripts for participating virtual machines",
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"--vlans",
|
||||||
|
metavar="VLAN",
|
||||||
|
action=EnvDefault,
|
||||||
|
envvar="vlans",
|
||||||
|
nargs="*",
|
||||||
|
help="vlans to span by the driver",
|
||||||
|
)
|
||||||
|
arg_parser.add_argument(
|
||||||
|
"testscript",
|
||||||
|
action=EnvDefault,
|
||||||
|
envvar="testScript",
|
||||||
|
help="the test script to run",
|
||||||
|
type=Path,
|
||||||
|
)
|
||||||
|
|
||||||
|
args = arg_parser.parse_args()
|
||||||
|
|
||||||
|
if not args.keep_vm_state:
|
||||||
|
rootlog.info("Machine state will be reset. To keep it, pass --keep-vm-state")
|
||||||
|
|
||||||
|
with Driver(
|
||||||
|
args.start_scripts, args.vlans, args.testscript.read_text(), args.keep_vm_state
|
||||||
|
) as driver:
|
||||||
|
if args.interactive:
|
||||||
|
ptpython.repl.embed(driver.test_symbols(), {})
|
||||||
|
else:
|
||||||
|
tic = time.time()
|
||||||
|
driver.run_tests()
|
||||||
|
toc = time.time()
|
||||||
|
rootlog.info(f"test script finished in {(toc-tic):.2f}s")
|
||||||
|
|
||||||
|
|
||||||
|
def generate_driver_symbols() -> None:
|
||||||
|
"""
|
||||||
|
This generates a file with symbols of the test-driver code that can be used
|
||||||
|
in user's test scripts. That list is then used by pyflakes to lint those
|
||||||
|
scripts.
|
||||||
|
"""
|
||||||
|
d = Driver([], [], "")
|
||||||
|
test_symbols = d.test_symbols()
|
||||||
|
with open("driver-symbols", "w") as fp:
|
||||||
|
fp.write(",".join(test_symbols.keys()))
|
161
third_party/nixpkgs/nixos/lib/test-driver/test_driver/driver.py
vendored
Normal file
161
third_party/nixpkgs/nixos/lib/test-driver/test_driver/driver.py
vendored
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
from contextlib import contextmanager
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, Iterator, List
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from test_driver.logger import rootlog
|
||||||
|
from test_driver.machine import Machine, NixStartScript, retry
|
||||||
|
from test_driver.vlan import VLan
|
||||||
|
|
||||||
|
|
||||||
|
class Driver:
|
||||||
|
"""A handle to the driver that sets up the environment
|
||||||
|
and runs the tests"""
|
||||||
|
|
||||||
|
tests: str
|
||||||
|
vlans: List[VLan]
|
||||||
|
machines: List[Machine]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
start_scripts: List[str],
|
||||||
|
vlans: List[int],
|
||||||
|
tests: str,
|
||||||
|
keep_vm_state: bool = False,
|
||||||
|
):
|
||||||
|
self.tests = tests
|
||||||
|
|
||||||
|
tmp_dir = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
|
||||||
|
tmp_dir.mkdir(mode=0o700, exist_ok=True)
|
||||||
|
|
||||||
|
with rootlog.nested("start all VLans"):
|
||||||
|
self.vlans = [VLan(nr, tmp_dir) for nr in vlans]
|
||||||
|
|
||||||
|
def cmd(scripts: List[str]) -> Iterator[NixStartScript]:
|
||||||
|
for s in scripts:
|
||||||
|
yield NixStartScript(s)
|
||||||
|
|
||||||
|
self.machines = [
|
||||||
|
Machine(
|
||||||
|
start_command=cmd,
|
||||||
|
keep_vm_state=keep_vm_state,
|
||||||
|
name=cmd.machine_name,
|
||||||
|
tmp_dir=tmp_dir,
|
||||||
|
)
|
||||||
|
for cmd in cmd(start_scripts)
|
||||||
|
]
|
||||||
|
|
||||||
|
def __enter__(self) -> "Driver":
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, *_: Any) -> None:
|
||||||
|
with rootlog.nested("cleanup"):
|
||||||
|
for machine in self.machines:
|
||||||
|
machine.release()
|
||||||
|
|
||||||
|
def subtest(self, name: str) -> Iterator[None]:
|
||||||
|
"""Group logs under a given test name"""
|
||||||
|
with rootlog.nested(name):
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
rootlog.error(f'Test "{name}" failed with error: "{e}"')
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def test_symbols(self) -> Dict[str, Any]:
|
||||||
|
@contextmanager
|
||||||
|
def subtest(name: str) -> Iterator[None]:
|
||||||
|
return self.subtest(name)
|
||||||
|
|
||||||
|
general_symbols = dict(
|
||||||
|
start_all=self.start_all,
|
||||||
|
test_script=self.test_script,
|
||||||
|
machines=self.machines,
|
||||||
|
vlans=self.vlans,
|
||||||
|
driver=self,
|
||||||
|
log=rootlog,
|
||||||
|
os=os,
|
||||||
|
create_machine=self.create_machine,
|
||||||
|
subtest=subtest,
|
||||||
|
run_tests=self.run_tests,
|
||||||
|
join_all=self.join_all,
|
||||||
|
retry=retry,
|
||||||
|
serial_stdout_off=self.serial_stdout_off,
|
||||||
|
serial_stdout_on=self.serial_stdout_on,
|
||||||
|
Machine=Machine, # for typing
|
||||||
|
)
|
||||||
|
machine_symbols = {m.name: m for m in self.machines}
|
||||||
|
# If there's exactly one machine, make it available under the name
|
||||||
|
# "machine", even if it's not called that.
|
||||||
|
if len(self.machines) == 1:
|
||||||
|
(machine_symbols["machine"],) = self.machines
|
||||||
|
vlan_symbols = {
|
||||||
|
f"vlan{v.nr}": self.vlans[idx] for idx, v in enumerate(self.vlans)
|
||||||
|
}
|
||||||
|
print(
|
||||||
|
"additionally exposed symbols:\n "
|
||||||
|
+ ", ".join(map(lambda m: m.name, self.machines))
|
||||||
|
+ ",\n "
|
||||||
|
+ ", ".join(map(lambda v: f"vlan{v.nr}", self.vlans))
|
||||||
|
+ ",\n "
|
||||||
|
+ ", ".join(list(general_symbols.keys()))
|
||||||
|
)
|
||||||
|
return {**general_symbols, **machine_symbols, **vlan_symbols}
|
||||||
|
|
||||||
|
def test_script(self) -> None:
|
||||||
|
"""Run the test script"""
|
||||||
|
with rootlog.nested("run the VM test script"):
|
||||||
|
symbols = self.test_symbols() # call eagerly
|
||||||
|
exec(self.tests, symbols, None)
|
||||||
|
|
||||||
|
def run_tests(self) -> None:
|
||||||
|
"""Run the test script (for non-interactive test runs)"""
|
||||||
|
self.test_script()
|
||||||
|
# TODO: Collect coverage data
|
||||||
|
for machine in self.machines:
|
||||||
|
if machine.is_up():
|
||||||
|
machine.execute("sync")
|
||||||
|
|
||||||
|
def start_all(self) -> None:
|
||||||
|
"""Start all machines"""
|
||||||
|
with rootlog.nested("start all VMs"):
|
||||||
|
for machine in self.machines:
|
||||||
|
machine.start()
|
||||||
|
|
||||||
|
def join_all(self) -> None:
|
||||||
|
"""Wait for all machines to shut down"""
|
||||||
|
with rootlog.nested("wait for all VMs to finish"):
|
||||||
|
for machine in self.machines:
|
||||||
|
machine.wait_for_shutdown()
|
||||||
|
|
||||||
|
def create_machine(self, args: Dict[str, Any]) -> Machine:
|
||||||
|
rootlog.warning(
|
||||||
|
"Using legacy create_machine(), please instantiate the"
|
||||||
|
"Machine class directly, instead"
|
||||||
|
)
|
||||||
|
tmp_dir = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
|
||||||
|
tmp_dir.mkdir(mode=0o700, exist_ok=True)
|
||||||
|
|
||||||
|
if args.get("startCommand"):
|
||||||
|
start_command: str = args.get("startCommand", "")
|
||||||
|
cmd = NixStartScript(start_command)
|
||||||
|
name = args.get("name", cmd.machine_name)
|
||||||
|
else:
|
||||||
|
cmd = Machine.create_startcommand(args) # type: ignore
|
||||||
|
name = args.get("name", "machine")
|
||||||
|
|
||||||
|
return Machine(
|
||||||
|
tmp_dir=tmp_dir,
|
||||||
|
start_command=cmd,
|
||||||
|
name=name,
|
||||||
|
keep_vm_state=args.get("keep_vm_state", False),
|
||||||
|
allow_reboot=args.get("allow_reboot", False),
|
||||||
|
)
|
||||||
|
|
||||||
|
def serial_stdout_on(self) -> None:
|
||||||
|
rootlog._print_serial_logs = True
|
||||||
|
|
||||||
|
def serial_stdout_off(self) -> None:
|
||||||
|
rootlog._print_serial_logs = False
|
101
third_party/nixpkgs/nixos/lib/test-driver/test_driver/logger.py
vendored
Normal file
101
third_party/nixpkgs/nixos/lib/test-driver/test_driver/logger.py
vendored
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
from colorama import Style
|
||||||
|
from contextlib import contextmanager
|
||||||
|
from typing import Any, Dict, Iterator
|
||||||
|
from queue import Queue, Empty
|
||||||
|
from xml.sax.saxutils import XMLGenerator
|
||||||
|
import codecs
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import unicodedata
|
||||||
|
|
||||||
|
|
||||||
|
class Logger:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.logfile = os.environ.get("LOGFILE", "/dev/null")
|
||||||
|
self.logfile_handle = codecs.open(self.logfile, "wb")
|
||||||
|
self.xml = XMLGenerator(self.logfile_handle, encoding="utf-8")
|
||||||
|
self.queue: "Queue[Dict[str, str]]" = Queue()
|
||||||
|
|
||||||
|
self.xml.startDocument()
|
||||||
|
self.xml.startElement("logfile", attrs={})
|
||||||
|
|
||||||
|
self._print_serial_logs = True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _eprint(*args: object, **kwargs: Any) -> None:
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
def close(self) -> None:
|
||||||
|
self.xml.endElement("logfile")
|
||||||
|
self.xml.endDocument()
|
||||||
|
self.logfile_handle.close()
|
||||||
|
|
||||||
|
def sanitise(self, message: str) -> str:
|
||||||
|
return "".join(ch for ch in message if unicodedata.category(ch)[0] != "C")
|
||||||
|
|
||||||
|
def maybe_prefix(self, message: str, attributes: Dict[str, str]) -> str:
|
||||||
|
if "machine" in attributes:
|
||||||
|
return "{}: {}".format(attributes["machine"], message)
|
||||||
|
return message
|
||||||
|
|
||||||
|
def log_line(self, message: str, attributes: Dict[str, str]) -> None:
|
||||||
|
self.xml.startElement("line", attributes)
|
||||||
|
self.xml.characters(message)
|
||||||
|
self.xml.endElement("line")
|
||||||
|
|
||||||
|
def info(self, *args, **kwargs) -> None: # type: ignore
|
||||||
|
self.log(*args, **kwargs)
|
||||||
|
|
||||||
|
def warning(self, *args, **kwargs) -> None: # type: ignore
|
||||||
|
self.log(*args, **kwargs)
|
||||||
|
|
||||||
|
def error(self, *args, **kwargs) -> None: # type: ignore
|
||||||
|
self.log(*args, **kwargs)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def log(self, message: str, attributes: Dict[str, str] = {}) -> None:
|
||||||
|
self._eprint(self.maybe_prefix(message, attributes))
|
||||||
|
self.drain_log_queue()
|
||||||
|
self.log_line(message, attributes)
|
||||||
|
|
||||||
|
def log_serial(self, message: str, machine: str) -> None:
|
||||||
|
self.enqueue({"msg": message, "machine": machine, "type": "serial"})
|
||||||
|
if self._print_serial_logs:
|
||||||
|
self._eprint(
|
||||||
|
Style.DIM + "{} # {}".format(machine, message) + Style.RESET_ALL
|
||||||
|
)
|
||||||
|
|
||||||
|
def enqueue(self, item: Dict[str, str]) -> None:
|
||||||
|
self.queue.put(item)
|
||||||
|
|
||||||
|
def drain_log_queue(self) -> None:
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
item = self.queue.get_nowait()
|
||||||
|
msg = self.sanitise(item["msg"])
|
||||||
|
del item["msg"]
|
||||||
|
self.log_line(msg, item)
|
||||||
|
except Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]:
|
||||||
|
self._eprint(self.maybe_prefix(message, attributes))
|
||||||
|
|
||||||
|
self.xml.startElement("nest", attrs={})
|
||||||
|
self.xml.startElement("head", attributes)
|
||||||
|
self.xml.characters(message)
|
||||||
|
self.xml.endElement("head")
|
||||||
|
|
||||||
|
tic = time.time()
|
||||||
|
self.drain_log_queue()
|
||||||
|
yield
|
||||||
|
self.drain_log_queue()
|
||||||
|
toc = time.time()
|
||||||
|
self.log("(finished: {}, in {:.2f} seconds)".format(message, toc - tic))
|
||||||
|
|
||||||
|
self.xml.endElement("nest")
|
||||||
|
|
||||||
|
|
||||||
|
rootlog = Logger()
|
424
third_party/nixpkgs/nixos/lib/test-driver/test-driver.py → third_party/nixpkgs/nixos/lib/test-driver/test_driver/machine.py
vendored
Executable file → Normal file
424
third_party/nixpkgs/nixos/lib/test-driver/test-driver.py → third_party/nixpkgs/nixos/lib/test-driver/test_driver/machine.py
vendored
Executable file → Normal file
|
@ -1,19 +1,11 @@
|
||||||
#! /somewhere/python3
|
from contextlib import _GeneratorContextManager
|
||||||
from contextlib import contextmanager, _GeneratorContextManager
|
|
||||||
from queue import Queue, Empty
|
|
||||||
from typing import Tuple, Any, Callable, Dict, Iterator, Optional, List, Iterable
|
|
||||||
from xml.sax.saxutils import XMLGenerator
|
|
||||||
from colorama import Style
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import queue
|
from queue import Queue
|
||||||
import io
|
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
|
||||||
import threading
|
|
||||||
import argparse
|
|
||||||
import base64
|
import base64
|
||||||
import codecs
|
import io
|
||||||
import os
|
import os
|
||||||
import ptpython.repl
|
import queue
|
||||||
import pty
|
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -21,8 +13,10 @@ import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import threading
|
||||||
import time
|
import time
|
||||||
import unicodedata
|
|
||||||
|
from test_driver.logger import rootlog
|
||||||
|
|
||||||
CHAR_TO_KEY = {
|
CHAR_TO_KEY = {
|
||||||
"A": "shift-a",
|
"A": "shift-a",
|
||||||
|
@ -88,115 +82,10 @@ CHAR_TO_KEY = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Logger:
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.logfile = os.environ.get("LOGFILE", "/dev/null")
|
|
||||||
self.logfile_handle = codecs.open(self.logfile, "wb")
|
|
||||||
self.xml = XMLGenerator(self.logfile_handle, encoding="utf-8")
|
|
||||||
self.queue: "Queue[Dict[str, str]]" = Queue()
|
|
||||||
|
|
||||||
self.xml.startDocument()
|
|
||||||
self.xml.startElement("logfile", attrs={})
|
|
||||||
|
|
||||||
self._print_serial_logs = True
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _eprint(*args: object, **kwargs: Any) -> None:
|
|
||||||
print(*args, file=sys.stderr, **kwargs)
|
|
||||||
|
|
||||||
def close(self) -> None:
|
|
||||||
self.xml.endElement("logfile")
|
|
||||||
self.xml.endDocument()
|
|
||||||
self.logfile_handle.close()
|
|
||||||
|
|
||||||
def sanitise(self, message: str) -> str:
|
|
||||||
return "".join(ch for ch in message if unicodedata.category(ch)[0] != "C")
|
|
||||||
|
|
||||||
def maybe_prefix(self, message: str, attributes: Dict[str, str]) -> str:
|
|
||||||
if "machine" in attributes:
|
|
||||||
return "{}: {}".format(attributes["machine"], message)
|
|
||||||
return message
|
|
||||||
|
|
||||||
def log_line(self, message: str, attributes: Dict[str, str]) -> None:
|
|
||||||
self.xml.startElement("line", attributes)
|
|
||||||
self.xml.characters(message)
|
|
||||||
self.xml.endElement("line")
|
|
||||||
|
|
||||||
def info(self, *args, **kwargs) -> None: # type: ignore
|
|
||||||
self.log(*args, **kwargs)
|
|
||||||
|
|
||||||
def warning(self, *args, **kwargs) -> None: # type: ignore
|
|
||||||
self.log(*args, **kwargs)
|
|
||||||
|
|
||||||
def error(self, *args, **kwargs) -> None: # type: ignore
|
|
||||||
self.log(*args, **kwargs)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
def log(self, message: str, attributes: Dict[str, str] = {}) -> None:
|
|
||||||
self._eprint(self.maybe_prefix(message, attributes))
|
|
||||||
self.drain_log_queue()
|
|
||||||
self.log_line(message, attributes)
|
|
||||||
|
|
||||||
def log_serial(self, message: str, machine: str) -> None:
|
|
||||||
self.enqueue({"msg": message, "machine": machine, "type": "serial"})
|
|
||||||
if self._print_serial_logs:
|
|
||||||
self._eprint(
|
|
||||||
Style.DIM + "{} # {}".format(machine, message) + Style.RESET_ALL
|
|
||||||
)
|
|
||||||
|
|
||||||
def enqueue(self, item: Dict[str, str]) -> None:
|
|
||||||
self.queue.put(item)
|
|
||||||
|
|
||||||
def drain_log_queue(self) -> None:
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
item = self.queue.get_nowait()
|
|
||||||
msg = self.sanitise(item["msg"])
|
|
||||||
del item["msg"]
|
|
||||||
self.log_line(msg, item)
|
|
||||||
except Empty:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]:
|
|
||||||
self._eprint(self.maybe_prefix(message, attributes))
|
|
||||||
|
|
||||||
self.xml.startElement("nest", attrs={})
|
|
||||||
self.xml.startElement("head", attributes)
|
|
||||||
self.xml.characters(message)
|
|
||||||
self.xml.endElement("head")
|
|
||||||
|
|
||||||
tic = time.time()
|
|
||||||
self.drain_log_queue()
|
|
||||||
yield
|
|
||||||
self.drain_log_queue()
|
|
||||||
toc = time.time()
|
|
||||||
self.log("(finished: {}, in {:.2f} seconds)".format(message, toc - tic))
|
|
||||||
|
|
||||||
self.xml.endElement("nest")
|
|
||||||
|
|
||||||
|
|
||||||
rootlog = Logger()
|
|
||||||
|
|
||||||
|
|
||||||
def make_command(args: list) -> str:
|
def make_command(args: list) -> str:
|
||||||
return " ".join(map(shlex.quote, (map(str, args))))
|
return " ".join(map(shlex.quote, (map(str, args))))
|
||||||
|
|
||||||
|
|
||||||
def retry(fn: Callable, timeout: int = 900) -> None:
|
|
||||||
"""Call the given function repeatedly, with 1 second intervals,
|
|
||||||
until it returns True or a timeout is reached.
|
|
||||||
"""
|
|
||||||
|
|
||||||
for _ in range(timeout):
|
|
||||||
if fn(False):
|
|
||||||
return
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
if not fn(True):
|
|
||||||
raise Exception(f"action timed out after {timeout} seconds")
|
|
||||||
|
|
||||||
|
|
||||||
def _perform_ocr_on_screenshot(
|
def _perform_ocr_on_screenshot(
|
||||||
screenshot_path: str, model_ids: Iterable[int]
|
screenshot_path: str, model_ids: Iterable[int]
|
||||||
) -> List[str]:
|
) -> List[str]:
|
||||||
|
@ -228,6 +117,20 @@ def _perform_ocr_on_screenshot(
|
||||||
return model_results
|
return model_results
|
||||||
|
|
||||||
|
|
||||||
|
def retry(fn: Callable, timeout: int = 900) -> None:
|
||||||
|
"""Call the given function repeatedly, with 1 second intervals,
|
||||||
|
until it returns True or a timeout is reached.
|
||||||
|
"""
|
||||||
|
|
||||||
|
for _ in range(timeout):
|
||||||
|
if fn(False):
|
||||||
|
return
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
if not fn(True):
|
||||||
|
raise Exception(f"action timed out after {timeout} seconds")
|
||||||
|
|
||||||
|
|
||||||
class StartCommand:
|
class StartCommand:
|
||||||
"""The Base Start Command knows how to append the necesary
|
"""The Base Start Command knows how to append the necesary
|
||||||
runtime qemu options as determined by a particular test driver
|
runtime qemu options as determined by a particular test driver
|
||||||
|
@ -1066,286 +969,3 @@ class Machine:
|
||||||
self.shell.close()
|
self.shell.close()
|
||||||
self.monitor.close()
|
self.monitor.close()
|
||||||
self.serial_thread.join()
|
self.serial_thread.join()
|
||||||
|
|
||||||
|
|
||||||
class VLan:
|
|
||||||
"""This class handles a VLAN that the run-vm scripts identify via its
|
|
||||||
number handles. The network's lifetime equals the object's lifetime.
|
|
||||||
"""
|
|
||||||
|
|
||||||
nr: int
|
|
||||||
socket_dir: Path
|
|
||||||
|
|
||||||
process: subprocess.Popen
|
|
||||||
pid: int
|
|
||||||
fd: io.TextIOBase
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
|
||||||
return f"<Vlan Nr. {self.nr}>"
|
|
||||||
|
|
||||||
def __init__(self, nr: int, tmp_dir: Path):
|
|
||||||
self.nr = nr
|
|
||||||
self.socket_dir = tmp_dir / f"vde{self.nr}.ctl"
|
|
||||||
|
|
||||||
# TODO: don't side-effect environment here
|
|
||||||
os.environ[f"QEMU_VDE_SOCKET_{self.nr}"] = str(self.socket_dir)
|
|
||||||
|
|
||||||
rootlog.info("start vlan")
|
|
||||||
pty_master, pty_slave = pty.openpty()
|
|
||||||
|
|
||||||
self.process = subprocess.Popen(
|
|
||||||
["vde_switch", "-s", self.socket_dir, "--dirmode", "0700"],
|
|
||||||
stdin=pty_slave,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE,
|
|
||||||
shell=False,
|
|
||||||
)
|
|
||||||
self.pid = self.process.pid
|
|
||||||
self.fd = os.fdopen(pty_master, "w")
|
|
||||||
self.fd.write("version\n")
|
|
||||||
|
|
||||||
# TODO: perl version checks if this can be read from
|
|
||||||
# an if not, dies. we could hang here forever. Fix it.
|
|
||||||
assert self.process.stdout is not None
|
|
||||||
self.process.stdout.readline()
|
|
||||||
if not (self.socket_dir / "ctl").exists():
|
|
||||||
rootlog.error("cannot start vde_switch")
|
|
||||||
|
|
||||||
rootlog.info(f"running vlan (pid {self.pid})")
|
|
||||||
|
|
||||||
def __del__(self) -> None:
|
|
||||||
rootlog.info(f"kill vlan (pid {self.pid})")
|
|
||||||
self.fd.close()
|
|
||||||
self.process.terminate()
|
|
||||||
|
|
||||||
|
|
||||||
class Driver:
|
|
||||||
"""A handle to the driver that sets up the environment
|
|
||||||
and runs the tests"""
|
|
||||||
|
|
||||||
tests: str
|
|
||||||
vlans: List[VLan]
|
|
||||||
machines: List[Machine]
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
start_scripts: List[str],
|
|
||||||
vlans: List[int],
|
|
||||||
tests: str,
|
|
||||||
keep_vm_state: bool = False,
|
|
||||||
):
|
|
||||||
self.tests = tests
|
|
||||||
|
|
||||||
tmp_dir = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
|
|
||||||
tmp_dir.mkdir(mode=0o700, exist_ok=True)
|
|
||||||
|
|
||||||
with rootlog.nested("start all VLans"):
|
|
||||||
self.vlans = [VLan(nr, tmp_dir) for nr in vlans]
|
|
||||||
|
|
||||||
def cmd(scripts: List[str]) -> Iterator[NixStartScript]:
|
|
||||||
for s in scripts:
|
|
||||||
yield NixStartScript(s)
|
|
||||||
|
|
||||||
self.machines = [
|
|
||||||
Machine(
|
|
||||||
start_command=cmd,
|
|
||||||
keep_vm_state=keep_vm_state,
|
|
||||||
name=cmd.machine_name,
|
|
||||||
tmp_dir=tmp_dir,
|
|
||||||
)
|
|
||||||
for cmd in cmd(start_scripts)
|
|
||||||
]
|
|
||||||
|
|
||||||
def __enter__(self) -> "Driver":
|
|
||||||
return self
|
|
||||||
|
|
||||||
def __exit__(self, *_: Any) -> None:
|
|
||||||
with rootlog.nested("cleanup"):
|
|
||||||
for machine in self.machines:
|
|
||||||
machine.release()
|
|
||||||
|
|
||||||
def subtest(self, name: str) -> Iterator[None]:
|
|
||||||
"""Group logs under a given test name"""
|
|
||||||
with rootlog.nested(name):
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
rootlog.error(f'Test "{name}" failed with error: "{e}"')
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def test_symbols(self) -> Dict[str, Any]:
|
|
||||||
@contextmanager
|
|
||||||
def subtest(name: str) -> Iterator[None]:
|
|
||||||
return self.subtest(name)
|
|
||||||
|
|
||||||
general_symbols = dict(
|
|
||||||
start_all=self.start_all,
|
|
||||||
test_script=self.test_script,
|
|
||||||
machines=self.machines,
|
|
||||||
vlans=self.vlans,
|
|
||||||
driver=self,
|
|
||||||
log=rootlog,
|
|
||||||
os=os,
|
|
||||||
create_machine=self.create_machine,
|
|
||||||
subtest=subtest,
|
|
||||||
run_tests=self.run_tests,
|
|
||||||
join_all=self.join_all,
|
|
||||||
retry=retry,
|
|
||||||
serial_stdout_off=self.serial_stdout_off,
|
|
||||||
serial_stdout_on=self.serial_stdout_on,
|
|
||||||
Machine=Machine, # for typing
|
|
||||||
)
|
|
||||||
machine_symbols = {m.name: m for m in self.machines}
|
|
||||||
# If there's exactly one machine, make it available under the name
|
|
||||||
# "machine", even if it's not called that.
|
|
||||||
if len(self.machines) == 1:
|
|
||||||
(machine_symbols["machine"],) = self.machines
|
|
||||||
vlan_symbols = {
|
|
||||||
f"vlan{v.nr}": self.vlans[idx] for idx, v in enumerate(self.vlans)
|
|
||||||
}
|
|
||||||
print(
|
|
||||||
"additionally exposed symbols:\n "
|
|
||||||
+ ", ".join(map(lambda m: m.name, self.machines))
|
|
||||||
+ ",\n "
|
|
||||||
+ ", ".join(map(lambda v: f"vlan{v.nr}", self.vlans))
|
|
||||||
+ ",\n "
|
|
||||||
+ ", ".join(list(general_symbols.keys()))
|
|
||||||
)
|
|
||||||
return {**general_symbols, **machine_symbols, **vlan_symbols}
|
|
||||||
|
|
||||||
def test_script(self) -> None:
|
|
||||||
"""Run the test script"""
|
|
||||||
with rootlog.nested("run the VM test script"):
|
|
||||||
symbols = self.test_symbols() # call eagerly
|
|
||||||
exec(self.tests, symbols, None)
|
|
||||||
|
|
||||||
def run_tests(self) -> None:
|
|
||||||
"""Run the test script (for non-interactive test runs)"""
|
|
||||||
self.test_script()
|
|
||||||
# TODO: Collect coverage data
|
|
||||||
for machine in self.machines:
|
|
||||||
if machine.is_up():
|
|
||||||
machine.execute("sync")
|
|
||||||
|
|
||||||
def start_all(self) -> None:
|
|
||||||
"""Start all machines"""
|
|
||||||
with rootlog.nested("start all VMs"):
|
|
||||||
for machine in self.machines:
|
|
||||||
machine.start()
|
|
||||||
|
|
||||||
def join_all(self) -> None:
|
|
||||||
"""Wait for all machines to shut down"""
|
|
||||||
with rootlog.nested("wait for all VMs to finish"):
|
|
||||||
for machine in self.machines:
|
|
||||||
machine.wait_for_shutdown()
|
|
||||||
|
|
||||||
def create_machine(self, args: Dict[str, Any]) -> Machine:
|
|
||||||
rootlog.warning(
|
|
||||||
"Using legacy create_machine(), please instantiate the"
|
|
||||||
"Machine class directly, instead"
|
|
||||||
)
|
|
||||||
tmp_dir = Path(os.environ.get("TMPDIR", tempfile.gettempdir()))
|
|
||||||
tmp_dir.mkdir(mode=0o700, exist_ok=True)
|
|
||||||
|
|
||||||
if args.get("startCommand"):
|
|
||||||
start_command: str = args.get("startCommand", "")
|
|
||||||
cmd = NixStartScript(start_command)
|
|
||||||
name = args.get("name", cmd.machine_name)
|
|
||||||
else:
|
|
||||||
cmd = Machine.create_startcommand(args) # type: ignore
|
|
||||||
name = args.get("name", "machine")
|
|
||||||
|
|
||||||
return Machine(
|
|
||||||
tmp_dir=tmp_dir,
|
|
||||||
start_command=cmd,
|
|
||||||
name=name,
|
|
||||||
keep_vm_state=args.get("keep_vm_state", False),
|
|
||||||
allow_reboot=args.get("allow_reboot", False),
|
|
||||||
)
|
|
||||||
|
|
||||||
def serial_stdout_on(self) -> None:
|
|
||||||
rootlog._print_serial_logs = True
|
|
||||||
|
|
||||||
def serial_stdout_off(self) -> None:
|
|
||||||
rootlog._print_serial_logs = False
|
|
||||||
|
|
||||||
|
|
||||||
class EnvDefault(argparse.Action):
|
|
||||||
"""An argpars Action that takes values from the specified
|
|
||||||
environment variable as the flags default value.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, envvar, required=False, default=None, nargs=None, **kwargs): # type: ignore
|
|
||||||
if not default and envvar:
|
|
||||||
if envvar in os.environ:
|
|
||||||
if nargs is not None and (nargs.isdigit() or nargs in ["*", "+"]):
|
|
||||||
default = os.environ[envvar].split()
|
|
||||||
else:
|
|
||||||
default = os.environ[envvar]
|
|
||||||
kwargs["help"] = (
|
|
||||||
kwargs["help"] + f" (default from environment: {default})"
|
|
||||||
)
|
|
||||||
if required and default:
|
|
||||||
required = False
|
|
||||||
super(EnvDefault, self).__init__(
|
|
||||||
default=default, required=required, nargs=nargs, **kwargs
|
|
||||||
)
|
|
||||||
|
|
||||||
def __call__(self, parser, namespace, values, option_string=None): # type: ignore
|
|
||||||
setattr(namespace, self.dest, values)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
arg_parser = argparse.ArgumentParser(prog="nixos-test-driver")
|
|
||||||
arg_parser.add_argument(
|
|
||||||
"-K",
|
|
||||||
"--keep-vm-state",
|
|
||||||
help="re-use a VM state coming from a previous run",
|
|
||||||
action="store_true",
|
|
||||||
)
|
|
||||||
arg_parser.add_argument(
|
|
||||||
"-I",
|
|
||||||
"--interactive",
|
|
||||||
help="drop into a python repl and run the tests interactively",
|
|
||||||
action="store_true",
|
|
||||||
)
|
|
||||||
arg_parser.add_argument(
|
|
||||||
"--start-scripts",
|
|
||||||
metavar="START-SCRIPT",
|
|
||||||
action=EnvDefault,
|
|
||||||
envvar="startScripts",
|
|
||||||
nargs="*",
|
|
||||||
help="start scripts for participating virtual machines",
|
|
||||||
)
|
|
||||||
arg_parser.add_argument(
|
|
||||||
"--vlans",
|
|
||||||
metavar="VLAN",
|
|
||||||
action=EnvDefault,
|
|
||||||
envvar="vlans",
|
|
||||||
nargs="*",
|
|
||||||
help="vlans to span by the driver",
|
|
||||||
)
|
|
||||||
arg_parser.add_argument(
|
|
||||||
"testscript",
|
|
||||||
action=EnvDefault,
|
|
||||||
envvar="testScript",
|
|
||||||
help="the test script to run",
|
|
||||||
type=Path,
|
|
||||||
)
|
|
||||||
|
|
||||||
args = arg_parser.parse_args()
|
|
||||||
|
|
||||||
if not args.keep_vm_state:
|
|
||||||
rootlog.info("Machine state will be reset. To keep it, pass --keep-vm-state")
|
|
||||||
|
|
||||||
with Driver(
|
|
||||||
args.start_scripts, args.vlans, args.testscript.read_text(), args.keep_vm_state
|
|
||||||
) as driver:
|
|
||||||
if args.interactive:
|
|
||||||
ptpython.repl.embed(driver.test_symbols(), {})
|
|
||||||
else:
|
|
||||||
tic = time.time()
|
|
||||||
driver.run_tests()
|
|
||||||
toc = time.time()
|
|
||||||
rootlog.info(f"test script finished in {(toc-tic):.2f}s")
|
|
58
third_party/nixpkgs/nixos/lib/test-driver/test_driver/vlan.py
vendored
Normal file
58
third_party/nixpkgs/nixos/lib/test-driver/test_driver/vlan.py
vendored
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
from pathlib import Path
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import pty
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
from test_driver.logger import rootlog
|
||||||
|
|
||||||
|
|
||||||
|
class VLan:
|
||||||
|
"""This class handles a VLAN that the run-vm scripts identify via its
|
||||||
|
number handles. The network's lifetime equals the object's lifetime.
|
||||||
|
"""
|
||||||
|
|
||||||
|
nr: int
|
||||||
|
socket_dir: Path
|
||||||
|
|
||||||
|
process: subprocess.Popen
|
||||||
|
pid: int
|
||||||
|
fd: io.TextIOBase
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return f"<Vlan Nr. {self.nr}>"
|
||||||
|
|
||||||
|
def __init__(self, nr: int, tmp_dir: Path):
|
||||||
|
self.nr = nr
|
||||||
|
self.socket_dir = tmp_dir / f"vde{self.nr}.ctl"
|
||||||
|
|
||||||
|
# TODO: don't side-effect environment here
|
||||||
|
os.environ[f"QEMU_VDE_SOCKET_{self.nr}"] = str(self.socket_dir)
|
||||||
|
|
||||||
|
rootlog.info("start vlan")
|
||||||
|
pty_master, pty_slave = pty.openpty()
|
||||||
|
|
||||||
|
self.process = subprocess.Popen(
|
||||||
|
["vde_switch", "-s", self.socket_dir, "--dirmode", "0700"],
|
||||||
|
stdin=pty_slave,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
shell=False,
|
||||||
|
)
|
||||||
|
self.pid = self.process.pid
|
||||||
|
self.fd = os.fdopen(pty_master, "w")
|
||||||
|
self.fd.write("version\n")
|
||||||
|
|
||||||
|
# TODO: perl version checks if this can be read from
|
||||||
|
# an if not, dies. we could hang here forever. Fix it.
|
||||||
|
assert self.process.stdout is not None
|
||||||
|
self.process.stdout.readline()
|
||||||
|
if not (self.socket_dir / "ctl").exists():
|
||||||
|
rootlog.error("cannot start vde_switch")
|
||||||
|
|
||||||
|
rootlog.info(f"running vlan (pid {self.pid})")
|
||||||
|
|
||||||
|
def __del__(self) -> None:
|
||||||
|
rootlog.info(f"kill vlan (pid {self.pid})")
|
||||||
|
self.fd.close()
|
||||||
|
self.process.terminate()
|
73
third_party/nixpkgs/nixos/lib/testing-python.nix
vendored
73
third_party/nixpkgs/nixos/lib/testing-python.nix
vendored
|
@ -16,65 +16,6 @@ rec {
|
||||||
|
|
||||||
inherit pkgs;
|
inherit pkgs;
|
||||||
|
|
||||||
# Reifies and correctly wraps the python test driver for
|
|
||||||
# the respective qemu version and with or without ocr support
|
|
||||||
pythonTestDriver = {
|
|
||||||
qemu_pkg ? pkgs.qemu_test
|
|
||||||
, enableOCR ? false
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
name = "nixos-test-driver";
|
|
||||||
testDriverScript = ./test-driver/test-driver.py;
|
|
||||||
ocrProg = tesseract4.override { enableLanguages = [ "eng" ]; };
|
|
||||||
imagemagick_tiff = imagemagick_light.override { inherit libtiff; };
|
|
||||||
in stdenv.mkDerivation {
|
|
||||||
inherit name;
|
|
||||||
|
|
||||||
nativeBuildInputs = [ makeWrapper ];
|
|
||||||
buildInputs = [ (python3.withPackages (p: [ p.ptpython p.colorama ])) ];
|
|
||||||
checkInputs = with python3Packages; [ pylint black mypy ];
|
|
||||||
|
|
||||||
dontUnpack = true;
|
|
||||||
|
|
||||||
preferLocalBuild = true;
|
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
python <<EOF
|
|
||||||
from pydoc import importfile
|
|
||||||
with open('driver-symbols', 'w') as fp:
|
|
||||||
t = importfile('${testDriverScript}')
|
|
||||||
d = t.Driver([],[],"")
|
|
||||||
test_symbols = d.test_symbols()
|
|
||||||
fp.write(','.join(test_symbols.keys()))
|
|
||||||
EOF
|
|
||||||
'';
|
|
||||||
|
|
||||||
doCheck = true;
|
|
||||||
checkPhase = ''
|
|
||||||
mypy --disallow-untyped-defs \
|
|
||||||
--no-implicit-optional \
|
|
||||||
--ignore-missing-imports ${testDriverScript}
|
|
||||||
pylint --errors-only ${testDriverScript}
|
|
||||||
black --check --diff ${testDriverScript}
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase =
|
|
||||||
''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
cp ${testDriverScript} $out/bin/nixos-test-driver
|
|
||||||
chmod u+x $out/bin/nixos-test-driver
|
|
||||||
# TODO: copy user script part into this file (append)
|
|
||||||
|
|
||||||
wrapProgram $out/bin/nixos-test-driver \
|
|
||||||
--argv0 ${name} \
|
|
||||||
--prefix PATH : "${lib.makeBinPath [ qemu_pkg vde2 netpbm coreutils socat ]}" \
|
|
||||||
${lib.optionalString enableOCR
|
|
||||||
"--prefix PATH : '${ocrProg}/bin:${imagemagick_tiff}/bin'"} \
|
|
||||||
|
|
||||||
install -m 0644 -vD driver-symbols $out/nix-support/driver-symbols
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# Run an automated test suite in the given virtual network.
|
# Run an automated test suite in the given virtual network.
|
||||||
runTests = { driver, pos }:
|
runTests = { driver, pos }:
|
||||||
stdenv.mkDerivation {
|
stdenv.mkDerivation {
|
||||||
|
@ -112,8 +53,15 @@ rec {
|
||||||
, passthru ? {}
|
, passthru ? {}
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
# FIXME: get this pkg from the module system
|
# Reifies and correctly wraps the python test driver for
|
||||||
testDriver = pythonTestDriver { inherit qemu_pkg enableOCR;};
|
# the respective qemu version and with or without ocr support
|
||||||
|
testDriver = pkgs.callPackage ./test-driver {
|
||||||
|
inherit enableOCR;
|
||||||
|
qemu_pkg = qemu_test;
|
||||||
|
imagemagick_light = imagemagick_light.override { inherit libtiff; };
|
||||||
|
tesseract4 = tesseract4.override { enableLanguages = [ "eng" ]; };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
testDriverName =
|
testDriverName =
|
||||||
let
|
let
|
||||||
|
@ -178,10 +126,11 @@ rec {
|
||||||
echo -n "$testScript" > $out/test-script
|
echo -n "$testScript" > $out/test-script
|
||||||
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-test-driver
|
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-test-driver
|
||||||
|
|
||||||
|
${testDriver}/bin/generate-driver-symbols
|
||||||
${lib.optionalString (!skipLint) ''
|
${lib.optionalString (!skipLint) ''
|
||||||
PYFLAKES_BUILTINS="$(
|
PYFLAKES_BUILTINS="$(
|
||||||
echo -n ${lib.escapeShellArg (lib.concatStringsSep "," nodeHostNames)},
|
echo -n ${lib.escapeShellArg (lib.concatStringsSep "," nodeHostNames)},
|
||||||
< ${lib.escapeShellArg "${testDriver}/nix-support/driver-symbols"}
|
< ${lib.escapeShellArg "driver-symbols"}
|
||||||
)" ${python3Packages.pyflakes}/bin/pyflakes $out/test-script
|
)" ${python3Packages.pyflakes}/bin/pyflakes $out/test-script
|
||||||
''}
|
''}
|
||||||
|
|
||||||
|
|
7
third_party/nixpkgs/nixos/lib/utils.nix
vendored
7
third_party/nixpkgs/nixos/lib/utils.nix
vendored
|
@ -1,4 +1,4 @@
|
||||||
pkgs: with pkgs.lib;
|
{ lib, config, pkgs }: with lib;
|
||||||
|
|
||||||
rec {
|
rec {
|
||||||
|
|
||||||
|
@ -165,4 +165,9 @@ rec {
|
||||||
${builtins.toJSON set}
|
${builtins.toJSON set}
|
||||||
EOF
|
EOF
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
systemdUtils = {
|
||||||
|
lib = import ./systemd-lib.nix { inherit lib config pkgs; };
|
||||||
|
unitOptions = import ./systemd-unit-options.nix { inherit lib systemdUtils; };
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
# /etc files related to networking, such as /etc/services.
|
# /etc files related to networking, such as /etc/services.
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.networking;
|
cfg = config.networking;
|
||||||
|
opt = options.networking;
|
||||||
|
|
||||||
localhostMultiple = any (elem "localhost") (attrValues (removeAttrs cfg.hosts [ "127.0.0.1" "::1" ]));
|
localhostMultiple = any (elem "localhost") (attrValues (removeAttrs cfg.hosts [ "127.0.0.1" "::1" ]));
|
||||||
|
|
||||||
|
@ -78,6 +79,7 @@ in
|
||||||
httpProxy = lib.mkOption {
|
httpProxy = lib.mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = cfg.proxy.default;
|
default = cfg.proxy.default;
|
||||||
|
defaultText = literalExpression "config.${opt.proxy.default}";
|
||||||
description = ''
|
description = ''
|
||||||
This option specifies the http_proxy environment variable.
|
This option specifies the http_proxy environment variable.
|
||||||
'';
|
'';
|
||||||
|
@ -87,6 +89,7 @@ in
|
||||||
httpsProxy = lib.mkOption {
|
httpsProxy = lib.mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = cfg.proxy.default;
|
default = cfg.proxy.default;
|
||||||
|
defaultText = literalExpression "config.${opt.proxy.default}";
|
||||||
description = ''
|
description = ''
|
||||||
This option specifies the https_proxy environment variable.
|
This option specifies the https_proxy environment variable.
|
||||||
'';
|
'';
|
||||||
|
@ -96,6 +99,7 @@ in
|
||||||
ftpProxy = lib.mkOption {
|
ftpProxy = lib.mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = cfg.proxy.default;
|
default = cfg.proxy.default;
|
||||||
|
defaultText = literalExpression "config.${opt.proxy.default}";
|
||||||
description = ''
|
description = ''
|
||||||
This option specifies the ftp_proxy environment variable.
|
This option specifies the ftp_proxy environment variable.
|
||||||
'';
|
'';
|
||||||
|
@ -105,6 +109,7 @@ in
|
||||||
rsyncProxy = lib.mkOption {
|
rsyncProxy = lib.mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = cfg.proxy.default;
|
default = cfg.proxy.default;
|
||||||
|
defaultText = literalExpression "config.${opt.proxy.default}";
|
||||||
description = ''
|
description = ''
|
||||||
This option specifies the rsync_proxy environment variable.
|
This option specifies the rsync_proxy environment variable.
|
||||||
'';
|
'';
|
||||||
|
@ -114,6 +119,7 @@ in
|
||||||
allProxy = lib.mkOption {
|
allProxy = lib.mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = cfg.proxy.default;
|
default = cfg.proxy.default;
|
||||||
|
defaultText = literalExpression "config.${opt.proxy.default}";
|
||||||
description = ''
|
description = ''
|
||||||
This option specifies the all_proxy environment variable.
|
This option specifies the all_proxy environment variable.
|
||||||
'';
|
'';
|
||||||
|
|
|
@ -41,12 +41,17 @@ let
|
||||||
pkgs.zstd
|
pkgs.zstd
|
||||||
];
|
];
|
||||||
|
|
||||||
defaultPackages = map (pkg: setPrio ((pkg.meta.priority or 5) + 3) pkg)
|
defaultPackageNames =
|
||||||
[ pkgs.nano
|
[ "nano"
|
||||||
pkgs.perl
|
"perl"
|
||||||
pkgs.rsync
|
"rsync"
|
||||||
pkgs.strace
|
"strace"
|
||||||
];
|
];
|
||||||
|
defaultPackages =
|
||||||
|
map
|
||||||
|
(n: let pkg = pkgs.${n}; in setPrio ((pkg.meta.priority or 5) + 3) pkg)
|
||||||
|
defaultPackageNames;
|
||||||
|
defaultPackagesText = "[ ${concatMapStringsSep " " (n: "pkgs.${n}") defaultPackageNames } ]";
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
|
@ -73,6 +78,11 @@ in
|
||||||
defaultPackages = mkOption {
|
defaultPackages = mkOption {
|
||||||
type = types.listOf types.package;
|
type = types.listOf types.package;
|
||||||
default = defaultPackages;
|
default = defaultPackages;
|
||||||
|
defaultText = literalDocBook ''
|
||||||
|
these packages, with their <literal>meta.priority</literal> numerically increased
|
||||||
|
(thus lowering their installation priority):
|
||||||
|
<programlisting>${defaultPackagesText}</programlisting>
|
||||||
|
'';
|
||||||
example = [];
|
example = [];
|
||||||
description = ''
|
description = ''
|
||||||
Set of default packages that aren't strictly necessary
|
Set of default packages that aren't strictly necessary
|
||||||
|
|
47
third_party/nixpkgs/nixos/modules/hardware/cpu/intel-sgx.nix
vendored
Normal file
47
third_party/nixpkgs/nixos/modules/hardware/cpu/intel-sgx.nix
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.hardware.cpu.intel.sgx.provision;
|
||||||
|
defaultGroup = "sgx_prv";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.hardware.cpu.intel.sgx.provision = {
|
||||||
|
enable = mkEnableOption "access to the Intel SGX provisioning device";
|
||||||
|
user = mkOption {
|
||||||
|
description = "Owner to assign to the SGX provisioning device.";
|
||||||
|
type = types.str;
|
||||||
|
default = "root";
|
||||||
|
};
|
||||||
|
group = mkOption {
|
||||||
|
description = "Group to assign to the SGX provisioning device.";
|
||||||
|
type = types.str;
|
||||||
|
default = defaultGroup;
|
||||||
|
};
|
||||||
|
mode = mkOption {
|
||||||
|
description = "Mode to set for the SGX provisioning device.";
|
||||||
|
type = types.str;
|
||||||
|
default = "0660";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = hasAttr cfg.user config.users.users;
|
||||||
|
message = "Given user does not exist";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = (cfg.group == defaultGroup) || (hasAttr cfg.group config.users.groups);
|
||||||
|
message = "Given group does not exist";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
users.groups = optionalAttrs (cfg.group == defaultGroup) {
|
||||||
|
"${cfg.group}" = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
services.udev.extraRules = ''
|
||||||
|
SUBSYSTEM=="misc", KERNEL=="sgx_provision", OWNER="${cfg.user}", GROUP="${cfg.group}", MODE="${cfg.mode}"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
37
third_party/nixpkgs/nixos/modules/hardware/gpgsmartcards.nix
vendored
Normal file
37
third_party/nixpkgs/nixos/modules/hardware/gpgsmartcards.nix
vendored
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
# gnupg's manual describes how to setup ccid udev rules:
|
||||||
|
# https://www.gnupg.org/howtos/card-howto/en/ch02s03.html
|
||||||
|
# gnupg folks advised me (https://dev.gnupg.org/T5409) to look at debian's rules:
|
||||||
|
# https://salsa.debian.org/debian/gnupg2/-/blob/debian/main/debian/scdaemon.udev
|
||||||
|
|
||||||
|
# the latest rev of the entire debian gnupg2 repo as of 2021-04-28
|
||||||
|
# the scdaemon.udev file was last commited on 2021-01-05 (7817a03):
|
||||||
|
scdaemonUdevRev = "01898735a015541e3ffb43c7245ac1e612f40836";
|
||||||
|
|
||||||
|
scdaemonRules = pkgs.fetchurl {
|
||||||
|
url = "https://salsa.debian.org/debian/gnupg2/-/raw/${scdaemonUdevRev}/debian/scdaemon.udev";
|
||||||
|
sha256 = "08v0vp6950bz7galvc92zdss89y9vcwbinmbfcdldy8x72w6rqr3";
|
||||||
|
};
|
||||||
|
|
||||||
|
# per debian's udev deb hook (https://man7.org/linux/man-pages/man1/dh_installudev.1.html)
|
||||||
|
destination = "60-scdaemon.rules";
|
||||||
|
|
||||||
|
scdaemonUdevRulesPkg = pkgs.runCommandNoCC "scdaemon-udev-rules" {} ''
|
||||||
|
loc="$out/lib/udev/rules.d/"
|
||||||
|
mkdir -p "''${loc}"
|
||||||
|
cp "${scdaemonRules}" "''${loc}/${destination}"
|
||||||
|
'';
|
||||||
|
|
||||||
|
cfg = config.hardware.gpgSmartcards;
|
||||||
|
in {
|
||||||
|
options.hardware.gpgSmartcards = {
|
||||||
|
enable = mkEnableOption "udev rules for gnupg smart cards";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
services.udev.packages = [ scdaemonUdevRulesPkg ];
|
||||||
|
};
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ let
|
||||||
cfg = config.hardware.keyboard.zsa;
|
cfg = config.hardware.keyboard.zsa;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# TODO: make group configurable like in https://github.com/NixOS/nixpkgs/blob/0b2b4b8c4e729535a61db56468809c5c2d3d175c/pkgs/tools/security/nitrokey-app/udev-rules.nix ?
|
|
||||||
options.hardware.keyboard.zsa = {
|
options.hardware.keyboard.zsa = {
|
||||||
enable = mkOption {
|
enable = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
|
@ -14,7 +13,6 @@ in
|
||||||
Enables udev rules for keyboards from ZSA like the ErgoDox EZ, Planck EZ and Moonlander Mark I.
|
Enables 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
|
You need it when you want to flash a new configuration on the keyboard
|
||||||
or use their live training in the browser.
|
or use their live training in the browser.
|
||||||
Access to the keyboard is granted to users in the "plugdev" group.
|
|
||||||
You may want to install the wally-cli package.
|
You may want to install the wally-cli package.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
@ -22,6 +20,5 @@ in
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
services.udev.packages = [ pkgs.zsa-udev-rules ];
|
services.udev.packages = [ pkgs.zsa-udev-rules ];
|
||||||
users.groups.plugdev = {};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ in
|
||||||
|
|
||||||
config = mkOption {
|
config = mkOption {
|
||||||
default = null;
|
default = null;
|
||||||
|
type = types.nullOr types.path;
|
||||||
description = ''
|
description = ''
|
||||||
Path to the configuration file which maps the memory, IRQs
|
Path to the configuration file which maps the memory, IRQs
|
||||||
and ports used by the PCMCIA hardware.
|
and ports used by the PCMCIA hardware.
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) mkOption mkEnableOption types mkIf mkMerge optional versionOlder;
|
inherit (lib) literalExpression mkOption mkEnableOption types mkIf mkMerge optional versionOlder;
|
||||||
cfg = config.hardware.system76;
|
cfg = config.hardware.system76;
|
||||||
|
opt = options.hardware.system76;
|
||||||
|
|
||||||
kpkgs = config.boot.kernelPackages;
|
kpkgs = config.boot.kernelPackages;
|
||||||
modules = [ "system76" "system76-io" ] ++ (optional (versionOlder kpkgs.kernel.version "5.5") "system76-acpi");
|
modules = [ "system76" "system76-io" ] ++ (optional (versionOlder kpkgs.kernel.version "5.5") "system76-acpi");
|
||||||
|
@ -60,6 +61,7 @@ in {
|
||||||
|
|
||||||
firmware-daemon.enable = mkOption {
|
firmware-daemon.enable = mkOption {
|
||||||
default = cfg.enableAll;
|
default = cfg.enableAll;
|
||||||
|
defaultText = literalExpression "config.${opt.enableAll}";
|
||||||
example = true;
|
example = true;
|
||||||
description = "Whether to enable the system76 firmware daemon";
|
description = "Whether to enable the system76 firmware daemon";
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
|
@ -67,6 +69,7 @@ in {
|
||||||
|
|
||||||
kernel-modules.enable = mkOption {
|
kernel-modules.enable = mkOption {
|
||||||
default = cfg.enableAll;
|
default = cfg.enableAll;
|
||||||
|
defaultText = literalExpression "config.${opt.enableAll}";
|
||||||
example = true;
|
example = true;
|
||||||
description = "Whether to make the system76 out-of-tree kernel modules available";
|
description = "Whether to make the system76 out-of-tree kernel modules available";
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
|
@ -74,6 +77,7 @@ in {
|
||||||
|
|
||||||
power-daemon.enable = mkOption {
|
power-daemon.enable = mkOption {
|
||||||
default = cfg.enableAll;
|
default = cfg.enableAll;
|
||||||
|
defaultText = literalExpression "config.${opt.enableAll}";
|
||||||
example = true;
|
example = true;
|
||||||
description = "Whether to enable the system76 power daemon";
|
description = "Whether to enable the system76 power daemon";
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{ config, lib, pkgs, baseModules, extraModules, modules, modulesPath, ... }:
|
{ config, lib, pkgs, extendModules, noUserModules, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
|
@ -6,11 +6,8 @@ let
|
||||||
|
|
||||||
cfg = config.documentation;
|
cfg = config.documentation;
|
||||||
|
|
||||||
manualModules =
|
/* Modules for which to show options even when not imported. */
|
||||||
baseModules
|
extraDocModules = [ ../virtualisation/qemu-vm.nix ];
|
||||||
# Modules for which to show options even when not imported
|
|
||||||
++ [ ../virtualisation/qemu-vm.nix ]
|
|
||||||
++ optionals cfg.nixos.includeAllModules (extraModules ++ modules);
|
|
||||||
|
|
||||||
/* For the purpose of generating docs, evaluate options with each derivation
|
/* For the purpose of generating docs, evaluate options with each derivation
|
||||||
in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}".
|
in `pkgs` (recursively) replaced by a fake with path "\${pkgs.attribute.path}".
|
||||||
|
@ -24,13 +21,10 @@ let
|
||||||
extraSources = cfg.nixos.extraModuleSources;
|
extraSources = cfg.nixos.extraModuleSources;
|
||||||
options =
|
options =
|
||||||
let
|
let
|
||||||
scrubbedEval = evalModules {
|
extendNixOS = if cfg.nixos.includeAllModules then extendModules else noUserModules.extendModules;
|
||||||
modules = [ { nixpkgs.localSystem = config.nixpkgs.localSystem; } ] ++ manualModules;
|
scrubbedEval = extendNixOS {
|
||||||
args = (config._module.args) // { modules = [ ]; };
|
modules = extraDocModules;
|
||||||
specialArgs = {
|
specialArgs.pkgs = scrubDerivations "pkgs" pkgs;
|
||||||
pkgs = scrubDerivations "pkgs" pkgs;
|
|
||||||
inherit modulesPath;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
scrubDerivations = namePrefix: pkgSet: mapAttrs
|
scrubDerivations = namePrefix: pkgSet: mapAttrs
|
||||||
(name: value:
|
(name: value:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{ pkgs, ... }:
|
{ lib, config, pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
_module.args = {
|
_module.args = {
|
||||||
utils = import ../../lib/utils.nix pkgs;
|
utils = import ../../lib/utils.nix { inherit lib config pkgs; };
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.system.nixos;
|
cfg = config.system.nixos;
|
||||||
|
opt = options.system.nixos;
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -53,6 +54,7 @@ in
|
||||||
stateVersion = mkOption {
|
stateVersion = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = cfg.release;
|
default = cfg.release;
|
||||||
|
defaultText = literalExpression "config.${opt.release}";
|
||||||
description = ''
|
description = ''
|
||||||
Every once in a while, a new NixOS release may change
|
Every once in a while, a new NixOS release may change
|
||||||
configuration defaults in a way incompatible with stateful
|
configuration defaults in a way incompatible with stateful
|
||||||
|
|
|
@ -45,11 +45,13 @@
|
||||||
./hardware/ckb-next.nix
|
./hardware/ckb-next.nix
|
||||||
./hardware/cpu/amd-microcode.nix
|
./hardware/cpu/amd-microcode.nix
|
||||||
./hardware/cpu/intel-microcode.nix
|
./hardware/cpu/intel-microcode.nix
|
||||||
|
./hardware/cpu/intel-sgx.nix
|
||||||
./hardware/corectrl.nix
|
./hardware/corectrl.nix
|
||||||
./hardware/digitalbitbox.nix
|
./hardware/digitalbitbox.nix
|
||||||
./hardware/device-tree.nix
|
./hardware/device-tree.nix
|
||||||
./hardware/gkraken.nix
|
./hardware/gkraken.nix
|
||||||
./hardware/flirc.nix
|
./hardware/flirc.nix
|
||||||
|
./hardware/gpgsmartcards.nix
|
||||||
./hardware/i2c.nix
|
./hardware/i2c.nix
|
||||||
./hardware/sensor/hddtemp.nix
|
./hardware/sensor/hddtemp.nix
|
||||||
./hardware/sensor/iio.nix
|
./hardware/sensor/iio.nix
|
||||||
|
@ -446,6 +448,7 @@
|
||||||
./services/hardware/xow.nix
|
./services/hardware/xow.nix
|
||||||
./services/logging/SystemdJournal2Gelf.nix
|
./services/logging/SystemdJournal2Gelf.nix
|
||||||
./services/logging/awstats.nix
|
./services/logging/awstats.nix
|
||||||
|
./services/logging/filebeat.nix
|
||||||
./services/logging/fluentd.nix
|
./services/logging/fluentd.nix
|
||||||
./services/logging/graylog.nix
|
./services/logging/graylog.nix
|
||||||
./services/logging/heartbeat.nix
|
./services/logging/heartbeat.nix
|
||||||
|
@ -467,6 +470,7 @@
|
||||||
./services/mail/dovecot.nix
|
./services/mail/dovecot.nix
|
||||||
./services/mail/dspam.nix
|
./services/mail/dspam.nix
|
||||||
./services/mail/exim.nix
|
./services/mail/exim.nix
|
||||||
|
./services/mail/maddy.nix
|
||||||
./services/mail/mail.nix
|
./services/mail/mail.nix
|
||||||
./services/mail/mailcatcher.nix
|
./services/mail/mailcatcher.nix
|
||||||
./services/mail/mailhog.nix
|
./services/mail/mailhog.nix
|
||||||
|
@ -926,6 +930,7 @@
|
||||||
./services/search/kibana.nix
|
./services/search/kibana.nix
|
||||||
./services/search/meilisearch.nix
|
./services/search/meilisearch.nix
|
||||||
./services/search/solr.nix
|
./services/search/solr.nix
|
||||||
|
./services/security/aesmd.nix
|
||||||
./services/security/certmgr.nix
|
./services/security/certmgr.nix
|
||||||
./services/security/cfssl.nix
|
./services/security/cfssl.nix
|
||||||
./services/security/clamav.nix
|
./services/security/clamav.nix
|
||||||
|
@ -1021,6 +1026,7 @@
|
||||||
./services/web-apps/plantuml-server.nix
|
./services/web-apps/plantuml-server.nix
|
||||||
./services/web-apps/plausible.nix
|
./services/web-apps/plausible.nix
|
||||||
./services/web-apps/pgpkeyserver-lite.nix
|
./services/web-apps/pgpkeyserver-lite.nix
|
||||||
|
./services/web-apps/powerdns-admin.nix
|
||||||
./services/web-apps/matomo.nix
|
./services/web-apps/matomo.nix
|
||||||
./services/web-apps/moinmoin.nix
|
./services/web-apps/moinmoin.nix
|
||||||
./services/web-apps/openwebrx.nix
|
./services/web-apps/openwebrx.nix
|
||||||
|
@ -1191,8 +1197,7 @@
|
||||||
./virtualisation/kvmgt.nix
|
./virtualisation/kvmgt.nix
|
||||||
./virtualisation/openvswitch.nix
|
./virtualisation/openvswitch.nix
|
||||||
./virtualisation/parallels-guest.nix
|
./virtualisation/parallels-guest.nix
|
||||||
./virtualisation/podman.nix
|
./virtualisation/podman/default.nix
|
||||||
./virtualisation/podman-network-socket-ghostunnel.nix
|
|
||||||
./virtualisation/qemu-guest-agent.nix
|
./virtualisation/qemu-guest-agent.nix
|
||||||
./virtualisation/railcar.nix
|
./virtualisation/railcar.nix
|
||||||
./virtualisation/spice-usb-redirection.nix
|
./virtualisation/spice-usb-redirection.nix
|
||||||
|
|
|
@ -3,6 +3,18 @@
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
cfg = config.programs.captive-browser;
|
cfg = config.programs.captive-browser;
|
||||||
|
browserDefault = chromium: concatStringsSep " " [
|
||||||
|
''env XDG_CONFIG_HOME="$PREV_CONFIG_HOME"''
|
||||||
|
''${chromium}/bin/chromium''
|
||||||
|
''--user-data-dir=''${XDG_DATA_HOME:-$HOME/.local/share}/chromium-captive''
|
||||||
|
''--proxy-server="socks5://$PROXY"''
|
||||||
|
''--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE localhost"''
|
||||||
|
''--no-first-run''
|
||||||
|
''--new-window''
|
||||||
|
''--incognito''
|
||||||
|
''-no-default-browser-check''
|
||||||
|
''http://cache.nixos.org/''
|
||||||
|
];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
###### interface
|
###### interface
|
||||||
|
@ -26,18 +38,8 @@ in
|
||||||
# the options below are the same as in "captive-browser.toml"
|
# the options below are the same as in "captive-browser.toml"
|
||||||
browser = mkOption {
|
browser = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = concatStringsSep " " [
|
default = browserDefault pkgs.chromium;
|
||||||
''env XDG_CONFIG_HOME="$PREV_CONFIG_HOME"''
|
defaultText = literalExpression (browserDefault "\${pkgs.chromium}");
|
||||||
''${pkgs.chromium}/bin/chromium''
|
|
||||||
''--user-data-dir=''${XDG_DATA_HOME:-$HOME/.local/share}/chromium-captive''
|
|
||||||
''--proxy-server="socks5://$PROXY"''
|
|
||||||
''--host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE localhost"''
|
|
||||||
''--no-first-run''
|
|
||||||
''--new-window''
|
|
||||||
''--incognito''
|
|
||||||
''-no-default-browser-check''
|
|
||||||
''http://cache.nixos.org/''
|
|
||||||
];
|
|
||||||
description = ''
|
description = ''
|
||||||
The shell (/bin/sh) command executed once the proxy starts.
|
The shell (/bin/sh) command executed once the proxy starts.
|
||||||
When browser exits, the proxy exits. An extra env var PROXY is available.
|
When browser exits, the proxy exits. An extra env var PROXY is available.
|
||||||
|
|
|
@ -60,7 +60,7 @@ in
|
||||||
environment.systemPackages = [ pkgs.dconf ];
|
environment.systemPackages = [ pkgs.dconf ];
|
||||||
|
|
||||||
# Needed for unwrapped applications
|
# Needed for unwrapped applications
|
||||||
environment.sessionVariables.GIO_EXTRA_MODULES = mkIf cfg.enable [ "${pkgs.dconf.lib}/lib/gio/modules" ];
|
environment.variables.GIO_EXTRA_MODULES = mkIf cfg.enable [ "${pkgs.dconf.lib}/lib/gio/modules" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ in
|
||||||
type = types.nullOr (types.enum pkgs.pinentry.flavors);
|
type = types.nullOr (types.enum pkgs.pinentry.flavors);
|
||||||
example = "gnome3";
|
example = "gnome3";
|
||||||
default = defaultPinentryFlavor;
|
default = defaultPinentryFlavor;
|
||||||
|
defaultText = literalDocBook ''matching the configured desktop environment'';
|
||||||
description = ''
|
description = ''
|
||||||
Which pinentry interface to use. If not null, the path to the
|
Which pinentry interface to use. If not null, the path to the
|
||||||
pinentry binary will be passed to gpg-agent via commandline and
|
pinentry binary will be passed to gpg-agent via commandline and
|
||||||
|
|
|
@ -33,6 +33,13 @@ in
|
||||||
|
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
|
|
||||||
|
enableAskPassword = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = config.services.xserver.enable;
|
||||||
|
defaultText = literalExpression "config.services.xserver.enable";
|
||||||
|
description = "Whether to configure SSH_ASKPASS in the environment.";
|
||||||
|
};
|
||||||
|
|
||||||
askPassword = mkOption {
|
askPassword = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass";
|
default = "${pkgs.x11_ssh_askpass}/libexec/x11-ssh-askpass";
|
||||||
|
@ -287,7 +294,7 @@ in
|
||||||
# Allow ssh-agent to ask for confirmation. This requires the
|
# Allow ssh-agent to ask for confirmation. This requires the
|
||||||
# unit to know about the user's $DISPLAY (via ‘systemctl
|
# unit to know about the user's $DISPLAY (via ‘systemctl
|
||||||
# import-environment’).
|
# import-environment’).
|
||||||
environment.SSH_ASKPASS = optionalString config.services.xserver.enable askPasswordWrapper;
|
environment.SSH_ASKPASS = optionalString cfg.enableAskPassword askPasswordWrapper;
|
||||||
environment.DISPLAY = "fake"; # required to make ssh-agent start $SSH_ASKPASS
|
environment.DISPLAY = "fake"; # required to make ssh-agent start $SSH_ASKPASS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -298,7 +305,7 @@ in
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
environment.variables.SSH_ASKPASS = optionalString config.services.xserver.enable askPassword;
|
environment.variables.SSH_ASKPASS = optionalString cfg.enableAskPassword askPassword;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# This module defines global configuration for the zshell.
|
# This module defines global configuration for the zshell.
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ let
|
||||||
cfge = config.environment;
|
cfge = config.environment;
|
||||||
|
|
||||||
cfg = config.programs.zsh;
|
cfg = config.programs.zsh;
|
||||||
|
opt = options.programs.zsh;
|
||||||
|
|
||||||
zshAliases = concatStringsSep "\n" (
|
zshAliases = concatStringsSep "\n" (
|
||||||
mapAttrsFlatten (k: v: "alias ${k}=${escapeShellArg v}")
|
mapAttrsFlatten (k: v: "alias ${k}=${escapeShellArg v}")
|
||||||
|
@ -147,6 +148,7 @@ in
|
||||||
|
|
||||||
enableGlobalCompInit = mkOption {
|
enableGlobalCompInit = mkOption {
|
||||||
default = cfg.enableCompletion;
|
default = cfg.enableCompletion;
|
||||||
|
defaultText = literalExpression "config.${opt.enableCompletion}";
|
||||||
description = ''
|
description = ''
|
||||||
Enable execution of compinit call for all interactive zsh shells.
|
Enable execution of compinit call for all interactive zsh shells.
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
cfg = config.security.acme;
|
cfg = config.security.acme;
|
||||||
|
opt = options.security.acme;
|
||||||
|
|
||||||
# Used to calculate timer accuracy for coalescing
|
# Used to calculate timer accuracy for coalescing
|
||||||
numCerts = length (builtins.attrNames cfg.certs);
|
numCerts = length (builtins.attrNames cfg.certs);
|
||||||
|
@ -163,9 +164,8 @@ let
|
||||||
[ "--dns" data.dnsProvider ]
|
[ "--dns" data.dnsProvider ]
|
||||||
++ optionals (!data.dnsPropagationCheck) [ "--dns.disable-cp" ]
|
++ optionals (!data.dnsPropagationCheck) [ "--dns.disable-cp" ]
|
||||||
++ optionals (data.dnsResolver != null) [ "--dns.resolvers" data.dnsResolver ]
|
++ optionals (data.dnsResolver != null) [ "--dns.resolvers" data.dnsResolver ]
|
||||||
) else (
|
) else if data.listenHTTP != null then [ "--http" "--http.port" data.listenHTTP ]
|
||||||
[ "--http" "--http.webroot" data.webroot ]
|
else [ "--http" "--http.webroot" data.webroot ];
|
||||||
);
|
|
||||||
|
|
||||||
commonOpts = [
|
commonOpts = [
|
||||||
"--accept-tos" # Checking the option is covered by the assertions
|
"--accept-tos" # Checking the option is covered by the assertions
|
||||||
|
@ -321,11 +321,14 @@ let
|
||||||
}
|
}
|
||||||
fi
|
fi
|
||||||
'');
|
'');
|
||||||
|
} // optionalAttrs (data.listenHTTP != null && toInt (elemAt (splitString ":" data.listenHTTP) 1) < 1024) {
|
||||||
|
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Working directory will be /tmp
|
# Working directory will be /tmp
|
||||||
script = ''
|
script = ''
|
||||||
set -euxo pipefail
|
${optionalString data.enableDebugLogs "set -x"}
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
# This reimplements the expiration date check, but without querying
|
# This reimplements the expiration date check, but without querying
|
||||||
# the acme server first. By doing this offline, we avoid errors
|
# the acme server first. By doing this offline, we avoid errors
|
||||||
|
@ -438,6 +441,8 @@ let
|
||||||
default = "_mkMergedOptionModule";
|
default = "_mkMergedOptionModule";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enableDebugLogs = mkEnableOption "debug logging for this certificate" // { default = cfg.enableDebugLogs; };
|
||||||
|
|
||||||
webroot = mkOption {
|
webroot = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
|
@ -451,6 +456,17 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
listenHTTP = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
example = ":1360";
|
||||||
|
description = ''
|
||||||
|
Interface and port to listen on to solve HTTP challenges
|
||||||
|
in the form [INTERFACE]:PORT.
|
||||||
|
If you use a port other than 80, you must proxy port 80 to this port.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
server = mkOption {
|
server = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
|
@ -470,6 +486,7 @@ let
|
||||||
email = mkOption {
|
email = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = cfg.email;
|
default = cfg.email;
|
||||||
|
defaultText = literalExpression "config.${opt.email}";
|
||||||
description = "Contact email address for the CA to be able to reach you.";
|
description = "Contact email address for the CA to be able to reach you.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -616,6 +633,8 @@ in {
|
||||||
options = {
|
options = {
|
||||||
security.acme = {
|
security.acme = {
|
||||||
|
|
||||||
|
enableDebugLogs = mkEnableOption "debug logging for all certificates by default" // { default = true; };
|
||||||
|
|
||||||
validMinDays = mkOption {
|
validMinDays = mkOption {
|
||||||
type = types.int;
|
type = types.int;
|
||||||
default = 30;
|
default = 30;
|
||||||
|
@ -778,6 +797,28 @@ in {
|
||||||
`security.acme.certs.${cert}.webroot` are mutually exclusive.
|
`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.
|
||||||
|
'';
|
||||||
|
}
|
||||||
]) cfg.certs));
|
]) cfg.certs));
|
||||||
|
|
||||||
users.users.acme = {
|
users.users.acme = {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) literalExpression mkOption types;
|
||||||
cfg = config.security.dhparams;
|
cfg = config.security.dhparams;
|
||||||
|
opt = options.security.dhparams;
|
||||||
|
|
||||||
bitType = types.addCheck types.int (b: b >= 16) // {
|
bitType = types.addCheck types.int (b: b >= 16) // {
|
||||||
name = "bits";
|
name = "bits";
|
||||||
|
@ -13,6 +14,7 @@ let
|
||||||
options.bits = mkOption {
|
options.bits = mkOption {
|
||||||
type = bitType;
|
type = bitType;
|
||||||
default = cfg.defaultBitSize;
|
default = cfg.defaultBitSize;
|
||||||
|
defaultText = literalExpression "config.${opt.defaultBitSize}";
|
||||||
description = ''
|
description = ''
|
||||||
The bit size for the prime that is used during a Diffie-Hellman
|
The bit size for the prime that is used during a Diffie-Hellman
|
||||||
key exchange.
|
key exchange.
|
||||||
|
|
|
@ -295,9 +295,14 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
limits = mkOption {
|
limits = mkOption {
|
||||||
|
default = [];
|
||||||
|
type = limitsType;
|
||||||
description = ''
|
description = ''
|
||||||
Attribute set describing resource limits. Defaults to the
|
Attribute set describing resource limits. Defaults to the
|
||||||
value of <option>security.pam.loginLimits</option>.
|
value of <option>security.pam.loginLimits</option>.
|
||||||
|
The meaning of the values is explained in <citerefentry>
|
||||||
|
<refentrytitle>limits.conf</refentrytitle><manvolnum>5</manvolnum>
|
||||||
|
</citerefentry>.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -648,6 +653,51 @@ let
|
||||||
"${domain} ${type} ${item} ${toString value}\n")
|
"${domain} ${type} ${item} ${toString value}\n")
|
||||||
limits);
|
limits);
|
||||||
|
|
||||||
|
limitsType = with lib.types; listOf (submodule ({ ... }: {
|
||||||
|
options = {
|
||||||
|
domain = mkOption {
|
||||||
|
description = "Username, groupname, or wildcard this limit applies to";
|
||||||
|
example = "@wheel";
|
||||||
|
type = str;
|
||||||
|
};
|
||||||
|
|
||||||
|
type = mkOption {
|
||||||
|
description = "Type of this limit";
|
||||||
|
type = enum [ "-" "hard" "soft" ];
|
||||||
|
default = "-";
|
||||||
|
};
|
||||||
|
|
||||||
|
item = mkOption {
|
||||||
|
description = "Item this limit applies to";
|
||||||
|
type = enum [
|
||||||
|
"core"
|
||||||
|
"data"
|
||||||
|
"fsize"
|
||||||
|
"memlock"
|
||||||
|
"nofile"
|
||||||
|
"rss"
|
||||||
|
"stack"
|
||||||
|
"cpu"
|
||||||
|
"nproc"
|
||||||
|
"as"
|
||||||
|
"maxlogins"
|
||||||
|
"maxsyslogins"
|
||||||
|
"priority"
|
||||||
|
"locks"
|
||||||
|
"sigpending"
|
||||||
|
"msgqueue"
|
||||||
|
"nice"
|
||||||
|
"rtprio"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
value = mkOption {
|
||||||
|
description = "Value of this limit";
|
||||||
|
type = oneOf [ str int ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
motd = pkgs.writeText "motd" config.users.motd;
|
motd = pkgs.writeText "motd" config.users.motd;
|
||||||
|
|
||||||
makePAMService = name: service:
|
makePAMService = name: service:
|
||||||
|
@ -669,6 +719,7 @@ in
|
||||||
|
|
||||||
security.pam.loginLimits = mkOption {
|
security.pam.loginLimits = mkOption {
|
||||||
default = [];
|
default = [];
|
||||||
|
type = limitsType;
|
||||||
example =
|
example =
|
||||||
[ { domain = "ftp";
|
[ { domain = "ftp";
|
||||||
type = "hard";
|
type = "hard";
|
||||||
|
@ -688,7 +739,8 @@ in
|
||||||
<varname>domain</varname>, <varname>type</varname>,
|
<varname>domain</varname>, <varname>type</varname>,
|
||||||
<varname>item</varname>, and <varname>value</varname>
|
<varname>item</varname>, and <varname>value</varname>
|
||||||
attribute. The syntax and semantics of these attributes
|
attribute. The syntax and semantics of these attributes
|
||||||
must be that described in the limits.conf(5) man page.
|
must be that described in <citerefentry><refentrytitle>limits.conf</refentrytitle>
|
||||||
|
<manvolnum>5</manvolnum></citerefentry>.
|
||||||
|
|
||||||
Note that these limits do not apply to systemd services,
|
Note that these limits do not apply to systemd services,
|
||||||
whose limits can be changed via <option>systemd.extraConfig</option>
|
whose limits can be changed via <option>systemd.extraConfig</option>
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, utils, ... }:
|
||||||
|
|
||||||
let
|
let
|
||||||
toplevelConfig = config;
|
toplevelConfig = config;
|
||||||
inherit (lib) types;
|
inherit (lib) types;
|
||||||
inherit (import ../system/boot/systemd-lib.nix {
|
inherit (utils.systemdUtils.lib) mkPathSafeName;
|
||||||
inherit config pkgs lib;
|
|
||||||
}) mkPathSafeName;
|
|
||||||
in {
|
in {
|
||||||
options.systemd.services = lib.mkOption {
|
options.systemd.services = lib.mkOption {
|
||||||
type = types.attrsOf (types.submodule ({ name, config, ... }: {
|
type = types.attrsOf (types.submodule ({ name, config, ... }: {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.mpdscribble;
|
cfg = config.services.mpdscribble;
|
||||||
mpdCfg = config.services.mpd;
|
mpdCfg = config.services.mpd;
|
||||||
|
mpdOpt = options.services.mpd;
|
||||||
|
|
||||||
endpointUrls = {
|
endpointUrls = {
|
||||||
"last.fm" = "http://post.audioscrobbler.com";
|
"last.fm" = "http://post.audioscrobbler.com";
|
||||||
|
@ -108,6 +109,11 @@ in {
|
||||||
mpdCfg.network.listenAddress
|
mpdCfg.network.listenAddress
|
||||||
else
|
else
|
||||||
"localhost");
|
"localhost");
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
if config.${mpdOpt.network.listenAddress} != "any"
|
||||||
|
then config.${mpdOpt.network.listenAddress}
|
||||||
|
else "localhost"
|
||||||
|
'';
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = ''
|
description = ''
|
||||||
Host for the mpdscribble daemon to search for a mpd daemon on.
|
Host for the mpdscribble daemon to search for a mpd daemon on.
|
||||||
|
@ -122,6 +128,10 @@ in {
|
||||||
mpdCfg.credentials).passwordFile
|
mpdCfg.credentials).passwordFile
|
||||||
else
|
else
|
||||||
null;
|
null;
|
||||||
|
defaultText = literalDocBook ''
|
||||||
|
The first password file with read access configured for MPD when using a local instance,
|
||||||
|
otherwise <literal>null</literal>.
|
||||||
|
'';
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
description = ''
|
description = ''
|
||||||
File containing the password for the mpd daemon.
|
File containing the password for the mpd daemon.
|
||||||
|
@ -132,6 +142,7 @@ in {
|
||||||
|
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
default = mpdCfg.network.port;
|
default = mpdCfg.network.port;
|
||||||
|
defaultText = literalExpression "config.${mpdOpt.network.port}";
|
||||||
type = types.port;
|
type = types.port;
|
||||||
description = ''
|
description = ''
|
||||||
Port for the mpdscribble daemon to search for a mpd daemon on.
|
Port for the mpdscribble daemon to search for a mpd daemon on.
|
||||||
|
|
|
@ -54,12 +54,12 @@ let
|
||||||
# tcp json rpc
|
# tcp json rpc
|
||||||
++ [ "--tcp.enabled ${toString cfg.tcp.enable}" ]
|
++ [ "--tcp.enabled ${toString cfg.tcp.enable}" ]
|
||||||
++ optionals cfg.tcp.enable [
|
++ optionals cfg.tcp.enable [
|
||||||
"--tcp.address ${cfg.tcp.listenAddress}"
|
"--tcp.bind_to_address ${cfg.tcp.listenAddress}"
|
||||||
"--tcp.port ${toString cfg.tcp.port}" ]
|
"--tcp.port ${toString cfg.tcp.port}" ]
|
||||||
# http json rpc
|
# http json rpc
|
||||||
++ [ "--http.enabled ${toString cfg.http.enable}" ]
|
++ [ "--http.enabled ${toString cfg.http.enable}" ]
|
||||||
++ optionals cfg.http.enable [
|
++ optionals cfg.http.enable [
|
||||||
"--http.address ${cfg.http.listenAddress}"
|
"--http.bind_to_address ${cfg.http.listenAddress}"
|
||||||
"--http.port ${toString cfg.http.port}"
|
"--http.port ${toString cfg.http.port}"
|
||||||
] ++ optional (cfg.http.docRoot != null) "--http.doc_root \"${toString cfg.http.docRoot}\"");
|
] ++ optional (cfg.http.docRoot != null) "--http.doc_root \"${toString cfg.http.docRoot}\"");
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, utils, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
# Type for a valid systemd unit option. Needed for correctly passing "timerConfig" to "systemd.timers"
|
# Type for a valid systemd unit option. Needed for correctly passing "timerConfig" to "systemd.timers"
|
||||||
unitOption = (import ../../system/boot/systemd-unit-options.nix { inherit config lib; }).unitOption;
|
inherit (utils.systemdUtils.unitOptions) unitOption;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.restic.backups = mkOption {
|
options.services.restic.backups = mkOption {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, utils, ... }:
|
{ config, lib, options, pkgs, utils, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
gcfg = config.services.tarsnap;
|
gcfg = config.services.tarsnap;
|
||||||
|
opt = options.services.tarsnap;
|
||||||
|
|
||||||
configFile = name: cfg: ''
|
configFile = name: cfg: ''
|
||||||
keyfile ${cfg.keyfile}
|
keyfile ${cfg.keyfile}
|
||||||
|
@ -59,12 +60,13 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
archives = mkOption {
|
archives = mkOption {
|
||||||
type = types.attrsOf (types.submodule ({ config, ... }:
|
type = types.attrsOf (types.submodule ({ config, options, ... }:
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
keyfile = mkOption {
|
keyfile = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = gcfg.keyfile;
|
default = gcfg.keyfile;
|
||||||
|
defaultText = literalExpression "config.${opt.keyfile}";
|
||||||
description = ''
|
description = ''
|
||||||
Set a specific keyfile for this archive. This defaults to
|
Set a specific keyfile for this archive. This defaults to
|
||||||
<literal>"/root/tarsnap.key"</literal> if left unspecified.
|
<literal>"/root/tarsnap.key"</literal> if left unspecified.
|
||||||
|
@ -87,6 +89,9 @@ in
|
||||||
cachedir = mkOption {
|
cachedir = mkOption {
|
||||||
type = types.nullOr types.path;
|
type = types.nullOr types.path;
|
||||||
default = "/var/cache/tarsnap/${utils.escapeSystemdPath config.keyfile}";
|
default = "/var/cache/tarsnap/${utils.escapeSystemdPath config.keyfile}";
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
"/var/cache/tarsnap/''${utils.escapeSystemdPath config.${options.keyfile}}"
|
||||||
|
'';
|
||||||
description = ''
|
description = ''
|
||||||
The cache allows tarsnap to identify previously stored data
|
The cache allows tarsnap to identify previously stored data
|
||||||
blocks, reducing archival time and bandwidth usage.
|
blocks, reducing archival time and bandwidth usage.
|
||||||
|
@ -320,21 +325,22 @@ in
|
||||||
${optionalString cfg.explicitSymlinks "-H"} \
|
${optionalString cfg.explicitSymlinks "-H"} \
|
||||||
${optionalString cfg.followSymlinks "-L"} \
|
${optionalString cfg.followSymlinks "-L"} \
|
||||||
${concatStringsSep " " cfg.directories}'';
|
${concatStringsSep " " cfg.directories}'';
|
||||||
|
cachedir = escapeShellArg cfg.cachedir;
|
||||||
in if (cfg.cachedir != null) then ''
|
in if (cfg.cachedir != null) then ''
|
||||||
mkdir -p ${cfg.cachedir}
|
mkdir -p ${cachedir}
|
||||||
chmod 0700 ${cfg.cachedir}
|
chmod 0700 ${cachedir}
|
||||||
|
|
||||||
( flock 9
|
( flock 9
|
||||||
if [ ! -e ${cfg.cachedir}/firstrun ]; then
|
if [ ! -e ${cachedir}/firstrun ]; then
|
||||||
( flock 10
|
( flock 10
|
||||||
flock -u 9
|
flock -u 9
|
||||||
${tarsnap} --fsck
|
${tarsnap} --fsck
|
||||||
flock 9
|
flock 9
|
||||||
) 10>${cfg.cachedir}/firstrun
|
) 10>${cachedir}/firstrun
|
||||||
fi
|
fi
|
||||||
) 9>${cfg.cachedir}/lockf
|
) 9>${cachedir}/lockf
|
||||||
|
|
||||||
exec flock ${cfg.cachedir}/firstrun ${run}
|
exec flock ${cachedir}/firstrun ${run}
|
||||||
'' else "exec ${run}";
|
'' else "exec ${run}";
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
@ -356,22 +362,23 @@ in
|
||||||
tarsnap = ''tarsnap --configfile "/etc/tarsnap/${name}.conf"'';
|
tarsnap = ''tarsnap --configfile "/etc/tarsnap/${name}.conf"'';
|
||||||
lastArchive = "$(${tarsnap} --list-archives | sort | tail -1)";
|
lastArchive = "$(${tarsnap} --list-archives | sort | tail -1)";
|
||||||
run = ''${tarsnap} -x -f "${lastArchive}" ${optionalString cfg.verbose "-v"}'';
|
run = ''${tarsnap} -x -f "${lastArchive}" ${optionalString cfg.verbose "-v"}'';
|
||||||
|
cachedir = escapeShellArg cfg.cachedir;
|
||||||
|
|
||||||
in if (cfg.cachedir != null) then ''
|
in if (cfg.cachedir != null) then ''
|
||||||
mkdir -p ${cfg.cachedir}
|
mkdir -p ${cachedir}
|
||||||
chmod 0700 ${cfg.cachedir}
|
chmod 0700 ${cachedir}
|
||||||
|
|
||||||
( flock 9
|
( flock 9
|
||||||
if [ ! -e ${cfg.cachedir}/firstrun ]; then
|
if [ ! -e ${cachedir}/firstrun ]; then
|
||||||
( flock 10
|
( flock 10
|
||||||
flock -u 9
|
flock -u 9
|
||||||
${tarsnap} --fsck
|
${tarsnap} --fsck
|
||||||
flock 9
|
flock 9
|
||||||
) 10>${cfg.cachedir}/firstrun
|
) 10>${cachedir}/firstrun
|
||||||
fi
|
fi
|
||||||
) 9>${cfg.cachedir}/lockf
|
) 9>${cachedir}/lockf
|
||||||
|
|
||||||
exec flock ${cfg.cachedir}/firstrun ${run}
|
exec flock ${cachedir}/firstrun ${run}
|
||||||
'' else "exec ${run}";
|
'' else "exec ${run}";
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{ config, lib, pkgs, ...}:
|
{ config, lib, options, pkgs, ...}:
|
||||||
let
|
let
|
||||||
cfg = config.services.hadoop;
|
cfg = config.services.hadoop;
|
||||||
|
opt = options.services.hadoop;
|
||||||
in
|
in
|
||||||
with lib;
|
with lib;
|
||||||
{
|
{
|
||||||
|
@ -44,6 +45,14 @@ with lib;
|
||||||
"mapreduce.map.env" = "HADOOP_MAPRED_HOME=${cfg.package}/lib/${cfg.package.untarDir}";
|
"mapreduce.map.env" = "HADOOP_MAPRED_HOME=${cfg.package}/lib/${cfg.package.untarDir}";
|
||||||
"mapreduce.reduce.env" = "HADOOP_MAPRED_HOME=${cfg.package}/lib/${cfg.package.untarDir}";
|
"mapreduce.reduce.env" = "HADOOP_MAPRED_HOME=${cfg.package}/lib/${cfg.package.untarDir}";
|
||||||
};
|
};
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
{
|
||||||
|
"mapreduce.framework.name" = "yarn";
|
||||||
|
"yarn.app.mapreduce.am.env" = "HADOOP_MAPRED_HOME=''${config.${opt.package}}/lib/''${config.${opt.package}.untarDir}";
|
||||||
|
"mapreduce.map.env" = "HADOOP_MAPRED_HOME=''${config.${opt.package}}/lib/''${config.${opt.package}.untarDir}";
|
||||||
|
"mapreduce.reduce.env" = "HADOOP_MAPRED_HOME=''${config.${opt.package}}/lib/''${config.${opt.package}.untarDir}";
|
||||||
|
}
|
||||||
|
'';
|
||||||
type = types.attrsOf types.anything;
|
type = types.attrsOf types.anything;
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
options.services.hadoop.mapredSite.default // {
|
options.services.hadoop.mapredSite.default // {
|
||||||
|
@ -98,6 +107,9 @@ with lib;
|
||||||
|
|
||||||
log4jProperties = mkOption {
|
log4jProperties = mkOption {
|
||||||
default = "${cfg.package}/lib/${cfg.package.untarDir}/etc/hadoop/log4j.properties";
|
default = "${cfg.package}/lib/${cfg.package.untarDir}/etc/hadoop/log4j.properties";
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
"''${config.${opt.package}}/lib/''${config.${opt.package}.untarDir}/etc/hadoop/log4j.properties"
|
||||||
|
'';
|
||||||
type = types.path;
|
type = types.path;
|
||||||
example = literalExpression ''
|
example = literalExpression ''
|
||||||
"''${pkgs.hadoop}/lib/''${pkgs.hadoop.untarDir}/etc/hadoop/log4j.properties";
|
"''${pkgs.hadoop}/lib/''${pkgs.hadoop.untarDir}/etc/hadoop/log4j.properties";
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, options, pkgs, lib, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.kubernetes.addons.dashboard;
|
cfg = config.services.kubernetes.addons.dashboard;
|
||||||
|
opt = options.services.kubernetes.addons.dashboard;
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
(mkRenamedOptionModule [ "services" "kubernetes" "addons" "dashboard" "enableRBAC" ] [ "services" "kubernetes" "addons" "dashboard" "rbac" "enable" ])
|
(mkRenamedOptionModule [ "services" "kubernetes" "addons" "dashboard" "enableRBAC" ] [ "services" "kubernetes" "addons" "dashboard" "rbac" "enable" ])
|
||||||
|
@ -28,6 +29,9 @@ in {
|
||||||
description = "Whether to enable role based access control is enabled for kubernetes dashboard";
|
description = "Whether to enable role based access control is enabled for kubernetes dashboard";
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = elem "RBAC" config.services.kubernetes.apiserver.authorizationMode;
|
default = elem "RBAC" config.services.kubernetes.apiserver.authorizationMode;
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
elem "RBAC" config.${options.services.kubernetes.apiserver.authorizationMode}
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
clusterAdmin = mkOption {
|
clusterAdmin = mkOption {
|
||||||
|
@ -54,6 +58,14 @@ in {
|
||||||
finalImageTag = cfg.version;
|
finalImageTag = cfg.version;
|
||||||
sha256 = "01xrr4pwgr2hcjrjsi3d14ifpzdfbxzqpzxbk2fkbjb9zkv38zxy";
|
sha256 = "01xrr4pwgr2hcjrjsi3d14ifpzdfbxzqpzxbk2fkbjb9zkv38zxy";
|
||||||
};
|
};
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
{
|
||||||
|
imageName = "k8s.gcr.io/kubernetes-dashboard-amd64";
|
||||||
|
imageDigest = "sha256:0ae6b69432e78069c5ce2bcde0fe409c5c4d6f0f4d9cd50a17974fea38898747";
|
||||||
|
finalImageTag = config.${opt.version};
|
||||||
|
sha256 = "01xrr4pwgr2hcjrjsi3d14ifpzdfbxzqpzxbk2fkbjb9zkv38zxy";
|
||||||
|
};
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, options, pkgs, lib, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
|
@ -23,6 +23,10 @@ in {
|
||||||
take 3 (splitString "." config.services.kubernetes.apiserver.serviceClusterIpRange
|
take 3 (splitString "." config.services.kubernetes.apiserver.serviceClusterIpRange
|
||||||
))
|
))
|
||||||
) + ".254";
|
) + ".254";
|
||||||
|
defaultText = literalDocBook ''
|
||||||
|
The <literal>x.y.z.254</literal> IP of
|
||||||
|
<literal>config.${options.services.kubernetes.apiserver.serviceClusterIpRange}</literal>.
|
||||||
|
'';
|
||||||
type = types.str;
|
type = types.str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
top = config.services.kubernetes;
|
top = config.services.kubernetes;
|
||||||
|
otop = options.services.kubernetes;
|
||||||
cfg = top.apiserver;
|
cfg = top.apiserver;
|
||||||
|
|
||||||
isRBACEnabled = elem "RBAC" cfg.authorizationMode;
|
isRBACEnabled = elem "RBAC" cfg.authorizationMode;
|
||||||
|
@ -84,6 +85,7 @@ in
|
||||||
clientCaFile = mkOption {
|
clientCaFile = mkOption {
|
||||||
description = "Kubernetes apiserver CA file for client auth.";
|
description = "Kubernetes apiserver CA file for client auth.";
|
||||||
default = top.caFile;
|
default = top.caFile;
|
||||||
|
defaultText = literalExpression "config.${otop.caFile}";
|
||||||
type = nullOr path;
|
type = nullOr path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -138,6 +140,7 @@ in
|
||||||
caFile = mkOption {
|
caFile = mkOption {
|
||||||
description = "Etcd ca file.";
|
description = "Etcd ca file.";
|
||||||
default = top.caFile;
|
default = top.caFile;
|
||||||
|
defaultText = literalExpression "config.${otop.caFile}";
|
||||||
type = types.nullOr types.path;
|
type = types.nullOr types.path;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -157,6 +160,7 @@ in
|
||||||
featureGates = mkOption {
|
featureGates = mkOption {
|
||||||
description = "List set of feature gates";
|
description = "List set of feature gates";
|
||||||
default = top.featureGates;
|
default = top.featureGates;
|
||||||
|
defaultText = literalExpression "config.${otop.featureGates}";
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -175,6 +179,7 @@ in
|
||||||
kubeletClientCaFile = mkOption {
|
kubeletClientCaFile = mkOption {
|
||||||
description = "Path to a cert file for connecting to kubelet.";
|
description = "Path to a cert file for connecting to kubelet.";
|
||||||
default = top.caFile;
|
default = top.caFile;
|
||||||
|
defaultText = literalExpression "config.${otop.caFile}";
|
||||||
type = nullOr path;
|
type = nullOr path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
top = config.services.kubernetes;
|
top = config.services.kubernetes;
|
||||||
|
otop = options.services.kubernetes;
|
||||||
cfg = top.controllerManager;
|
cfg = top.controllerManager;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
@ -30,6 +31,7 @@ in
|
||||||
clusterCidr = mkOption {
|
clusterCidr = mkOption {
|
||||||
description = "Kubernetes CIDR Range for Pods in cluster.";
|
description = "Kubernetes CIDR Range for Pods in cluster.";
|
||||||
default = top.clusterCidr;
|
default = top.clusterCidr;
|
||||||
|
defaultText = literalExpression "config.${otop.clusterCidr}";
|
||||||
type = str;
|
type = str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,6 +46,7 @@ in
|
||||||
featureGates = mkOption {
|
featureGates = mkOption {
|
||||||
description = "List set of feature gates";
|
description = "List set of feature gates";
|
||||||
default = top.featureGates;
|
default = top.featureGates;
|
||||||
|
defaultText = literalExpression "config.${otop.featureGates}";
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,6 +70,7 @@ in
|
||||||
service account's token secret.
|
service account's token secret.
|
||||||
'';
|
'';
|
||||||
default = top.caFile;
|
default = top.caFile;
|
||||||
|
defaultText = literalExpression "config.${otop.caFile}";
|
||||||
type = nullOr path;
|
type = nullOr path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.kubernetes;
|
cfg = config.services.kubernetes;
|
||||||
|
opt = options.services.kubernetes;
|
||||||
|
|
||||||
defaultContainerdSettings = {
|
defaultContainerdSettings = {
|
||||||
version = 2;
|
version = 2;
|
||||||
|
@ -87,6 +88,7 @@ let
|
||||||
description = "${prefix} certificate authority file used to connect to kube-apiserver.";
|
description = "${prefix} certificate authority file used to connect to kube-apiserver.";
|
||||||
type = types.nullOr types.path;
|
type = types.nullOr types.path;
|
||||||
default = cfg.caFile;
|
default = cfg.caFile;
|
||||||
|
defaultText = literalExpression "config.${opt.caFile}";
|
||||||
};
|
};
|
||||||
|
|
||||||
certFile = mkOption {
|
certFile = mkOption {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
top = config.services.kubernetes;
|
top = config.services.kubernetes;
|
||||||
|
otop = options.services.kubernetes;
|
||||||
cfg = top.kubelet;
|
cfg = top.kubelet;
|
||||||
|
|
||||||
cniConfig =
|
cniConfig =
|
||||||
|
@ -35,6 +36,7 @@ let
|
||||||
key = mkOption {
|
key = mkOption {
|
||||||
description = "Key of taint.";
|
description = "Key of taint.";
|
||||||
default = name;
|
default = name;
|
||||||
|
defaultText = literalDocBook "Name of this submodule.";
|
||||||
type = str;
|
type = str;
|
||||||
};
|
};
|
||||||
value = mkOption {
|
value = mkOption {
|
||||||
|
@ -76,12 +78,14 @@ in
|
||||||
clusterDomain = mkOption {
|
clusterDomain = mkOption {
|
||||||
description = "Use alternative domain.";
|
description = "Use alternative domain.";
|
||||||
default = config.services.kubernetes.addons.dns.clusterDomain;
|
default = config.services.kubernetes.addons.dns.clusterDomain;
|
||||||
|
defaultText = literalExpression "config.${options.services.kubernetes.addons.dns.clusterDomain}";
|
||||||
type = str;
|
type = str;
|
||||||
};
|
};
|
||||||
|
|
||||||
clientCaFile = mkOption {
|
clientCaFile = mkOption {
|
||||||
description = "Kubernetes apiserver CA file for client authentication.";
|
description = "Kubernetes apiserver CA file for client authentication.";
|
||||||
default = top.caFile;
|
default = top.caFile;
|
||||||
|
defaultText = literalExpression "config.${otop.caFile}";
|
||||||
type = nullOr path;
|
type = nullOr path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -148,6 +152,7 @@ in
|
||||||
featureGates = mkOption {
|
featureGates = mkOption {
|
||||||
description = "List set of feature gates";
|
description = "List set of feature gates";
|
||||||
default = top.featureGates;
|
default = top.featureGates;
|
||||||
|
defaultText = literalExpression "config.${otop.featureGates}";
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
top = config.services.kubernetes;
|
top = config.services.kubernetes;
|
||||||
|
otop = options.services.kubernetes;
|
||||||
cfg = top.proxy;
|
cfg = top.proxy;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
@ -31,6 +32,7 @@ in
|
||||||
featureGates = mkOption {
|
featureGates = mkOption {
|
||||||
description = "List set of feature gates";
|
description = "List set of feature gates";
|
||||||
default = top.featureGates;
|
default = top.featureGates;
|
||||||
|
defaultText = literalExpression "config.${otop.featureGates}";
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
top = config.services.kubernetes;
|
top = config.services.kubernetes;
|
||||||
|
otop = options.services.kubernetes;
|
||||||
cfg = top.scheduler;
|
cfg = top.scheduler;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
@ -27,6 +28,7 @@ in
|
||||||
featureGates = mkOption {
|
featureGates = mkOption {
|
||||||
description = "List set of feature gates";
|
description = "List set of feature gates";
|
||||||
default = top.featureGates;
|
default = top.featureGates;
|
||||||
|
defaultText = literalExpression "config.${otop.featureGates}";
|
||||||
type = listOf str;
|
type = listOf str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.services.slurm;
|
cfg = config.services.slurm;
|
||||||
|
opt = options.services.slurm;
|
||||||
# configuration file can be generated by http://slurm.schedmd.com/configurator.html
|
# configuration file can be generated by http://slurm.schedmd.com/configurator.html
|
||||||
|
|
||||||
defaultUser = "slurm";
|
defaultUser = "slurm";
|
||||||
|
@ -90,6 +91,7 @@ in
|
||||||
storageUser = mkOption {
|
storageUser = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = cfg.user;
|
default = cfg.user;
|
||||||
|
defaultText = literalExpression "config.${opt.user}";
|
||||||
description = ''
|
description = ''
|
||||||
Database user name.
|
Database user name.
|
||||||
'';
|
'';
|
||||||
|
@ -154,6 +156,7 @@ in
|
||||||
controlAddr = mkOption {
|
controlAddr = mkOption {
|
||||||
type = types.nullOr types.str;
|
type = types.nullOr types.str;
|
||||||
default = cfg.controlMachine;
|
default = cfg.controlMachine;
|
||||||
|
defaultText = literalExpression "config.${opt.controlMachine}";
|
||||||
example = null;
|
example = null;
|
||||||
description = ''
|
description = ''
|
||||||
Name that ControlMachine should be referred to in establishing a
|
Name that ControlMachine should be referred to in establishing a
|
||||||
|
@ -279,6 +282,10 @@ in
|
||||||
type = types.path;
|
type = types.path;
|
||||||
internal = true;
|
internal = true;
|
||||||
default = etcSlurm;
|
default = etcSlurm;
|
||||||
|
defaultText = literalDocBook ''
|
||||||
|
Directory created from generated config files and
|
||||||
|
<literal>config.${opt.extraConfigPaths}</literal>.
|
||||||
|
'';
|
||||||
description = ''
|
description = ''
|
||||||
Path to directory with slurm config files. This option is set by default from the
|
Path to directory with slurm config files. This option is set by default from the
|
||||||
Slurm module and is meant to make the Slurm config file available to other modules.
|
Slurm module and is meant to make the Slurm config file available to other modules.
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
# NixOS module for Buildbot continous integration server.
|
# NixOS module for Buildbot continous integration server.
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.buildbot-master;
|
cfg = config.services.buildbot-master;
|
||||||
|
opt = options.services.buildbot-master;
|
||||||
|
|
||||||
python = cfg.package.pythonModule;
|
python = cfg.package.pythonModule;
|
||||||
|
|
||||||
|
@ -152,6 +153,7 @@ in {
|
||||||
|
|
||||||
buildbotDir = mkOption {
|
buildbotDir = mkOption {
|
||||||
default = "${cfg.home}/master";
|
default = "${cfg.home}/master";
|
||||||
|
defaultText = literalExpression ''"''${config.${opt.home}}/master"'';
|
||||||
type = types.path;
|
type = types.path;
|
||||||
description = "Specifies the Buildbot directory.";
|
description = "Specifies the Buildbot directory.";
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
# NixOS module for Buildbot Worker.
|
# NixOS module for Buildbot Worker.
|
||||||
|
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.buildbot-worker;
|
cfg = config.services.buildbot-worker;
|
||||||
|
opt = options.services.buildbot-worker;
|
||||||
|
|
||||||
python = cfg.package.pythonModule;
|
python = cfg.package.pythonModule;
|
||||||
|
|
||||||
|
@ -77,6 +78,7 @@ in {
|
||||||
|
|
||||||
buildbotDir = mkOption {
|
buildbotDir = mkOption {
|
||||||
default = "${cfg.home}/worker";
|
default = "${cfg.home}/worker";
|
||||||
|
defaultText = literalExpression ''"''${config.${opt.home}}/worker"'';
|
||||||
type = types.path;
|
type = types.path;
|
||||||
description = "Specifies the Buildbot directory.";
|
description = "Specifies the Buildbot directory.";
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,8 @@ let
|
||||||
stateDir = "%S/${systemdDir}";
|
stateDir = "%S/${systemdDir}";
|
||||||
# %L: Log directory root (usually /var/log); see systemd.unit(5)
|
# %L: Log directory root (usually /var/log); see systemd.unit(5)
|
||||||
logsDir = "%L/${systemdDir}";
|
logsDir = "%L/${systemdDir}";
|
||||||
|
# Name of file stored in service state directory
|
||||||
|
currentConfigTokenFilename = ".current-token";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.github-runner = {
|
options.services.github-runner = {
|
||||||
|
@ -144,13 +146,11 @@ in
|
||||||
ExecStart = "${cfg.package}/bin/runsvc.sh";
|
ExecStart = "${cfg.package}/bin/runsvc.sh";
|
||||||
|
|
||||||
# Does the following, sequentially:
|
# Does the following, sequentially:
|
||||||
# - Copy the current and the previous `tokenFile` to the $RUNTIME_DIRECTORY
|
# - If the module configuration or the token has changed, purge the state directory,
|
||||||
# and make it accessible to the service user to allow for a content
|
# and create the current and the new token file with the contents of the configured
|
||||||
# comparison.
|
# token. While both files have the same content, only the later is accessible by
|
||||||
# - If the module configuration or the token has changed, clear the state directory.
|
# the service user.
|
||||||
# - Configure the runner.
|
# - Configure the runner using the new token file. When finished, delete it.
|
||||||
# - Copy the configured `tokenFile` to the $STATE_DIRECTORY and make it
|
|
||||||
# inaccessible to the service user.
|
|
||||||
# - Set up the directory structure by creating the necessary symlinks.
|
# - Set up the directory structure by creating the necessary symlinks.
|
||||||
ExecStartPre =
|
ExecStartPre =
|
||||||
let
|
let
|
||||||
|
@ -173,37 +173,20 @@ in
|
||||||
currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json";
|
currentConfigPath = "$STATE_DIRECTORY/.nixos-current-config.json";
|
||||||
runnerRegistrationConfig = getAttrs [ "name" "tokenFile" "url" "runnerGroup" "extraLabels" ] cfg;
|
runnerRegistrationConfig = getAttrs [ "name" "tokenFile" "url" "runnerGroup" "extraLabels" ] cfg;
|
||||||
newConfigPath = builtins.toFile "${svcName}-config.json" (builtins.toJSON runnerRegistrationConfig);
|
newConfigPath = builtins.toFile "${svcName}-config.json" (builtins.toJSON runnerRegistrationConfig);
|
||||||
currentConfigTokenFilename = ".current-token";
|
|
||||||
newConfigTokenFilename = ".new-token";
|
newConfigTokenFilename = ".new-token";
|
||||||
runnerCredFiles = [
|
runnerCredFiles = [
|
||||||
".credentials"
|
".credentials"
|
||||||
".credentials_rsaparams"
|
".credentials_rsaparams"
|
||||||
".runner"
|
".runner"
|
||||||
];
|
];
|
||||||
ownConfigTokens = writeScript "own-config-tokens" ''
|
|
||||||
# Copy current and new token file to runtime dir and make it accessible to the service user
|
|
||||||
cp ${escapeShellArg cfg.tokenFile} "$RUNTIME_DIRECTORY/${newConfigTokenFilename}"
|
|
||||||
chmod 600 "$RUNTIME_DIRECTORY/${newConfigTokenFilename}"
|
|
||||||
chown "$USER" "$RUNTIME_DIRECTORY/${newConfigTokenFilename}"
|
|
||||||
|
|
||||||
if [[ -e "$STATE_DIRECTORY/${currentConfigTokenFilename}" ]]; then
|
|
||||||
cp "$STATE_DIRECTORY/${currentConfigTokenFilename}" "$RUNTIME_DIRECTORY/${currentConfigTokenFilename}"
|
|
||||||
chmod 600 "$RUNTIME_DIRECTORY/${currentConfigTokenFilename}"
|
|
||||||
chown "$USER" "$RUNTIME_DIRECTORY/${currentConfigTokenFilename}"
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
disownConfigTokens = writeScript "disown-config-tokens" ''
|
|
||||||
# Make the token inaccessible to the runner service user
|
|
||||||
chmod 600 "$STATE_DIRECTORY/${currentConfigTokenFilename}"
|
|
||||||
chown root:root "$STATE_DIRECTORY/${currentConfigTokenFilename}"
|
|
||||||
'';
|
|
||||||
unconfigureRunner = writeScript "unconfigure" ''
|
unconfigureRunner = writeScript "unconfigure" ''
|
||||||
differs=
|
differs=
|
||||||
# Set `differs = 1` if current and new runner config differ or if `currentConfigPath` does not exist
|
# Set `differs = 1` if current and new runner config differ or if `currentConfigPath` does not exist
|
||||||
${pkgs.diffutils}/bin/diff -q '${newConfigPath}' "${currentConfigPath}" >/dev/null 2>&1 || differs=1
|
${pkgs.diffutils}/bin/diff -q '${newConfigPath}' "${currentConfigPath}" >/dev/null 2>&1 || differs=1
|
||||||
# Also trigger a registration if the token content changed
|
# Also trigger a registration if the token content changed
|
||||||
${pkgs.diffutils}/bin/diff -q \
|
${pkgs.diffutils}/bin/diff -q \
|
||||||
"$RUNTIME_DIRECTORY"/{${currentConfigTokenFilename},${newConfigTokenFilename}} \
|
"$STATE_DIRECTORY"/${currentConfigTokenFilename} \
|
||||||
|
${escapeShellArg cfg.tokenFile} \
|
||||||
>/dev/null 2>&1 || differs=1
|
>/dev/null 2>&1 || differs=1
|
||||||
|
|
||||||
if [[ -n "$differs" ]]; then
|
if [[ -n "$differs" ]]; then
|
||||||
|
@ -211,13 +194,18 @@ in
|
||||||
echo "The old runner will still appear in the GitHub Actions UI." \
|
echo "The old runner will still appear in the GitHub Actions UI." \
|
||||||
"You have to remove it manually."
|
"You have to remove it manually."
|
||||||
find "$STATE_DIRECTORY/" -mindepth 1 -delete
|
find "$STATE_DIRECTORY/" -mindepth 1 -delete
|
||||||
|
|
||||||
|
# Copy the configured token file to the state dir and allow the service user to read the file
|
||||||
|
install --mode=666 ${escapeShellArg cfg.tokenFile} "$STATE_DIRECTORY/${newConfigTokenFilename}"
|
||||||
|
# Also copy current file to allow for a diff on the next start
|
||||||
|
install --mode=600 ${escapeShellArg cfg.tokenFile} "$STATE_DIRECTORY/${currentConfigTokenFilename}"
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
configureRunner = writeScript "configure" ''
|
configureRunner = writeScript "configure" ''
|
||||||
empty=$(ls -A "$STATE_DIRECTORY")
|
if [[ -e "$STATE_DIRECTORY/${newConfigTokenFilename}" ]]; then
|
||||||
if [[ -z "$empty" ]]; then
|
|
||||||
echo "Configuring GitHub Actions Runner"
|
echo "Configuring GitHub Actions Runner"
|
||||||
token=$(< "$RUNTIME_DIRECTORY"/${newConfigTokenFilename})
|
|
||||||
|
token=$(< "$STATE_DIRECTORY"/${newConfigTokenFilename})
|
||||||
RUNNER_ROOT="$STATE_DIRECTORY" ${cfg.package}/bin/config.sh \
|
RUNNER_ROOT="$STATE_DIRECTORY" ${cfg.package}/bin/config.sh \
|
||||||
--unattended \
|
--unattended \
|
||||||
--work "$RUNTIME_DIRECTORY" \
|
--work "$RUNTIME_DIRECTORY" \
|
||||||
|
@ -234,8 +222,7 @@ in
|
||||||
rm -rf "$STATE_DIRECTORY/_diag/"
|
rm -rf "$STATE_DIRECTORY/_diag/"
|
||||||
|
|
||||||
# Cleanup token from config
|
# Cleanup token from config
|
||||||
rm -f "$RUNTIME_DIRECTORY"/${currentConfigTokenFilename}
|
rm "$STATE_DIRECTORY/${newConfigTokenFilename}"
|
||||||
mv "$RUNTIME_DIRECTORY"/${newConfigTokenFilename} "$STATE_DIRECTORY/${currentConfigTokenFilename}"
|
|
||||||
|
|
||||||
# Symlink to new config
|
# Symlink to new config
|
||||||
ln -s '${newConfigPath}' "${currentConfigPath}"
|
ln -s '${newConfigPath}' "${currentConfigPath}"
|
||||||
|
@ -250,10 +237,8 @@ in
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
map (x: "${x} ${escapeShellArgs [ stateDir runtimeDir logsDir ]}") [
|
map (x: "${x} ${escapeShellArgs [ stateDir runtimeDir logsDir ]}") [
|
||||||
"+${ownConfigTokens}" # runs as root
|
"+${unconfigureRunner}" # runs as root
|
||||||
unconfigureRunner
|
|
||||||
configureRunner
|
configureRunner
|
||||||
"+${disownConfigTokens}" # runs as root
|
|
||||||
setupRuntimeDir
|
setupRuntimeDir
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -266,6 +251,13 @@ in
|
||||||
StateDirectoryMode = "0700";
|
StateDirectoryMode = "0700";
|
||||||
WorkingDirectory = runtimeDir;
|
WorkingDirectory = runtimeDir;
|
||||||
|
|
||||||
|
InaccessiblePaths = [
|
||||||
|
# Token file path given in the configuration
|
||||||
|
cfg.tokenFile
|
||||||
|
# Token file in the state directory
|
||||||
|
"${stateDir}/${currentConfigTokenFilename}"
|
||||||
|
];
|
||||||
|
|
||||||
# By default, use a dynamically allocated user
|
# By default, use a dynamically allocated user
|
||||||
DynamicUser = true;
|
DynamicUser = true;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.gocd-agent;
|
cfg = config.services.gocd-agent;
|
||||||
|
opt = options.services.gocd-agent;
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
services.gocd-agent = {
|
services.gocd-agent = {
|
||||||
|
@ -98,6 +99,15 @@ in {
|
||||||
"-Dcruise.console.publish.interval=10"
|
"-Dcruise.console.publish.interval=10"
|
||||||
"-Djava.security.egd=file:/dev/./urandom"
|
"-Djava.security.egd=file:/dev/./urandom"
|
||||||
];
|
];
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
[
|
||||||
|
"-Xms''${config.${opt.initialJavaHeapSize}}"
|
||||||
|
"-Xmx''${config.${opt.maxJavaHeapMemory}}"
|
||||||
|
"-Djava.io.tmpdir=/tmp"
|
||||||
|
"-Dcruise.console.publish.interval=10"
|
||||||
|
"-Djava.security.egd=file:/dev/./urandom"
|
||||||
|
]
|
||||||
|
'';
|
||||||
description = ''
|
description = ''
|
||||||
Specifies startup command line arguments to pass to Go.CD agent
|
Specifies startup command line arguments to pass to Go.CD agent
|
||||||
java process.
|
java process.
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.gocd-server;
|
cfg = config.services.gocd-server;
|
||||||
|
opt = options.services.gocd-server;
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
services.gocd-server = {
|
services.gocd-server = {
|
||||||
|
@ -106,6 +107,20 @@ in {
|
||||||
"-Dcruise.server.port=${toString cfg.port}"
|
"-Dcruise.server.port=${toString cfg.port}"
|
||||||
"-Dcruise.server.ssl.port=${toString cfg.sslPort}"
|
"-Dcruise.server.ssl.port=${toString cfg.sslPort}"
|
||||||
];
|
];
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
[
|
||||||
|
"-Xms''${config.${opt.initialJavaHeapSize}}"
|
||||||
|
"-Xmx''${config.${opt.maxJavaHeapMemory}}"
|
||||||
|
"-Dcruise.listen.host=''${config.${opt.listenAddress}}"
|
||||||
|
"-Duser.language=en"
|
||||||
|
"-Djruby.rack.request.size.threshold.bytes=30000000"
|
||||||
|
"-Duser.country=US"
|
||||||
|
"-Dcruise.config.dir=''${config.${opt.workDir}}/conf"
|
||||||
|
"-Dcruise.config.file=''${config.${opt.workDir}}/conf/cruise-config.xml"
|
||||||
|
"-Dcruise.server.port=''${toString config.${opt.port}}"
|
||||||
|
"-Dcruise.server.ssl.port=''${toString config.${opt.sslPort}}"
|
||||||
|
]
|
||||||
|
'';
|
||||||
|
|
||||||
description = ''
|
description = ''
|
||||||
Specifies startup command line arguments to pass to Go.CD server
|
Specifies startup command line arguments to pass to Go.CD server
|
||||||
|
|
|
@ -43,8 +43,8 @@ in {
|
||||||
|
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.couchdb;
|
default = pkgs.couchdb3;
|
||||||
defaultText = literalExpression "pkgs.couchdb";
|
defaultText = literalExpression "pkgs.couchdb3";
|
||||||
description = ''
|
description = ''
|
||||||
CouchDB package to use.
|
CouchDB package to use.
|
||||||
'';
|
'';
|
||||||
|
@ -150,6 +150,14 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
argsFile = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = "${cfg.package}/etc/vm.args";
|
||||||
|
description = ''
|
||||||
|
vm.args configuration. Overrides Couchdb's Erlang VM parameters file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
configFile = mkOption {
|
configFile = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
description = ''
|
description = ''
|
||||||
|
@ -186,12 +194,14 @@ in {
|
||||||
'';
|
'';
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
# we are actually specifying 4 configuration files:
|
# we are actually specifying 5 configuration files:
|
||||||
# 1. the preinstalled default.ini
|
# 1. the preinstalled default.ini
|
||||||
# 2. the module configuration
|
# 2. the module configuration
|
||||||
# 3. the extraConfig from the module options
|
# 3. the extraConfig from the module options
|
||||||
# 4. the locally writable config file, which couchdb itself writes to
|
# 4. the locally writable config file, which couchdb itself writes to
|
||||||
ERL_FLAGS= ''-couch_ini ${cfg.package}/etc/default.ini ${configFile} ${pkgs.writeText "couchdb-extra.ini" cfg.extraConfig} ${cfg.configFile}'';
|
ERL_FLAGS= ''-couch_ini ${cfg.package}/etc/default.ini ${configFile} ${pkgs.writeText "couchdb-extra.ini" cfg.extraConfig} ${cfg.configFile}'';
|
||||||
|
# 5. the vm.args file
|
||||||
|
COUCHDB_ARGS_FILE=''${cfg.argsFile}'';
|
||||||
};
|
};
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, options, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.hbase;
|
cfg = config.services.hbase;
|
||||||
|
opt = options.services.hbase;
|
||||||
defaultConfig = {
|
|
||||||
"hbase.rootdir" = "file://${cfg.dataDir}/hbase";
|
|
||||||
"hbase.zookeeper.property.dataDir" = "${cfg.dataDir}/zookeeper";
|
|
||||||
};
|
|
||||||
|
|
||||||
buildProperty = configAttr:
|
buildProperty = configAttr:
|
||||||
(builtins.concatStringsSep "\n"
|
(builtins.concatStringsSep "\n"
|
||||||
|
@ -23,7 +19,7 @@ let
|
||||||
|
|
||||||
configFile = pkgs.writeText "hbase-site.xml"
|
configFile = pkgs.writeText "hbase-site.xml"
|
||||||
''<configuration>
|
''<configuration>
|
||||||
${buildProperty (defaultConfig // cfg.settings)}
|
${buildProperty (opt.settings.default // cfg.settings)}
|
||||||
</configuration>
|
</configuration>
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
@ -96,7 +92,16 @@ in {
|
||||||
|
|
||||||
settings = mkOption {
|
settings = mkOption {
|
||||||
type = with lib.types; attrsOf (oneOf [ str int bool ]);
|
type = with lib.types; attrsOf (oneOf [ str int bool ]);
|
||||||
default = defaultConfig;
|
default = {
|
||||||
|
"hbase.rootdir" = "file://${cfg.dataDir}/hbase";
|
||||||
|
"hbase.zookeeper.property.dataDir" = "${cfg.dataDir}/zookeeper";
|
||||||
|
};
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
{
|
||||||
|
"hbase.rootdir" = "file://''${config.${opt.dataDir}}/hbase";
|
||||||
|
"hbase.zookeeper.property.dataDir" = "''${config.${opt.dataDir}}/zookeeper";
|
||||||
|
}
|
||||||
|
'';
|
||||||
description = ''
|
description = ''
|
||||||
configurations in hbase-site.xml, see <link xlink:href="https://github.com/apache/hbase/blob/master/hbase-server/src/test/resources/hbase-site.xml"/> for details.
|
configurations in hbase-site.xml, see <link xlink:href="https://github.com/apache/hbase/blob/master/hbase-server/src/test/resources/hbase-site.xml"/> for details.
|
||||||
'';
|
'';
|
||||||
|
|
|
@ -10,7 +10,7 @@ in
|
||||||
services.influxdb2 = {
|
services.influxdb2 = {
|
||||||
enable = mkEnableOption "the influxdb2 server";
|
enable = mkEnableOption "the influxdb2 server";
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
default = pkgs.influxdb2;
|
default = pkgs.influxdb2-server;
|
||||||
defaultText = literalExpression "pkgs.influxdb2";
|
defaultText = literalExpression "pkgs.influxdb2";
|
||||||
description = "influxdb2 derivation to use.";
|
description = "influxdb2 derivation to use.";
|
||||||
type = types.package;
|
type = types.package;
|
||||||
|
|
|
@ -4,6 +4,7 @@ with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.neo4j;
|
cfg = config.services.neo4j;
|
||||||
|
opt = options.services.neo4j;
|
||||||
certDirOpt = options.services.neo4j.directories.certificates;
|
certDirOpt = options.services.neo4j.directories.certificates;
|
||||||
isDefaultPathOption = opt: isOption opt && opt.type == types.path && opt.highestPrio >= 1500;
|
isDefaultPathOption = opt: isOption opt && opt.type == types.path && opt.highestPrio >= 1500;
|
||||||
|
|
||||||
|
@ -256,6 +257,7 @@ in {
|
||||||
certificates = mkOption {
|
certificates = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "${cfg.directories.home}/certificates";
|
default = "${cfg.directories.home}/certificates";
|
||||||
|
defaultText = literalExpression ''"''${config.${opt.directories.home}}/certificates"'';
|
||||||
description = ''
|
description = ''
|
||||||
Directory for storing certificates to be used by Neo4j for
|
Directory for storing certificates to be used by Neo4j for
|
||||||
TLS connections.
|
TLS connections.
|
||||||
|
@ -280,6 +282,7 @@ in {
|
||||||
data = mkOption {
|
data = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "${cfg.directories.home}/data";
|
default = "${cfg.directories.home}/data";
|
||||||
|
defaultText = literalExpression ''"''${config.${opt.directories.home}}/data"'';
|
||||||
description = ''
|
description = ''
|
||||||
Path of the data directory. You must not configure more than one
|
Path of the data directory. You must not configure more than one
|
||||||
Neo4j installation to use the same data directory.
|
Neo4j installation to use the same data directory.
|
||||||
|
@ -305,6 +308,7 @@ in {
|
||||||
imports = mkOption {
|
imports = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "${cfg.directories.home}/import";
|
default = "${cfg.directories.home}/import";
|
||||||
|
defaultText = literalExpression ''"''${config.${opt.directories.home}}/import"'';
|
||||||
description = ''
|
description = ''
|
||||||
The root directory for file URLs used with the Cypher
|
The root directory for file URLs used with the Cypher
|
||||||
<literal>LOAD CSV</literal> clause. Only meaningful when
|
<literal>LOAD CSV</literal> clause. Only meaningful when
|
||||||
|
@ -321,6 +325,7 @@ in {
|
||||||
plugins = mkOption {
|
plugins = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "${cfg.directories.home}/plugins";
|
default = "${cfg.directories.home}/plugins";
|
||||||
|
defaultText = literalExpression ''"''${config.${opt.directories.home}}/plugins"'';
|
||||||
description = ''
|
description = ''
|
||||||
Path of the database plugin directory. Compiled Java JAR files that
|
Path of the database plugin directory. Compiled Java JAR files that
|
||||||
contain database procedures will be loaded if they are placed in
|
contain database procedures will be loaded if they are placed in
|
||||||
|
@ -432,6 +437,7 @@ in {
|
||||||
baseDirectory = mkOption {
|
baseDirectory = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "${cfg.directories.certificates}/${name}";
|
default = "${cfg.directories.certificates}/${name}";
|
||||||
|
defaultText = literalExpression ''"''${config.${opt.directories.certificates}}/''${name}"'';
|
||||||
description = ''
|
description = ''
|
||||||
The mandatory base directory for cryptographic objects of this
|
The mandatory base directory for cryptographic objects of this
|
||||||
policy. This path is only automatically generated when this
|
policy. This path is only automatically generated when this
|
||||||
|
@ -493,6 +499,7 @@ in {
|
||||||
revokedDir = mkOption {
|
revokedDir = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "${config.baseDirectory}/revoked";
|
default = "${config.baseDirectory}/revoked";
|
||||||
|
defaultText = literalExpression ''"''${config.${options.baseDirectory}}/revoked"'';
|
||||||
description = ''
|
description = ''
|
||||||
Path to directory of CRLs (Certificate Revocation Lists) in
|
Path to directory of CRLs (Certificate Revocation Lists) in
|
||||||
PEM format. Must be an absolute path. The existence of this
|
PEM format. Must be an absolute path. The existence of this
|
||||||
|
@ -528,6 +535,7 @@ in {
|
||||||
trustedDir = mkOption {
|
trustedDir = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "${config.baseDirectory}/trusted";
|
default = "${config.baseDirectory}/trusted";
|
||||||
|
defaultText = literalExpression ''"''${config.${options.baseDirectory}}/trusted"'';
|
||||||
description = ''
|
description = ''
|
||||||
Path to directory of X.509 certificates in PEM format for
|
Path to directory of X.509 certificates in PEM format for
|
||||||
trusted parties. Must be an absolute path. The existence of this
|
trusted parties. Must be an absolute path. The existence of this
|
||||||
|
|
|
@ -289,14 +289,16 @@ in
|
||||||
port = cfg.port;
|
port = cfg.port;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.postgresql.package =
|
services.postgresql.package = let
|
||||||
|
mkThrow = ver: throw "postgresql_${ver} was removed, please upgrade your postgresql version.";
|
||||||
|
in
|
||||||
# Note: when changing the default, make it conditional on
|
# Note: when changing the default, make it conditional on
|
||||||
# ‘system.stateVersion’ to maintain compatibility with existing
|
# ‘system.stateVersion’ to maintain compatibility with existing
|
||||||
# systems!
|
# systems!
|
||||||
mkDefault (if versionAtLeast config.system.stateVersion "21.11" then pkgs.postgresql_13
|
mkDefault (if versionAtLeast config.system.stateVersion "21.11" then pkgs.postgresql_13
|
||||||
else if versionAtLeast config.system.stateVersion "20.03" then pkgs.postgresql_11
|
else if versionAtLeast config.system.stateVersion "20.03" then pkgs.postgresql_11
|
||||||
else if versionAtLeast config.system.stateVersion "17.09" then pkgs.postgresql_9_6
|
else if versionAtLeast config.system.stateVersion "17.09" then mkThrow "9_6"
|
||||||
else throw "postgresql_9_5 was removed, please upgrade your postgresql version.");
|
else mkThrow "9_5");
|
||||||
|
|
||||||
services.postgresql.dataDir = mkDefault "/var/lib/postgresql/${cfg.package.psqlSchema}";
|
services.postgresql.dataDir = mkDefault "/var/lib/postgresql/${cfg.package.psqlSchema}";
|
||||||
|
|
||||||
|
|
|
@ -52,37 +52,51 @@ Type "help" for help.
|
||||||
<section xml:id="module-services-postgres-upgrading">
|
<section xml:id="module-services-postgres-upgrading">
|
||||||
<title>Upgrading</title>
|
<title>Upgrading</title>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
The steps below demonstrate how to upgrade from an older version to <package>pkgs.postgresql_13</package>.
|
||||||
|
These instructions are also applicable to other versions.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
<para>
|
<para>
|
||||||
Major PostgreSQL upgrade requires PostgreSQL downtime and a few imperative steps to be called. To simplify this process, use the following NixOS module:
|
Major PostgreSQL upgrades require a downtime and a few imperative steps to be called. This is the case because
|
||||||
|
each major version has some internal changes in the databases' state during major releases. Because of that,
|
||||||
|
NixOS places the state into <filename>/var/lib/postgresql/<version></filename> where each <literal>version</literal>
|
||||||
|
can be obtained like this:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
containers.temp-pg.config.services.postgresql = {
|
<prompt>$ </prompt>nix-instantiate --eval -A postgresql_13.psqlSchema
|
||||||
enable = true;
|
"13"
|
||||||
package = pkgs.postgresql_12;
|
</programlisting>
|
||||||
## set a custom new dataDir
|
For an upgrade, a script like this can be used to simplify the process:
|
||||||
# dataDir = "/some/data/dir";
|
<programlisting>
|
||||||
};
|
{ config, pkgs, ... }:
|
||||||
environment.systemPackages =
|
{
|
||||||
let newpg = config.containers.temp-pg.config.services.postgresql;
|
<xref linkend="opt-environment.systemPackages" /> = [
|
||||||
in [
|
(pkgs.writeScriptBin "upgrade-pg-cluster" ''
|
||||||
(pkgs.writeScriptBin "upgrade-pg-cluster" ''
|
set -eux
|
||||||
set -x
|
# XXX it's perhaps advisable to stop all services that depend on postgresql
|
||||||
export OLDDATA="${config.services.postgresql.dataDir}"
|
systemctl stop postgresql
|
||||||
export NEWDATA="${newpg.dataDir}"
|
|
||||||
export OLDBIN="${config.services.postgresql.package}/bin"
|
|
||||||
export NEWBIN="${newpg.package}/bin"
|
|
||||||
|
|
||||||
install -d -m 0700 -o postgres -g postgres "$NEWDATA"
|
# XXX replace `<new version>` with the psqlSchema here
|
||||||
cd "$NEWDATA"
|
export NEWDATA="/var/lib/postgresql/<new version>"
|
||||||
sudo -u postgres $NEWBIN/initdb -D "$NEWDATA"
|
|
||||||
|
|
||||||
systemctl stop postgresql # old one
|
# XXX specify the postgresql package you'd like to upgrade to
|
||||||
|
export NEWBIN="${pkgs.postgresql_13}/bin"
|
||||||
|
|
||||||
sudo -u postgres $NEWBIN/pg_upgrade \
|
export OLDDATA="${config.<xref linkend="opt-services.postgresql.dataDir"/>}"
|
||||||
--old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \
|
export OLDBIN="${config.<xref linkend="opt-services.postgresql.package"/>}/bin"
|
||||||
--old-bindir $OLDBIN --new-bindir $NEWBIN \
|
|
||||||
"$@"
|
install -d -m 0700 -o postgres -g postgres "$NEWDATA"
|
||||||
'')
|
cd "$NEWDATA"
|
||||||
];
|
sudo -u postgres $NEWBIN/initdb -D "$NEWDATA"
|
||||||
|
|
||||||
|
sudo -u postgres $NEWBIN/pg_upgrade \
|
||||||
|
--old-datadir "$OLDDATA" --new-datadir "$NEWDATA" \
|
||||||
|
--old-bindir $OLDBIN --new-bindir $NEWBIN \
|
||||||
|
"$@"
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
}
|
||||||
</programlisting>
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
@ -103,17 +117,25 @@ Type "help" for help.
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Run <literal>upgrade-pg-cluster</literal>. It will stop old postgresql, initialize new one and migrate old one to new one. You may supply arguments like <literal>--jobs 4</literal> and <literal>--link</literal> to speedup migration process. See <link xlink:href="https://www.postgresql.org/docs/current/pgupgrade.html" /> for details.
|
Run <literal>upgrade-pg-cluster</literal>. It will stop old postgresql, initialize a new one and migrate the old one to the new one. You may supply arguments like <literal>--jobs 4</literal> and <literal>--link</literal> to speedup migration process. See <link xlink:href="https://www.postgresql.org/docs/current/pgupgrade.html" /> for details.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Change postgresql package in NixOS configuration to the one you were upgrading to, and change <literal>dataDir</literal> to the one you have migrated to. Rebuild NixOS. This should start new postgres using upgraded data directory.
|
Change postgresql package in NixOS configuration to the one you were upgrading to via <xref linkend="opt-services.postgresql.package" />. Rebuild NixOS. This should start new postgres using upgraded data directory and all services you stopped during the upgrade.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
After upgrade you may want to <literal>ANALYZE</literal> new db.
|
After the upgrade it's advisable to analyze the new cluster (as <literal>su -l postgres</literal> in the
|
||||||
|
<xref linkend="opt-services.postgresql.dataDir" />, in this example <filename>/var/lib/postgresql/13</filename>):
|
||||||
|
<programlisting>
|
||||||
|
<prompt>$ </prompt>./analyze_new_cluster.sh
|
||||||
|
</programlisting>
|
||||||
|
<warning><para>The next step removes the old state-directory!</para></warning>
|
||||||
|
<programlisting>
|
||||||
|
<prompt>$ </prompt>./delete_old_cluster.sh
|
||||||
|
</programlisting>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</orderedlist>
|
</orderedlist>
|
||||||
|
|
|
@ -5,17 +5,18 @@ with lib;
|
||||||
let
|
let
|
||||||
cfg = config.services.redis;
|
cfg = config.services.redis;
|
||||||
|
|
||||||
ulimitNofile = cfg.maxclients + 32;
|
|
||||||
|
|
||||||
mkValueString = value:
|
mkValueString = value:
|
||||||
if value == true then "yes"
|
if value == true then "yes"
|
||||||
else if value == false then "no"
|
else if value == false then "no"
|
||||||
else generators.mkValueStringDefault { } value;
|
else generators.mkValueStringDefault { } value;
|
||||||
|
|
||||||
redisConfig = pkgs.writeText "redis.conf" (generators.toKeyValue {
|
redisConfig = settings: pkgs.writeText "redis.conf" (generators.toKeyValue {
|
||||||
listsAsDuplicateKeys = true;
|
listsAsDuplicateKeys = true;
|
||||||
mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " ";
|
mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } " ";
|
||||||
} cfg.settings);
|
} settings);
|
||||||
|
|
||||||
|
redisName = name: "redis" + optionalString (name != "") ("-"+name);
|
||||||
|
enabledServers = filterAttrs (name: conf: conf.enable) config.services.redis.servers;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
|
@ -24,7 +25,28 @@ in {
|
||||||
(mkRemovedOptionModule [ "services" "redis" "dbFilename" ] "The redis module now uses /var/lib/redis/dump.rdb as database dump location.")
|
(mkRemovedOptionModule [ "services" "redis" "dbFilename" ] "The redis module now uses /var/lib/redis/dump.rdb as database dump location.")
|
||||||
(mkRemovedOptionModule [ "services" "redis" "appendOnlyFilename" ] "This option was never used.")
|
(mkRemovedOptionModule [ "services" "redis" "appendOnlyFilename" ] "This option was never used.")
|
||||||
(mkRemovedOptionModule [ "services" "redis" "pidFile" ] "This option was removed.")
|
(mkRemovedOptionModule [ "services" "redis" "pidFile" ] "This option was removed.")
|
||||||
(mkRemovedOptionModule [ "services" "redis" "extraConfig" ] "Use services.redis.settings instead.")
|
(mkRemovedOptionModule [ "services" "redis" "extraConfig" ] "Use services.redis.servers.*.settings instead.")
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "enable"] [ "services" "redis" "servers" "" "enable" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "port"] [ "services" "redis" "servers" "" "port" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "openFirewall"] [ "services" "redis" "servers" "" "openFirewall" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "bind"] [ "services" "redis" "servers" "" "bind" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "unixSocket"] [ "services" "redis" "servers" "" "unixSocket" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "unixSocketPerm"] [ "services" "redis" "servers" "" "unixSocketPerm" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "logLevel"] [ "services" "redis" "servers" "" "logLevel" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "logfile"] [ "services" "redis" "servers" "" "logfile" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "syslog"] [ "services" "redis" "servers" "" "syslog" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "databases"] [ "services" "redis" "servers" "" "databases" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "maxclients"] [ "services" "redis" "servers" "" "maxclients" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "save"] [ "services" "redis" "servers" "" "save" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "slaveOf"] [ "services" "redis" "servers" "" "slaveOf" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "masterAuth"] [ "services" "redis" "servers" "" "masterAuth" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "requirePass"] [ "services" "redis" "servers" "" "requirePass" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "requirePassFile"] [ "services" "redis" "servers" "" "requirePassFile" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "appendOnly"] [ "services" "redis" "servers" "" "appendOnly" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "appendFsync"] [ "services" "redis" "servers" "" "appendFsync" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "slowLogLogSlowerThan"] [ "services" "redis" "servers" "" "slowLogLogSlowerThan" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "slowLogMaxLen"] [ "services" "redis" "servers" "" "slowLogMaxLen" ])
|
||||||
|
(mkRenamedOptionModule [ "services" "redis" "settings"] [ "services" "redis" "servers" "" "settings" ])
|
||||||
];
|
];
|
||||||
|
|
||||||
###### interface
|
###### interface
|
||||||
|
@ -32,18 +54,6 @@ in {
|
||||||
options = {
|
options = {
|
||||||
|
|
||||||
services.redis = {
|
services.redis = {
|
||||||
|
|
||||||
enable = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
Whether to enable the Redis server. Note that the NixOS module for
|
|
||||||
Redis disables kernel support for Transparent Huge Pages (THP),
|
|
||||||
because this features causes major performance problems for Redis,
|
|
||||||
e.g. (https://redis.io/topics/latency).
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.redis;
|
default = pkgs.redis;
|
||||||
|
@ -51,176 +61,226 @@ in {
|
||||||
description = "Which Redis derivation to use.";
|
description = "Which Redis derivation to use.";
|
||||||
};
|
};
|
||||||
|
|
||||||
port = mkOption {
|
vmOverCommit = mkEnableOption ''
|
||||||
type = types.port;
|
setting of vm.overcommit_memory to 1
|
||||||
default = 6379;
|
(Suggested for Background Saving: http://redis.io/topics/faq)
|
||||||
description = "The port for Redis to listen to.";
|
'';
|
||||||
};
|
|
||||||
|
|
||||||
vmOverCommit = mkOption {
|
servers = mkOption {
|
||||||
type = types.bool;
|
type = with types; attrsOf (submodule ({config, name, ...}@args: {
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
Set vm.overcommit_memory to 1 (Suggested for Background Saving: http://redis.io/topics/faq)
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
openFirewall = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
Whether to open ports in the firewall for the server.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
bind = mkOption {
|
|
||||||
type = with types; nullOr str;
|
|
||||||
default = "127.0.0.1";
|
|
||||||
description = ''
|
|
||||||
The IP interface to bind to.
|
|
||||||
<literal>null</literal> means "all interfaces".
|
|
||||||
'';
|
|
||||||
example = "192.0.2.1";
|
|
||||||
};
|
|
||||||
|
|
||||||
unixSocket = mkOption {
|
|
||||||
type = with types; nullOr path;
|
|
||||||
default = null;
|
|
||||||
description = "The path to the socket to bind to.";
|
|
||||||
example = "/run/redis/redis.sock";
|
|
||||||
};
|
|
||||||
|
|
||||||
unixSocketPerm = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = 750;
|
|
||||||
description = "Change permissions for the socket";
|
|
||||||
example = 700;
|
|
||||||
};
|
|
||||||
|
|
||||||
logLevel = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "notice"; # debug, verbose, notice, warning
|
|
||||||
example = "debug";
|
|
||||||
description = "Specify the server verbosity level, options: debug, verbose, notice, warning.";
|
|
||||||
};
|
|
||||||
|
|
||||||
logfile = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "/dev/null";
|
|
||||||
description = "Specify the log file name. Also 'stdout' can be used to force Redis to log on the standard output.";
|
|
||||||
example = "/var/log/redis.log";
|
|
||||||
};
|
|
||||||
|
|
||||||
syslog = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = "Enable logging to the system logger.";
|
|
||||||
};
|
|
||||||
|
|
||||||
databases = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = 16;
|
|
||||||
description = "Set the number of databases.";
|
|
||||||
};
|
|
||||||
|
|
||||||
maxclients = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = 10000;
|
|
||||||
description = "Set the max number of connected clients at the same time.";
|
|
||||||
};
|
|
||||||
|
|
||||||
save = mkOption {
|
|
||||||
type = with types; listOf (listOf int);
|
|
||||||
default = [ [900 1] [300 10] [60 10000] ];
|
|
||||||
description = "The schedule in which data is persisted to disk, represented as a list of lists where the first element represent the amount of seconds and the second the number of changes.";
|
|
||||||
};
|
|
||||||
|
|
||||||
slaveOf = mkOption {
|
|
||||||
type = with types; nullOr (submodule ({ ... }: {
|
|
||||||
options = {
|
options = {
|
||||||
ip = mkOption {
|
enable = mkEnableOption ''
|
||||||
type = str;
|
Redis server.
|
||||||
description = "IP of the Redis master";
|
|
||||||
example = "192.168.1.100";
|
Note that the NixOS module for Redis disables kernel support
|
||||||
|
for Transparent Huge Pages (THP),
|
||||||
|
because this features causes major performance problems for Redis,
|
||||||
|
e.g. (https://redis.io/topics/latency).
|
||||||
|
'';
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = redisName name;
|
||||||
|
defaultText = "\"redis\" or \"redis-\${name}\" if name != \"\"";
|
||||||
|
description = "The username and groupname for redis-server.";
|
||||||
};
|
};
|
||||||
|
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = port;
|
type = types.port;
|
||||||
description = "port of the Redis master";
|
|
||||||
default = 6379;
|
default = 6379;
|
||||||
|
description = "The port for Redis to listen to.";
|
||||||
|
};
|
||||||
|
|
||||||
|
openFirewall = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether to open ports in the firewall for the server.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
bind = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = if name == "" then "127.0.0.1" else null;
|
||||||
|
defaultText = "127.0.0.1 or null if name != \"\"";
|
||||||
|
description = ''
|
||||||
|
The IP interface to bind to.
|
||||||
|
<literal>null</literal> means "all interfaces".
|
||||||
|
'';
|
||||||
|
example = "192.0.2.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
unixSocket = mkOption {
|
||||||
|
type = with types; nullOr path;
|
||||||
|
default = "/run/${redisName name}/redis.sock";
|
||||||
|
defaultText = "\"/run/redis/redis.sock\" or \"/run/redis-\${name}/redis.sock\" if name != \"\"";
|
||||||
|
description = "The path to the socket to bind to.";
|
||||||
|
};
|
||||||
|
|
||||||
|
unixSocketPerm = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 660;
|
||||||
|
description = "Change permissions for the socket";
|
||||||
|
example = 600;
|
||||||
|
};
|
||||||
|
|
||||||
|
logLevel = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "notice"; # debug, verbose, notice, warning
|
||||||
|
example = "debug";
|
||||||
|
description = "Specify the server verbosity level, options: debug, verbose, notice, warning.";
|
||||||
|
};
|
||||||
|
|
||||||
|
logfile = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "/dev/null";
|
||||||
|
description = "Specify the log file name. Also 'stdout' can be used to force Redis to log on the standard output.";
|
||||||
|
example = "/var/log/redis.log";
|
||||||
|
};
|
||||||
|
|
||||||
|
syslog = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Enable logging to the system logger.";
|
||||||
|
};
|
||||||
|
|
||||||
|
databases = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 16;
|
||||||
|
description = "Set the number of databases.";
|
||||||
|
};
|
||||||
|
|
||||||
|
maxclients = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 10000;
|
||||||
|
description = "Set the max number of connected clients at the same time.";
|
||||||
|
};
|
||||||
|
|
||||||
|
save = mkOption {
|
||||||
|
type = with types; listOf (listOf int);
|
||||||
|
default = [ [900 1] [300 10] [60 10000] ];
|
||||||
|
description = "The schedule in which data is persisted to disk, represented as a list of lists where the first element represent the amount of seconds and the second the number of changes.";
|
||||||
|
};
|
||||||
|
|
||||||
|
slaveOf = mkOption {
|
||||||
|
type = with types; nullOr (submodule ({ ... }: {
|
||||||
|
options = {
|
||||||
|
ip = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = "IP of the Redis master";
|
||||||
|
example = "192.168.1.100";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = port;
|
||||||
|
description = "port of the Redis master";
|
||||||
|
default = 6379;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
|
||||||
|
default = null;
|
||||||
|
description = "IP and port to which this redis instance acts as a slave.";
|
||||||
|
example = { ip = "192.168.1.100"; port = 6379; };
|
||||||
|
};
|
||||||
|
|
||||||
|
masterAuth = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = ''If the master is password protected (using the requirePass configuration)
|
||||||
|
it is possible to tell the slave to authenticate before starting the replication synchronization
|
||||||
|
process, otherwise the master will refuse the slave request.
|
||||||
|
(STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)'';
|
||||||
|
};
|
||||||
|
|
||||||
|
requirePass = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Password for database (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE).
|
||||||
|
Use requirePassFile to store it outside of the nix store in a dedicated file.
|
||||||
|
'';
|
||||||
|
example = "letmein!";
|
||||||
|
};
|
||||||
|
|
||||||
|
requirePassFile = mkOption {
|
||||||
|
type = with types; nullOr path;
|
||||||
|
default = null;
|
||||||
|
description = "File with password for the database.";
|
||||||
|
example = "/run/keys/redis-password";
|
||||||
|
};
|
||||||
|
|
||||||
|
appendOnly = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "By default data is only periodically persisted to disk, enable this option to use an append-only file for improved persistence.";
|
||||||
|
};
|
||||||
|
|
||||||
|
appendFsync = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "everysec"; # no, always, everysec
|
||||||
|
description = "How often to fsync the append-only log, options: no, always, everysec.";
|
||||||
|
};
|
||||||
|
|
||||||
|
slowLogLogSlowerThan = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 10000;
|
||||||
|
description = "Log queries whose execution take longer than X in milliseconds.";
|
||||||
|
example = 1000;
|
||||||
|
};
|
||||||
|
|
||||||
|
slowLogMaxLen = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 128;
|
||||||
|
description = "Maximum number of items to keep in slow log.";
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = mkOption {
|
||||||
|
# TODO: this should be converted to freeformType
|
||||||
|
type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
Redis configuration. Refer to
|
||||||
|
<link xlink:href="https://redis.io/topics/config"/>
|
||||||
|
for details on supported values.
|
||||||
|
'';
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
loadmodule = [ "/path/to/my_module.so" "/path/to/other_module.so" ];
|
||||||
|
}
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
config.settings = mkMerge [
|
||||||
|
{
|
||||||
|
port = if config.bind == null then 0 else config.port;
|
||||||
|
daemonize = false;
|
||||||
|
supervised = "systemd";
|
||||||
|
loglevel = config.logLevel;
|
||||||
|
logfile = config.logfile;
|
||||||
|
syslog-enabled = config.syslog;
|
||||||
|
databases = config.databases;
|
||||||
|
maxclients = config.maxclients;
|
||||||
|
save = map (d: "${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}") config.save;
|
||||||
|
dbfilename = "dump.rdb";
|
||||||
|
dir = "/var/lib/${redisName name}";
|
||||||
|
appendOnly = config.appendOnly;
|
||||||
|
appendfsync = config.appendFsync;
|
||||||
|
slowlog-log-slower-than = config.slowLogLogSlowerThan;
|
||||||
|
slowlog-max-len = config.slowLogMaxLen;
|
||||||
|
}
|
||||||
|
(mkIf (config.bind != null) { bind = config.bind; })
|
||||||
|
(mkIf (config.unixSocket != null) {
|
||||||
|
unixsocket = config.unixSocket;
|
||||||
|
unixsocketperm = toString config.unixSocketPerm;
|
||||||
|
})
|
||||||
|
(mkIf (config.slaveOf != null) { slaveof = "${config.slaveOf.ip} ${toString config.slaveOf.port}"; })
|
||||||
|
(mkIf (config.masterAuth != null) { masterauth = config.masterAuth; })
|
||||||
|
(mkIf (config.requirePass != null) { requirepass = config.requirePass; })
|
||||||
|
];
|
||||||
}));
|
}));
|
||||||
|
description = "Configuration of multiple <literal>redis-server</literal> instances.";
|
||||||
default = null;
|
|
||||||
description = "IP and port to which this redis instance acts as a slave.";
|
|
||||||
example = { ip = "192.168.1.100"; port = 6379; };
|
|
||||||
};
|
|
||||||
|
|
||||||
masterAuth = mkOption {
|
|
||||||
type = with types; nullOr str;
|
|
||||||
default = null;
|
|
||||||
description = ''If the master is password protected (using the requirePass configuration)
|
|
||||||
it is possible to tell the slave to authenticate before starting the replication synchronization
|
|
||||||
process, otherwise the master will refuse the slave request.
|
|
||||||
(STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)'';
|
|
||||||
};
|
|
||||||
|
|
||||||
requirePass = mkOption {
|
|
||||||
type = with types; nullOr str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Password for database (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE).
|
|
||||||
Use requirePassFile to store it outside of the nix store in a dedicated file.
|
|
||||||
'';
|
|
||||||
example = "letmein!";
|
|
||||||
};
|
|
||||||
|
|
||||||
requirePassFile = mkOption {
|
|
||||||
type = with types; nullOr path;
|
|
||||||
default = null;
|
|
||||||
description = "File with password for the database.";
|
|
||||||
example = "/run/keys/redis-password";
|
|
||||||
};
|
|
||||||
|
|
||||||
appendOnly = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = "By default data is only periodically persisted to disk, enable this option to use an append-only file for improved persistence.";
|
|
||||||
};
|
|
||||||
|
|
||||||
appendFsync = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "everysec"; # no, always, everysec
|
|
||||||
description = "How often to fsync the append-only log, options: no, always, everysec.";
|
|
||||||
};
|
|
||||||
|
|
||||||
slowLogLogSlowerThan = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = 10000;
|
|
||||||
description = "Log queries whose execution take longer than X in milliseconds.";
|
|
||||||
example = 1000;
|
|
||||||
};
|
|
||||||
|
|
||||||
slowLogMaxLen = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
default = 128;
|
|
||||||
description = "Maximum number of items to keep in slow log.";
|
|
||||||
};
|
|
||||||
|
|
||||||
settings = mkOption {
|
|
||||||
type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
|
|
||||||
default = {};
|
default = {};
|
||||||
description = ''
|
|
||||||
Redis configuration. Refer to
|
|
||||||
<link xlink:href="https://redis.io/topics/config"/>
|
|
||||||
for details on supported values.
|
|
||||||
'';
|
|
||||||
example = literalExpression ''
|
|
||||||
{
|
|
||||||
loadmodule = [ "/path/to/my_module.so" "/path/to/other_module.so" ];
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -229,78 +289,61 @@ in {
|
||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
|
|
||||||
config = mkIf config.services.redis.enable {
|
config = mkIf (enabledServers != {}) {
|
||||||
assertions = [{
|
|
||||||
assertion = cfg.requirePass != null -> cfg.requirePassFile == null;
|
assertions = attrValues (mapAttrs (name: conf: {
|
||||||
message = "You can only set one services.redis.requirePass or services.redis.requirePassFile";
|
assertion = conf.requirePass != null -> conf.requirePassFile == null;
|
||||||
}];
|
message = ''
|
||||||
boot.kernel.sysctl = (mkMerge [
|
You can only set one services.redis.servers.${name}.requirePass
|
||||||
|
or services.redis.servers.${name}.requirePassFile
|
||||||
|
'';
|
||||||
|
}) enabledServers);
|
||||||
|
|
||||||
|
boot.kernel.sysctl = mkMerge [
|
||||||
{ "vm.nr_hugepages" = "0"; }
|
{ "vm.nr_hugepages" = "0"; }
|
||||||
( mkIf cfg.vmOverCommit { "vm.overcommit_memory" = "1"; } )
|
( mkIf cfg.vmOverCommit { "vm.overcommit_memory" = "1"; } )
|
||||||
]);
|
];
|
||||||
|
|
||||||
networking.firewall = mkIf cfg.openFirewall {
|
networking.firewall.allowedTCPPorts = concatMap (conf:
|
||||||
allowedTCPPorts = [ cfg.port ];
|
optional conf.openFirewall conf.port
|
||||||
};
|
) (attrValues enabledServers);
|
||||||
|
|
||||||
users.users.redis = {
|
|
||||||
description = "Redis database user";
|
|
||||||
group = "redis";
|
|
||||||
isSystemUser = true;
|
|
||||||
};
|
|
||||||
users.groups.redis = {};
|
|
||||||
|
|
||||||
environment.systemPackages = [ cfg.package ];
|
environment.systemPackages = [ cfg.package ];
|
||||||
|
|
||||||
services.redis.settings = mkMerge [
|
users.users = mapAttrs' (name: conf: nameValuePair (redisName name) {
|
||||||
{
|
description = "System user for the redis-server instance ${name}";
|
||||||
port = cfg.port;
|
isSystemUser = true;
|
||||||
daemonize = false;
|
group = redisName name;
|
||||||
supervised = "systemd";
|
}) enabledServers;
|
||||||
loglevel = cfg.logLevel;
|
users.groups = mapAttrs' (name: conf: nameValuePair (redisName name) {
|
||||||
logfile = cfg.logfile;
|
}) enabledServers;
|
||||||
syslog-enabled = cfg.syslog;
|
|
||||||
databases = cfg.databases;
|
|
||||||
maxclients = cfg.maxclients;
|
|
||||||
save = map (d: "${toString (builtins.elemAt d 0)} ${toString (builtins.elemAt d 1)}") cfg.save;
|
|
||||||
dbfilename = "dump.rdb";
|
|
||||||
dir = "/var/lib/redis";
|
|
||||||
appendOnly = cfg.appendOnly;
|
|
||||||
appendfsync = cfg.appendFsync;
|
|
||||||
slowlog-log-slower-than = cfg.slowLogLogSlowerThan;
|
|
||||||
slowlog-max-len = cfg.slowLogMaxLen;
|
|
||||||
}
|
|
||||||
(mkIf (cfg.bind != null) { bind = cfg.bind; })
|
|
||||||
(mkIf (cfg.unixSocket != null) { unixsocket = cfg.unixSocket; unixsocketperm = "${toString cfg.unixSocketPerm}"; })
|
|
||||||
(mkIf (cfg.slaveOf != null) { slaveof = "${cfg.slaveOf.ip} ${toString cfg.slaveOf.port}"; })
|
|
||||||
(mkIf (cfg.masterAuth != null) { masterauth = cfg.masterAuth; })
|
|
||||||
(mkIf (cfg.requirePass != null) { requirepass = cfg.requirePass; })
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.services.redis = {
|
systemd.services = mapAttrs' (name: conf: nameValuePair (redisName name) {
|
||||||
description = "Redis Server";
|
description = "Redis Server - ${redisName name}";
|
||||||
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
|
|
||||||
preStart = ''
|
|
||||||
install -m 600 ${redisConfig} /run/redis/redis.conf
|
|
||||||
'' + optionalString (cfg.requirePassFile != null) ''
|
|
||||||
password=$(cat ${escapeShellArg cfg.requirePassFile})
|
|
||||||
echo "requirePass $password" >> /run/redis/redis.conf
|
|
||||||
'';
|
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${cfg.package}/bin/redis-server /run/redis/redis.conf";
|
ExecStart = "${cfg.package}/bin/redis-server /run/${redisName name}/redis.conf";
|
||||||
|
ExecStartPre = [("+"+pkgs.writeShellScript "${redisName name}-credentials" (''
|
||||||
|
install -o '${conf.user}' -m 600 ${redisConfig conf.settings} /run/${redisName name}/redis.conf
|
||||||
|
'' + optionalString (conf.requirePassFile != null) ''
|
||||||
|
{
|
||||||
|
printf requirePass' '
|
||||||
|
cat ${escapeShellArg conf.requirePassFile}
|
||||||
|
} >>/run/${redisName name}/redis.conf
|
||||||
|
'')
|
||||||
|
)];
|
||||||
Type = "notify";
|
Type = "notify";
|
||||||
# User and group
|
# User and group
|
||||||
User = "redis";
|
User = conf.user;
|
||||||
Group = "redis";
|
Group = conf.user;
|
||||||
# Runtime directory and mode
|
# Runtime directory and mode
|
||||||
RuntimeDirectory = "redis";
|
RuntimeDirectory = redisName name;
|
||||||
RuntimeDirectoryMode = "0750";
|
RuntimeDirectoryMode = "0750";
|
||||||
# State directory and mode
|
# State directory and mode
|
||||||
StateDirectory = "redis";
|
StateDirectory = redisName name;
|
||||||
StateDirectoryMode = "0700";
|
StateDirectoryMode = "0700";
|
||||||
# Access write directories
|
# Access write directories
|
||||||
UMask = "0077";
|
UMask = "0077";
|
||||||
|
@ -309,7 +352,7 @@ in {
|
||||||
# Security
|
# Security
|
||||||
NoNewPrivileges = true;
|
NoNewPrivileges = true;
|
||||||
# Process Properties
|
# Process Properties
|
||||||
LimitNOFILE = "${toString ulimitNofile}";
|
LimitNOFILE = mkDefault "${toString (conf.maxclients + 32)}";
|
||||||
# Sandboxing
|
# Sandboxing
|
||||||
ProtectSystem = "strict";
|
ProtectSystem = "strict";
|
||||||
ProtectHome = true;
|
ProtectHome = true;
|
||||||
|
@ -322,7 +365,9 @@ in {
|
||||||
ProtectKernelModules = true;
|
ProtectKernelModules = true;
|
||||||
ProtectKernelTunables = true;
|
ProtectKernelTunables = true;
|
||||||
ProtectControlGroups = true;
|
ProtectControlGroups = true;
|
||||||
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
|
RestrictAddressFamilies =
|
||||||
|
optionals (conf.bind != null) ["AF_INET" "AF_INET6"] ++
|
||||||
|
optional (conf.unixSocket != null) "AF_UNIX";
|
||||||
RestrictNamespaces = true;
|
RestrictNamespaces = true;
|
||||||
LockPersonality = true;
|
LockPersonality = true;
|
||||||
MemoryDenyWriteExecute = true;
|
MemoryDenyWriteExecute = true;
|
||||||
|
@ -333,6 +378,7 @@ in {
|
||||||
SystemCallArchitectures = "native";
|
SystemCallArchitectures = "native";
|
||||||
SystemCallFilter = "~@cpu-emulation @debug @keyring @memlock @mount @obsolete @privileged @resources @setuid";
|
SystemCallFilter = "~@cpu-emulation @debug @keyring @memlock @mount @obsolete @privileged @resources @setuid";
|
||||||
};
|
};
|
||||||
};
|
}) enabledServers;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ with lib;
|
||||||
|
|
||||||
systemd.packages = [ pkgs.glib-networking ];
|
systemd.packages = [ pkgs.glib-networking ];
|
||||||
|
|
||||||
environment.sessionVariables.GIO_EXTRA_MODULES = [ "${pkgs.glib-networking.out}/lib/gio/modules" ];
|
environment.variables.GIO_EXTRA_MODULES = [ "${pkgs.glib-networking.out}/lib/gio/modules" ];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ in
|
||||||
services.udev.packages = [ pkgs.libmtp.bin ];
|
services.udev.packages = [ pkgs.libmtp.bin ];
|
||||||
|
|
||||||
# Needed for unwrapped applications
|
# Needed for unwrapped applications
|
||||||
environment.sessionVariables.GIO_EXTRA_MODULES = [ "${cfg.package}/lib/gio/modules" ];
|
environment.variables.GIO_EXTRA_MODULES = [ "${cfg.package}/lib/gio/modules" ];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ in {
|
||||||
|
|
||||||
haskellPackages = mkOption {
|
haskellPackages = mkOption {
|
||||||
description = "Which haskell package set to use.";
|
description = "Which haskell package set to use.";
|
||||||
|
type = types.attrs;
|
||||||
default = pkgs.haskellPackages;
|
default = pkgs.haskellPackages;
|
||||||
defaultText = literalExpression "pkgs.haskellPackages";
|
defaultText = literalExpression "pkgs.haskellPackages";
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,6 +71,7 @@ in {
|
||||||
baseq3 = mkOption {
|
baseq3 = mkOption {
|
||||||
type = types.either types.package types.path;
|
type = types.either types.package types.path;
|
||||||
default = defaultBaseq3;
|
default = defaultBaseq3;
|
||||||
|
defaultText = literalDocBook "Manually downloaded Quake 3 installation directory.";
|
||||||
example = "/var/lib/q3ds";
|
example = "/var/lib/q3ds";
|
||||||
description = ''
|
description = ''
|
||||||
Path to the baseq3 files (pak*.pk3). If this is on the nix store (type = package) all .pk3 files should be saved
|
Path to the baseq3 files (pak*.pk3). If this is on the nix store (type = package) all .pk3 files should be saved
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, options, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.services.terraria;
|
cfg = config.services.terraria;
|
||||||
|
opt = options.services.terraria;
|
||||||
worldSizeMap = { small = 1; medium = 2; large = 3; };
|
worldSizeMap = { small = 1; medium = 2; large = 3; };
|
||||||
valFlag = name: val: optionalString (val != null) "-${name} \"${escape ["\\" "\""] (toString val)}\"";
|
valFlag = name: val: optionalString (val != null) "-${name} \"${escape ["\\" "\""] (toString val)}\"";
|
||||||
boolFlag = name: val: optionalString val "-${name}";
|
boolFlag = name: val: optionalString val "-${name}";
|
||||||
|
@ -36,7 +37,7 @@ in
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
If enabled, starts a Terraria server. The server can be connected to via <literal>tmux -S ${cfg.dataDir}/terraria.sock attach</literal>
|
If enabled, starts a Terraria server. The server can be connected to via <literal>tmux -S ''${config.${opt.dataDir}}/terraria.sock attach</literal>
|
||||||
for administration by users who are a part of the <literal>terraria</literal> group (use <literal>C-b d</literal> shortcut to detach again).
|
for administration by users who are a part of the <literal>terraria</literal> group (use <literal>C-b d</literal> shortcut to detach again).
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue