Project import generated by Copybara.

GitOrigin-RevId: 988cc958c57ce4350ec248d2d53087777f9e1949
This commit is contained in:
Default email 2023-02-22 11:55:15 +01:00
parent ffe3f91058
commit 5557ff764c
1009 changed files with 35449 additions and 25368 deletions

View file

@ -95,3 +95,9 @@ trim_trailing_whitespace = unset
[pkgs/tools/misc/timidity/timidity.cfg] [pkgs/tools/misc/timidity/timidity.cfg]
trim_trailing_whitespace = unset trim_trailing_whitespace = unset
[pkgs/tools/virtualization/ovftool/*.ova]
end_of_line = unset
insert_final_newline = unset
trim_trailing_whitespace = unset
charset = unset

View file

@ -75,7 +75,7 @@ in pkgs.runCommand "doc-support" {}
ln -s ${epub-xsl} ./epub.xsl ln -s ${epub-xsl} ./epub.xsl
ln -s ${xhtml-xsl} ./xhtml.xsl ln -s ${xhtml-xsl} ./xhtml.xsl
ln -s ${../../nixos/doc/xmlformat.conf} ./xmlformat.conf ln -s ${./xmlformat.conf} ./xmlformat.conf
ln -s ${pkgs.documentation-highlighter} ./highlightjs ln -s ${pkgs.documentation-highlighter} ./highlightjs
echo -n "${version}" > ./version echo -n "${version}" > ./version

View file

@ -137,7 +137,12 @@ set the default version to a version older than the newest on Hackage. We do
this to get them or their reverse dependencies to compile in our package set. this to get them or their reverse dependencies to compile in our package set.
4. For all packages, for which the newest Hackage version is not the default 4. For all packages, for which the newest Hackage version is not the default
version, there will also be a `haskellPackages.foo_x_y_z` package with the version, there will also be a `haskellPackages.foo_x_y_z` package with the
newest version. newest version. The `x_y_z` part encodes the version with dots replaced by
underscores. When the newest version changes by a new release to Hackage the
old package will disappear under that name and be replaced by a newer one under
the name with the new version. The package name including the version will
also disappear when the default version e.g. from Stackage catches up with the
newest version from Hackage.
5. For some packages, we also manually add other `haskellPackages.foo_x_y_z` 5. For some packages, we also manually add other `haskellPackages.foo_x_y_z`
versions, if they are required for a certain build. versions, if they are required for a certain build.
@ -161,12 +166,14 @@ given in the `.cabal` file of your package and all its dependencies.
The [Haskell builder in nixpkgs](#haskell-mkderivation) does no such thing. The [Haskell builder in nixpkgs](#haskell-mkderivation) does no such thing.
It will simply take as input packages with names off the desired dependencies It will simply take as input packages with names off the desired dependencies
and just check whether they fulfill the version bounds and (by default, see and just check whether they fulfill the version bounds and fail if they dont
`jailbreak`) fail if they dont. (by default, see `jailbreak` to circumvent this).
The package resolution is done by the `haskellPackages.callPackage` function The `haskellPackages.callPackage` function does the package resolution.
which will, e.g., use `haskellPackages.aeson` for a package input of name It will, e.g., use `haskellPackages.aeson`which has the default version as
`aeson`. described above for a package input of name `aeson`. (More general:
`<packages>.callPackage f` will call `f` with named inputs provided from the
package set `<packages>`.)
While this is the default behavior, it is possible to override the dependencies While this is the default behavior, it is possible to override the dependencies
for a specific package, see for a specific package, see
[`override` and `overrideScope`](#haskell-overriding-haskell-packages). [`override` and `overrideScope`](#haskell-overriding-haskell-packages).

View file

@ -95,6 +95,27 @@ installPhase() {
genericBuild genericBuild
``` ```
### Building a `stdenv` package in `nix-shell` {#sec-building-stdenv-package-in-nix-shell}
To build a `stdenv` package in a [`nix-shell`](https://nixos.org/manual/nix/unstable/command-ref/nix-shell.html), use
```bash
nix-shell '<nixpkgs>' -A some_package
eval ${unpackPhase:-unpackPhase}
cd $sourceRoot
eval ${patchPhase:-patchPhase}
eval ${configurePhase:-configurePhase}
eval ${buildPhase:-buildPhase}
```
To modify a [phase](#sec-stdenv-phases), first print it with
```bash
type buildPhase
```
then change it in a text editor, and paste it back to the terminal.
## Tools provided by `stdenv` {#sec-tools-of-stdenv} ## Tools provided by `stdenv` {#sec-tools-of-stdenv}
The standard environment provides the following packages: The standard environment provides the following packages:

View file

@ -337,19 +337,17 @@ rec {
# Helper functions. # Helper functions.
/* Convert an option, described as a list of the option parts in to a /* Convert an option, described as a list of the option parts to a
safe, human readable version. human-readable version.
Example: Example:
(showOption ["foo" "bar" "baz"]) == "foo.bar.baz" (showOption ["foo" "bar" "baz"]) == "foo.bar.baz"
(showOption ["foo" "bar.baz" "tux"]) == "foo.bar.baz.tux" (showOption ["foo" "bar.baz" "tux"]) == "foo.\"bar.baz\".tux"
(showOption ["windowManager" "2bwm" "enable"]) == "windowManager.\"2bwm\".enable"
Placeholders will not be quoted as they are not actual values: Placeholders will not be quoted as they are not actual values:
(showOption ["foo" "*" "bar"]) == "foo.*.bar" (showOption ["foo" "*" "bar"]) == "foo.*.bar"
(showOption ["foo" "<name>" "bar"]) == "foo.<name>.bar" (showOption ["foo" "<name>" "bar"]) == "foo.<name>.bar"
Unlike attributes, options can also start with numbers:
(showOption ["windowManager" "2bwm" "enable"]) == "windowManager.2bwm.enable"
*/ */
showOption = parts: let showOption = parts: let
escapeOptionPart = part: escapeOptionPart = part:

View file

@ -1417,6 +1417,12 @@
githubId = 12958979; githubId = 12958979;
name = "Mika Naylor"; name = "Mika Naylor";
}; };
avakhrenev = {
email = "avakhrenev@gmail.com";
github = "avakhrenev";
githubId = 1060224;
name = "Alexey Vakhrenev";
};
avaq = { avaq = {
email = "nixpkgs@account.avaq.it"; email = "nixpkgs@account.avaq.it";
github = "Avaq"; github = "Avaq";
@ -2461,6 +2467,12 @@
githubId = 3471749; githubId = 3471749;
name = "Claudio Bley"; name = "Claudio Bley";
}; };
cbrewster = {
email = "cbrewster@hey.com";
github = "cbrewster";
githubId = 9086315;
name = "Connor Brewster";
};
cburstedde = { cburstedde = {
email = "burstedde@ins.uni-bonn.de"; email = "burstedde@ins.uni-bonn.de";
github = "cburstedde"; github = "cburstedde";
@ -3398,6 +3410,12 @@
githubId = 6754950; githubId = 6754950;
name = "David Armstrong Lewis"; name = "David Armstrong Lewis";
}; };
davidcromp = {
email = "davidcrompton1192@gmail.com";
github = "DavidCromp";
githubId = 10701143;
name = "David Crompton";
};
davidrusu = { davidrusu = {
email = "davidrusu.me@gmail.com"; email = "davidrusu.me@gmail.com";
github = "davidrusu"; github = "davidrusu";
@ -3756,12 +3774,6 @@
githubId = 14034137; githubId = 14034137;
name = "Mostly Void"; name = "Mostly Void";
}; };
dizfer = {
email = "david@izquierdofernandez.com";
github = "DIzFer";
githubId = 8852888;
name = "David Izquierdo";
};
djacu = { djacu = {
email = "daniel.n.baker@gmail.com"; email = "daniel.n.baker@gmail.com";
github = "djacu"; github = "djacu";
@ -5912,6 +5924,15 @@
githubId = 41522204; githubId = 41522204;
name = "hexchen"; name = "hexchen";
}; };
heyimnova = {
email = "git@heyimnova.dev";
github = "heyimnova";
githubId = 115728866;
name = "Nova Witterick";
keys = [{
fingerprint = "4304 6B43 8D83 078E 3DF7 10D6 DEB0 E15C 6D2A 5A7C";
}];
};
hh = { hh = {
email = "hh@m-labs.hk"; email = "hh@m-labs.hk";
github = "HarryMakes"; github = "HarryMakes";
@ -7293,6 +7314,12 @@
github = "jorsn"; github = "jorsn";
githubId = 4646725; githubId = 4646725;
}; };
joshniemela = {
name = "Joshua Niemelä";
email = "josh@jniemela.dk";
github = "joshniemela";
githubId = 88747315;
};
joshuafern = { joshuafern = {
name = "Joshua Fern"; name = "Joshua Fern";
email = "joshuafern@protonmail.com"; email = "joshuafern@protonmail.com";
@ -8573,6 +8600,12 @@
githubId = 22085373; githubId = 22085373;
name = "Luis Hebendanz"; name = "Luis Hebendanz";
}; };
luizirber = {
email = "nixpkgs@luizirber.org";
github = "luizirber";
githubId = 6642;
name = "Luiz Irber";
};
luizribeiro = { luizribeiro = {
email = "nixpkgs@l9o.dev"; email = "nixpkgs@l9o.dev";
matrix = "@luizribeiro:matrix.org"; matrix = "@luizribeiro:matrix.org";
@ -9177,6 +9210,12 @@
githubId = 952712; githubId = 952712;
name = "Matt Christ"; name = "Matt Christ";
}; };
matthew-levan = {
email = "matthew@coeli.network";
github = "matthew-levan";
githubId = 91502660;
name = "Matthew LeVan";
};
matthewcroughan = { matthewcroughan = {
email = "matt@croughan.sh"; email = "matt@croughan.sh";
github = "MatthewCroughan"; github = "MatthewCroughan";
@ -11317,6 +11356,12 @@
githubId = 15645854; githubId = 15645854;
name = "Brad Christensen"; name = "Brad Christensen";
}; };
paveloom = {
email = "paveloom@riseup.net";
github = "paveloom";
githubId = 49961859;
name = "Pavel Sobolev";
};
payas = { payas = {
email = "relekarpayas@gmail.com"; email = "relekarpayas@gmail.com";
github = "bhankas"; github = "bhankas";
@ -14915,7 +14960,7 @@
}; };
toastal = { toastal = {
email = "toastal+nix@posteo.net"; email = "toastal+nix@posteo.net";
matrix = "@toastal:chat.mozilla.org"; matrix = "@toastal:mozilla.org";
github = "toastal"; github = "toastal";
githubId = 561087; githubId = 561087;
name = "toastal"; name = "toastal";

View file

@ -66,6 +66,28 @@ let
if !builtins.isList files then [ files ] else files if !builtins.isList files then [ files ] else files
); );
packageSetsWithVersionedHead = pkgs.haskell.packages // (
let
headSet = pkgs.haskell.packages.ghcHEAD;
# Determine the next GHC release version following GHC HEAD.
# GHC HEAD always has an uneven, tentative version number, e.g. 9.7.
# GHC releases always have even numbers, i.e. GHC 9.8 is branched off from
# GHC HEAD 9.7. Since we use the to be release number for GHC HEAD's
# configuration file, we need to calculate this here.
headVersion = lib.pipe headSet.ghc.version [
lib.versions.splitVersion
(lib.take 2)
lib.concatStrings
lib.strings.toInt
(builtins.add 1)
toString
];
in
{
"ghc${headVersion}" = headSet;
}
);
setsForFile = fileName: setsForFile = fileName:
let let
# extract the unique part of the config's file name # extract the unique part of the config's file name
@ -77,12 +99,12 @@ let
builtins.match "ghc-([0-9]+).([0-9]+).x" configName builtins.match "ghc-([0-9]+).([0-9]+).x" configName
); );
# return all package sets under haskell.packages matching the version components # return all package sets under haskell.packages matching the version components
setsForVersion = builtins.map (name: pkgs.haskell.packages.${name}) ( setsForVersion = builtins.map (name: packageSetsWithVersionedHead.${name}) (
builtins.filter (setName: builtins.filter (setName:
lib.hasPrefix "ghc${configVersion}" setName lib.hasPrefix "ghc${configVersion}" setName
&& (skipBinaryGHCs -> !(lib.hasInfix "Binary" setName)) && (skipBinaryGHCs -> !(lib.hasInfix "Binary" setName))
) ( ) (
builtins.attrNames pkgs.haskell.packages builtins.attrNames packageSetsWithVersionedHead
) )
); );

View file

@ -63,11 +63,13 @@ sed -r \
-e '/ lsp-test /d' \ -e '/ lsp-test /d' \
-e '/ hie-bios /d' \ -e '/ hie-bios /d' \
-e '/ ShellCheck /d' \ -e '/ ShellCheck /d' \
-e '/ Agda /d' \
< "${tmpfile_new}" >> $stackage_config < "${tmpfile_new}" >> $stackage_config
# Explanations: # Explanations:
# cabal2nix, distribution-nixpkgs, jailbreak-cabal, language-nix: These are our packages and we know what we are doing. # cabal2nix, distribution-nixpkgs, jailbreak-cabal, language-nix: These are our packages and we know what we are doing.
# lsp, lsp-types, lsp-test, hie-bios: These are tightly coupled to hls which is not in stackage. They have no rdeps in stackage. # lsp, lsp-types, lsp-test, hie-bios: These are tightly coupled to hls which is not in stackage. They have no rdeps in stackage.
# ShellCheck: latest version of command-line dev tool. # ShellCheck: latest version of command-line dev tool.
# Agda: The Agda community is fast-moving; we strive to always include the newest versions of Agda and the Agda packages in nixpkgs.
if [[ "${1:-}" == "--do-commit" ]]; then if [[ "${1:-}" == "--do-commit" ]]; then
git add $stackage_config git add $stackage_config

View file

@ -1,2 +0,0 @@
generated
manual-combined.xml

View file

@ -1,30 +0,0 @@
.PHONY: all
all: manual-combined.xml
.PHONY: debug
debug: generated manual-combined.xml
manual-combined.xml: generated *.xml **/*.xml
rm -f ./manual-combined.xml
nix-shell --pure -Q --packages xmloscopy \
--run "xmloscopy --docbook5 ./manual.xml ./manual-combined.xml"
.PHONY: format
format:
nix-shell --pure -Q --packages xmlformat \
--run "find ../../ -iname '*.xml' -type f -print0 | xargs -0 -I{} -n1 \
xmlformat --config-file '../xmlformat.conf' -i {}"
.PHONY: fix-misc-xml
fix-misc-xml:
find . -iname '*.xml' -type f \
-exec ../varlistentry-fixer.rb {} ';'
.PHONY: clean
clean:
rm -f manual-combined.xml generated
generated:
nix-build ../../release.nix \
--attr manualGeneratedSources.x86_64-linux \
--out-link ./generated

View file

@ -21,8 +21,8 @@ which is often not what you want. By contrast, in the imperative
approach, containers are configured and updated independently from the approach, containers are configured and updated independently from the
host system. host system.
```{=docbook} ```{=include=} sections
<xi:include href="imperative-containers.section.xml" /> imperative-containers.section.md
<xi:include href="declarative-containers.section.xml" /> declarative-containers.section.md
<xi:include href="container-networking.section.xml" /> container-networking.section.md
``` ```

View file

@ -0,0 +1,14 @@
# Administration {#ch-running}
This chapter describes various aspects of managing a running NixOS system, such as how to use the {command}`systemd` service manager.
```{=include=} chapters
service-mgmt.chapter.md
rebooting.chapter.md
user-sessions.chapter.md
control-groups.chapter.md
logging.chapter.md
cleaning-store.chapter.md
containers.chapter.md
troubleshooting.chapter.md
```

View file

@ -1,21 +0,0 @@
<part xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="ch-running">
<title>Administration</title>
<partintro xml:id="ch-running-intro">
<para>
This chapter describes various aspects of managing a running NixOS system,
such as how to use the <command>systemd</command> service manager.
</para>
</partintro>
<xi:include href="../from_md/administration/service-mgmt.chapter.xml" />
<xi:include href="../from_md/administration/rebooting.chapter.xml" />
<xi:include href="../from_md/administration/user-sessions.chapter.xml" />
<xi:include href="../from_md/administration/control-groups.chapter.xml" />
<xi:include href="../from_md/administration/logging.chapter.xml" />
<xi:include href="../from_md/administration/cleaning-store.chapter.xml" />
<xi:include href="../from_md/administration/containers.chapter.xml" />
<xi:include href="../from_md/administration/troubleshooting.chapter.xml" />
</part>

View file

@ -3,10 +3,10 @@
This chapter describes solutions to common problems you might encounter This chapter describes solutions to common problems you might encounter
when you manage your NixOS system. when you manage your NixOS system.
```{=docbook} ```{=include=} sections
<xi:include href="boot-problems.section.xml" /> boot-problems.section.md
<xi:include href="maintenance-mode.section.xml" /> maintenance-mode.section.md
<xi:include href="rollback.section.xml" /> rollback.section.md
<xi:include href="store-corruption.section.xml" /> store-corruption.section.md
<xi:include href="network-problems.section.xml" /> network-problems.section.md
``` ```

View file

@ -11,8 +11,8 @@ manual](https://nixos.org/nix/manual/#chap-writing-nix-expressions), but
here we give a short overview of the most important constructs useful in here we give a short overview of the most important constructs useful in
NixOS configuration files. NixOS configuration files.
```{=docbook} ```{=include=} sections
<xi:include href="config-file.section.xml" /> config-file.section.md
<xi:include href="abstractions.section.xml" /> abstractions.section.md
<xi:include href="modularity.section.xml" /> modularity.section.md
``` ```

View file

@ -0,0 +1,27 @@
# Configuration {#ch-configuration}
This chapter describes how to configure various aspects of a NixOS machine through the configuration file {file}`/etc/nixos/configuration.nix`. As described in [](#sec-changing-config), changes to this file only take effect after you run {command}`nixos-rebuild`.
```{=include=} chapters
config-syntax.chapter.md
package-mgmt.chapter.md
user-mgmt.chapter.md
file-systems.chapter.md
x-windows.chapter.md
wayland.chapter.md
gpu-accel.chapter.md
xfce.chapter.md
networking.chapter.md
linux-kernel.chapter.md
subversion.chapter.md
```
```{=include=} chapters
@MODULE_CHAPTERS@
```
```{=include=} chapters
profiles.chapter.md
kubernetes.chapter.md
```
<!-- Apache; libvirtd virtualisation -->

View file

@ -1,31 +0,0 @@
<part xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="ch-configuration">
<title>Configuration</title>
<partintro xml:id="ch-configuration-intro">
<para>
This chapter describes how to configure various aspects of a NixOS machine
through the configuration file
<filename>/etc/nixos/configuration.nix</filename>. As described in
<xref linkend="sec-changing-config" />, changes to this file only take
effect after you run <command>nixos-rebuild</command>.
</para>
</partintro>
<xi:include href="../from_md/configuration/config-syntax.chapter.xml" />
<xi:include href="../from_md/configuration/package-mgmt.chapter.xml" />
<xi:include href="../from_md/configuration/user-mgmt.chapter.xml" />
<xi:include href="../from_md/configuration/file-systems.chapter.xml" />
<xi:include href="../from_md/configuration/x-windows.chapter.xml" />
<xi:include href="../from_md/configuration/wayland.chapter.xml" />
<xi:include href="../from_md/configuration/gpu-accel.chapter.xml" />
<xi:include href="../from_md/configuration/xfce.chapter.xml" />
<xi:include href="../from_md/configuration/networking.chapter.xml" />
<xi:include href="../from_md/configuration/linux-kernel.chapter.xml" />
<xi:include href="../from_md/configuration/subversion.chapter.xml" />
<xi:include href="../generated/modules.xml" xpointer="xpointer(//section[@id='modules']/*)" />
<xi:include href="../from_md/configuration/profiles.chapter.xml" />
<xi:include href="../from_md/configuration/kubernetes.chapter.xml" />
<!-- Apache; libvirtd virtualisation -->
</part>

View file

@ -40,7 +40,7 @@ configuration use `pkgs` prefix (variable).
To "uninstall" a package, simply remove it from To "uninstall" a package, simply remove it from
[](#opt-environment.systemPackages) and run `nixos-rebuild switch`. [](#opt-environment.systemPackages) and run `nixos-rebuild switch`.
```{=docbook} ```{=include=} sections
<xi:include href="customizing-packages.section.xml" /> customizing-packages.section.md
<xi:include href="adding-custom-packages.section.xml" /> adding-custom-packages.section.md
``` ```

View file

@ -36,7 +36,7 @@ dropping you to the emergency shell. You can make a mount asynchronous
and non-critical by adding `options = [ "nofail" ];`. and non-critical by adding `options = [ "nofail" ];`.
::: :::
```{=docbook} ```{=include=} sections
<xi:include href="luks-file-systems.section.xml" /> luks-file-systems.section.md
<xi:include href="sshfs-file-systems.section.xml" /> sshfs-file-systems.section.md
``` ```

View file

@ -3,14 +3,14 @@
This section describes how to configure networking components This section describes how to configure networking components
on your NixOS machine. on your NixOS machine.
```{=docbook} ```{=include=} sections
<xi:include href="network-manager.section.xml" /> network-manager.section.md
<xi:include href="ssh.section.xml" /> ssh.section.md
<xi:include href="ipv4-config.section.xml" /> ipv4-config.section.md
<xi:include href="ipv6-config.section.xml" /> ipv6-config.section.md
<xi:include href="firewall.section.xml" /> firewall.section.md
<xi:include href="wireless.section.xml" /> wireless.section.md
<xi:include href="ad-hoc-network-config.section.xml" /> ad-hoc-network-config.section.md
<xi:include href="renaming-interfaces.section.xml" /> renaming-interfaces.section.md
``` ```
<!-- TODO: OpenVPN, NAT --> <!-- TODO: OpenVPN, NAT -->

View file

@ -12,7 +12,7 @@ NixOS has two distinct styles of package management:
`nix-env` command. This style allows mixing packages from different `nix-env` command. This style allows mixing packages from different
Nixpkgs versions. It's the only choice for non-root users. Nixpkgs versions. It's the only choice for non-root users.
```{=docbook} ```{=include=} sections
<xi:include href="declarative-packages.section.xml" /> declarative-packages.section.md
<xi:include href="ad-hoc-packages.section.xml" /> ad-hoc-packages.section.md
``` ```

View file

@ -19,16 +19,16 @@ install media, many are actually intended to be used in real installs.
What follows is a brief explanation on the purpose and use-case for each What follows is a brief explanation on the purpose and use-case for each
profile. Detailing each option configured by each one is out of scope. profile. Detailing each option configured by each one is out of scope.
```{=docbook} ```{=include=} sections
<xi:include href="profiles/all-hardware.section.xml" /> profiles/all-hardware.section.md
<xi:include href="profiles/base.section.xml" /> profiles/base.section.md
<xi:include href="profiles/clone-config.section.xml" /> profiles/clone-config.section.md
<xi:include href="profiles/demo.section.xml" /> profiles/demo.section.md
<xi:include href="profiles/docker-container.section.xml" /> profiles/docker-container.section.md
<xi:include href="profiles/graphical.section.xml" /> profiles/graphical.section.md
<xi:include href="profiles/hardened.section.xml" /> profiles/hardened.section.md
<xi:include href="profiles/headless.section.xml" /> profiles/headless.section.md
<xi:include href="profiles/installation-device.section.xml" /> profiles/installation-device.section.md
<xi:include href="profiles/minimal.section.xml" /> profiles/minimal.section.md
<xi:include href="profiles/qemu-guest.section.xml" /> profiles/qemu-guest.section.md
``` ```

View file

@ -68,56 +68,6 @@ let
optionIdPrefix = "test-opt-"; optionIdPrefix = "test-opt-";
}; };
sources = runCommand "manual-sources" {
inputs = lib.sourceFilesBySuffices ./. [ ".xml" ".md" ];
nativeBuildInputs = [ pkgs.nixos-render-docs ];
} ''
mkdir $out
cd $out
cp -r --no-preserve=all $inputs/* .
declare -a convert_args
while read -r mf; do
if [[ "$mf" = *.chapter.md ]]; then
convert_args+=("--chapter")
else
convert_args+=("--section")
fi
convert_args+=("from_md/''${mf%.md}.xml" "$mf")
done < <(find . -type f -name '*.md')
nixos-render-docs manual docbook-fragment \
--manpage-urls ${manpageUrls} \
"''${convert_args[@]}"
'';
modulesDoc = runCommand "modules.xml" {
nativeBuildInputs = [ pkgs.nixos-render-docs ];
} ''
nixos-render-docs manual docbook-section \
--manpage-urls ${manpageUrls} \
"$out" \
--section \
--section-id modules \
--chapters ${lib.concatMapStrings (p: "${p.value} ") config.meta.doc}
'';
generatedSources = runCommand "generated-docbook" {} ''
mkdir $out
ln -s ${modulesDoc} $out/modules.xml
ln -s ${optionsDoc.optionsDocBook} $out/options-db.xml
ln -s ${testOptionsDoc.optionsDocBook} $out/test-options-db.xml
printf "%s" "${version}" > $out/version
'';
copySources =
''
cp -prd $sources/* . # */
ln -s ${generatedSources} ./generated
chmod -R u+w .
'';
toc = builtins.toFile "toc.xml" toc = builtins.toFile "toc.xml"
'' ''
<toc role="chunk-toc"> <toc role="chunk-toc">
@ -148,70 +98,102 @@ let
"--stringparam chunk.toc ${toc}" "--stringparam chunk.toc ${toc}"
]; ];
linterFunctions = ''
# outputs the context of an xmllint error output
# LEN lines around the failing line are printed
function context {
# length of context
local LEN=6
# lines to print before error line
local BEFORE=4
# xmllint output lines are:
# file.xml:1234: there was an error on line 1234
while IFS=':' read -r file line rest; do
echo
if [[ -n "$rest" ]]; then
echo "$file:$line:$rest"
local FROM=$(($line>$BEFORE ? $line - $BEFORE : 1))
# number lines & filter context
nl --body-numbering=a "$file" | sed -n "$FROM,+$LEN p"
else
if [[ -n "$line" ]]; then
echo "$file:$line"
else
echo "$file"
fi
fi
done
}
function lintrng {
xmllint --debug --noout --nonet \
--relaxng ${docbook5}/xml/rng/docbook/docbook.rng \
"$1" \
2>&1 | context 1>&2
# ^ redirect assumes xmllint doesnt print to stdout
}
'';
manual-combined = runCommand "nixos-manual-combined" manual-combined = runCommand "nixos-manual-combined"
{ inherit sources; { inputs = lib.sourceFilesBySuffices ./. [ ".xml" ".md" ];
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ]; nativeBuildInputs = [ pkgs.nixos-render-docs pkgs.libxml2.bin pkgs.libxslt.bin ];
meta.description = "The NixOS manual as plain docbook XML"; meta.description = "The NixOS manual as plain docbook XML";
} }
'' ''
${copySources} cp -r --no-preserve=all $inputs/* .
xmllint --xinclude --output ./manual-combined.xml ./manual.xml substituteInPlace ./manual.md \
xmllint --xinclude --noxincludenode \ --replace '@NIXOS_VERSION@' "${version}"
--output ./man-pages-combined.xml ./man-pages.xml substituteInPlace ./configuration/configuration.md \
--replace \
'@MODULE_CHAPTERS@' \
${lib.escapeShellArg (lib.concatMapStringsSep "\n" (p: "${p.value}") config.meta.doc)}
substituteInPlace ./nixos-options.md \
--replace \
'@NIXOS_OPTIONS_JSON@' \
${optionsDoc.optionsJSON}/share/doc/nixos/options.json
substituteInPlace ./development/writing-nixos-tests.section.md \
--replace \
'@NIXOS_TEST_OPTIONS_JSON@' \
${testOptionsDoc.optionsJSON}/share/doc/nixos/options.json
# outputs the context of an xmllint error output nixos-render-docs -j $NIX_BUILD_CORES manual docbook \
# LEN lines around the failing line are printed --manpage-urls ${manpageUrls} \
function context { --revision ${lib.escapeShellArg revision} \
# length of context ./manual.md \
local LEN=6 ./manual-combined.xml
# lines to print before error line
local BEFORE=4
# xmllint output lines are: ${linterFunctions}
# file.xml:1234: there was an error on line 1234
while IFS=':' read -r file line rest; do
echo
if [[ -n "$rest" ]]; then
echo "$file:$line:$rest"
local FROM=$(($line>$BEFORE ? $line - $BEFORE : 1))
# number lines & filter context
nl --body-numbering=a "$file" | sed -n "$FROM,+$LEN p"
else
if [[ -n "$line" ]]; then
echo "$file:$line"
else
echo "$file"
fi
fi
done
}
function lintrng {
xmllint --debug --noout --nonet \
--relaxng ${docbook5}/xml/rng/docbook/docbook.rng \
"$1" \
2>&1 | context 1>&2
# ^ redirect assumes xmllint doesnt print to stdout
}
mkdir $out mkdir $out
cp manual-combined.xml $out/ cp manual-combined.xml $out/
cp man-pages-combined.xml $out/
lintrng $out/manual-combined.xml lintrng $out/manual-combined.xml
lintrng $out/man-pages-combined.xml '';
manpages-combined = runCommand "nixos-manpages-combined.xml"
{ nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
meta.description = "The NixOS manpages as plain docbook XML";
}
''
mkdir generated
cp -prd ${./man-pages.xml} man-pages.xml
ln -s ${optionsDoc.optionsDocBook} generated/options-db.xml
xmllint --xinclude --noxincludenode --output $out ./man-pages.xml
${linterFunctions}
lintrng $out
''; '';
in rec { in rec {
inherit generatedSources;
inherit (optionsDoc) optionsJSON optionsNix optionsDocBook optionsUsedDocbook; inherit (optionsDoc) optionsJSON optionsNix optionsDocBook optionsUsedDocbook;
# Generate the NixOS manual. # Generate the NixOS manual.
manualHTML = runCommand "nixos-manual-html" manualHTML = runCommand "nixos-manual-html"
{ inherit sources; { nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin ];
meta.description = "The NixOS manual in HTML format"; meta.description = "The NixOS manual in HTML format";
allowedReferences = ["out"]; allowedReferences = ["out"];
} }
@ -248,8 +230,7 @@ in rec {
manualHTMLIndex = "${manualHTML}/share/doc/nixos/index.html"; manualHTMLIndex = "${manualHTML}/share/doc/nixos/index.html";
manualEpub = runCommand "nixos-manual-epub" manualEpub = runCommand "nixos-manual-epub"
{ inherit sources; { nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin buildPackages.zip ];
nativeBuildInputs = [ buildPackages.libxml2.bin buildPackages.libxslt.bin buildPackages.zip ];
} }
'' ''
# Generate the epub manual. # Generate the epub manual.
@ -300,11 +281,11 @@ in rec {
--param man.endnotes.are.numbered 0 \ --param man.endnotes.are.numbered 0 \
--param man.break.after.slash 1 \ --param man.break.after.slash 1 \
${docbook_xsl_ns}/xml/xsl/docbook/manpages/docbook.xsl \ ${docbook_xsl_ns}/xml/xsl/docbook/manpages/docbook.xsl \
${manual-combined}/man-pages-combined.xml ${manpages-combined}
'' ''
else '' else ''
mkdir -p $out/share/man/man5 mkdir -p $out/share/man/man5
nixos-render-docs options manpage \ nixos-render-docs -j $NIX_BUILD_CORES options manpage \
--revision ${lib.escapeShellArg revision} \ --revision ${lib.escapeShellArg revision} \
${optionsJSON}/share/doc/nixos/options.json \ ${optionsJSON}/share/doc/nixos/options.json \
$out/share/man/man5/configuration.nix.5 $out/share/man/man5/configuration.nix.5

View file

@ -0,0 +1,43 @@
# Developing the NixOS Test Driver {#chap-developing-the-test-driver}
The NixOS test framework is a project of its own.
It consists of roughly the following components:
- `nixos/lib/test-driver`: The Python framework that sets up the test and runs the [`testScript`](#test-opt-testScript)
- `nixos/lib/testing`: The Nix code responsible for the wiring, written using the (NixOS) Module System.
These components are exposed publicly through:
- `nixos/lib/default.nix`: The public interface that exposes the `nixos/lib/testing` entrypoint.
- `flake.nix`: Exposes the `lib.nixos`, including the public test interface.
Beyond the test driver itself, its integration into NixOS and Nixpkgs is important.
- `pkgs/top-level/all-packages.nix`: Defines the `nixosTests` attribute, used
by the package `tests` attributes and OfBorg.
- `nixos/release.nix`: Defines the `tests` attribute built by Hydra, independently, but analogous to `nixosTests`
- `nixos/release-combined.nix`: Defines which tests are channel blockers.
Finally, we have legacy entrypoints that users should move away from, but are cared for on a best effort basis.
These include `pkgs.nixosTest`, `testing-python.nix` and `make-test-python.nix`.
## Testing changes to the test framework {#sec-test-the-test-framework}
When making significant changes to the test framework, we run the tests on Hydra, to avoid disrupting the larger NixOS project.
For this, we use the `python-test-refactoring` branch in the `NixOS/nixpkgs` repository, and its [corresponding Hydra jobset](https://hydra.nixos.org/jobset/nixos/python-test-refactoring).
This branch is used as a pointer, and not as a feature branch.
1. Rebase the PR onto a recent, good evaluation of `nixos-unstable`
2. Create a baseline evaluation by force-pushing this revision of `nixos-unstable` to `python-test-refactoring`.
3. Note the evaluation number (we'll call it `<previous>`)
4. Push the PR to `python-test-refactoring` and evaluate the PR on Hydra
5. Create a comparison URL by navigating to the latest build of the PR and adding to the URL `?compare=<previous>`. This is not necessary for the evaluation that comes right after the baseline.
Review the removed tests and newly failed tests using the constructed URL; otherwise you will accidentally compare iterations of the PR instead of changes to the PR base.
As we currently have some flaky tests, newly failing tests are expected, but should be reviewed to make sure that
- The number of failures did not increase significantly.
- All failures that do occur can reasonably be assumed to fail for a different reason than the changes.

View file

@ -0,0 +1,15 @@
# Development {#ch-development}
This chapter describes how you can modify and extend NixOS.
```{=include=} chapters
sources.chapter.md
writing-modules.chapter.md
building-parts.chapter.md
bootspec.chapter.md
what-happens-during-a-system-switch.chapter.md
writing-documentation.chapter.md
nixos-tests.chapter.md
developing-the-test-driver.chapter.md
testing-installer.chapter.md
```

View file

@ -1,20 +0,0 @@
<part xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="ch-development">
<title>Development</title>
<partintro xml:id="ch-development-intro">
<para>
This chapter describes how you can modify and extend NixOS.
</para>
</partintro>
<xi:include href="../from_md/development/sources.chapter.xml" />
<xi:include href="../from_md/development/writing-modules.chapter.xml" />
<xi:include href="../from_md/development/building-parts.chapter.xml" />
<xi:include href="../from_md/development/bootspec.chapter.xml" />
<xi:include href="../from_md/development/what-happens-during-a-system-switch.chapter.xml" />
<xi:include href="../from_md/development/writing-documentation.chapter.xml" />
<xi:include href="../from_md/development/nixos-tests.chapter.xml" />
<xi:include href="../from_md/development/testing-installer.chapter.xml" />
</part>

View file

@ -5,9 +5,9 @@ NixOS tests are kept in the directory `nixos/tests`, and are executed
(using Nix) by a testing framework that automatically starts one or more (using Nix) by a testing framework that automatically starts one or more
virtual machines containing the NixOS system(s) required for the test. virtual machines containing the NixOS system(s) required for the test.
```{=docbook} ```{=include=} sections
<xi:include href="writing-nixos-tests.section.xml" /> writing-nixos-tests.section.md
<xi:include href="running-nixos-tests.section.xml" /> running-nixos-tests.section.md
<xi:include href="running-nixos-tests-interactively.section.xml" /> running-nixos-tests-interactively.section.md
<xi:include href="linking-nixos-tests-to-packages.section.xml" /> linking-nixos-tests-to-packages.section.md
``` ```

View file

@ -47,7 +47,7 @@ Most of these actions are either self-explaining but some of them have to do
with our units or the activation script. For this reason, these topics are with our units or the activation script. For this reason, these topics are
explained in the next sections. explained in the next sections.
```{=docbook} ```{=include=} sections
<xi:include href="unit-handling.section.xml" /> unit-handling.section.md
<xi:include href="activation-script.section.xml" /> activation-script.section.md
``` ```

View file

@ -83,7 +83,7 @@ Keep the following guidelines in mind when you create and add a topic:
## Adding a Topic to the Book {#sec-writing-docs-adding-a-topic} ## Adding a Topic to the Book {#sec-writing-docs-adding-a-topic}
Open the parent XML file and add an `xi:include` element to the list of Open the parent CommonMark file and add a line to the list of
chapters with the file name of the topic that you created. If you chapters with the file name of the topic that you created. If you
created a `section`, you add the file to the `chapter` file. If you created created a `section`, you add the file to the `chapter` file. If you created
a `chapter`, you add the file to the `part` file. a `chapter`, you add the file to the `part` file.

View file

@ -189,14 +189,14 @@ in {
``` ```
::: :::
```{=docbook} ```{=include=} sections
<xi:include href="option-declarations.section.xml" /> option-declarations.section.md
<xi:include href="option-types.section.xml" /> option-types.section.md
<xi:include href="option-def.section.xml" /> option-def.section.md
<xi:include href="assertions.section.xml" /> assertions.section.md
<xi:include href="meta-attributes.section.xml" /> meta-attributes.section.md
<xi:include href="importing-modules.section.xml" /> importing-modules.section.md
<xi:include href="replace-modules.section.xml" /> replace-modules.section.md
<xi:include href="freeform-modules.section.xml" /> freeform-modules.section.md
<xi:include href="settings-options.section.xml" /> settings-options.section.md
``` ```

View file

@ -470,6 +470,8 @@ In that case, `numpy` is chosen from the generic `python3Packages`.
The following options can be used when writing tests. The following options can be used when writing tests.
```{=docbook} ```{=include=} options
<xi:include href="../../generated/test-options-db.xml" xpointer="test-options-list"/> id-prefix: test-opt-
list-id: test-options-list
source: @NIXOS_TEST_OPTIONS_JSON@
``` ```

View file

@ -0,0 +1,11 @@
# Installation {#ch-installation}
This section describes how to obtain, install, and configure NixOS for first-time use.
```{=include=} chapters
obtaining.chapter.md
installing.chapter.md
changing-config.chapter.md
upgrading.chapter.md
building-nixos.chapter.md
```

View file

@ -1,18 +0,0 @@
<part xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="ch-installation">
<title>Installation</title>
<partintro xml:id="ch-installation-intro">
<para>
This section describes how to obtain, install, and configure NixOS for
first-time use.
</para>
</partintro>
<xi:include href="../from_md/installation/obtaining.chapter.xml" />
<xi:include href="../from_md/installation/installing.chapter.xml" />
<xi:include href="../from_md/installation/changing-config.chapter.xml" />
<xi:include href="../from_md/installation/upgrading.chapter.xml" />
<xi:include href="../from_md/installation/building-nixos.chapter.xml" />
</part>

View file

@ -602,11 +602,11 @@ With a partitioned disk.
## Additional installation notes {#sec-installation-additional-notes} ## Additional installation notes {#sec-installation-additional-notes}
```{=docbook} ```{=include=} sections
<xi:include href="installing-usb.section.xml" /> installing-usb.section.md
<xi:include href="installing-pxe.section.xml" /> installing-pxe.section.md
<xi:include href="installing-kexec.section.xml" /> installing-kexec.section.md
<xi:include href="installing-virtualbox-guest.section.xml" /> installing-virtualbox-guest.section.md
<xi:include href="installing-from-other-distro.section.xml" /> installing-from-other-distro.section.md
<xi:include href="installing-behind-a-proxy.section.xml" /> installing-behind-a-proxy.section.md
``` ```

View file

@ -1,31 +0,0 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle><filename>configuration.nix</filename>
</refentrytitle><manvolnum>5</manvolnum>
<refmiscinfo class="source">NixOS</refmiscinfo>
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
</refmeta>
<refnamediv>
<refname><filename>configuration.nix</filename></refname>
<refpurpose>NixOS system configuration specification</refpurpose>
</refnamediv>
<refsection>
<title>Description</title>
<para>
The file <filename>/etc/nixos/configuration.nix</filename> contains the
declarative specification of your NixOS system configuration. The command
<command>nixos-rebuild</command> takes this file and realises the system
configuration specified therein.
</para>
</refsection>
<refsection>
<title>Options</title>
<para>
You can use the following options in <filename>configuration.nix</filename>.
</para>
<xi:include href="./generated/options-db.xml"
xpointer="configuration-variable-list" />
</refsection>
</refentry>

View file

@ -14,5 +14,33 @@
<copyright><year>2007-2022</year><holder>Eelco Dolstra and the Nixpkgs/NixOS contributors</holder> <copyright><year>2007-2022</year><holder>Eelco Dolstra and the Nixpkgs/NixOS contributors</holder>
</copyright> </copyright>
</info> </info>
<xi:include href="man-configuration.xml" /> <refentry>
<refmeta>
<refentrytitle><filename>configuration.nix</filename>
</refentrytitle><manvolnum>5</manvolnum>
<refmiscinfo class="source">NixOS</refmiscinfo>
<!-- <refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo> -->
</refmeta>
<refnamediv>
<refname><filename>configuration.nix</filename></refname>
<refpurpose>NixOS system configuration specification</refpurpose>
</refnamediv>
<refsection>
<title>Description</title>
<para>
The file <filename>/etc/nixos/configuration.nix</filename> contains the
declarative specification of your NixOS system configuration. The command
<command>nixos-rebuild</command> takes this file and realises the system
configuration specified therein.
</para>
</refsection>
<refsection>
<title>Options</title>
<para>
You can use the following options in <filename>configuration.nix</filename>.
</para>
<xi:include href="./generated/options-db.xml"
xpointer="configuration-variable-list" />
</refsection>
</refentry>
</reference> </reference>

View file

@ -0,0 +1,53 @@
# NixOS Manual {#book-nixos-manual}
## Version @NIXOS_VERSION@
<!--
this is the top-level structure file for the nixos manual.
the manual structure extends the nixpkgs commonmark further with include
blocks to allow better organization of input text. there are six types of
include blocks: preface, parts, chapters, sections, appendix, and options.
each type except `options`` corresponds to the docbook elements of (roughly)
the same name, and can itself can further include blocks to denote its
substructure.
non-`options`` include blocks are fenced code blocks that list a number of
files to include, in the form
```{=include=} <type>
<file-name-1>
<file-name-2>
<...>
```
`options` include blocks do not list file names but contain a list of key-value
pairs that describe the options to be included and how to convert them into
elements of the manual output type:
```{=include=} options
id-prefix: <options id prefix>
list-id: <variable list element id>
source: <path to options.json>
```
-->
```{=include=} preface
preface.md
```
```{=include=} parts
installation/installation.md
configuration/configuration.md
administration/running.md
development/development.md
```
```{=include=} chapters
contributing-to-this-manual.chapter.md
```
```{=include=} appendix
nixos-options.md
release-notes/release-notes.md
```

View file

@ -1,23 +0,0 @@
<book xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="book-nixos-manual">
<info>
<title>NixOS Manual</title>
<subtitle>Version <xi:include href="./generated/version" parse="text" />
</subtitle>
</info>
<xi:include href="preface.xml" />
<xi:include href="installation/installation.xml" />
<xi:include href="configuration/configuration.xml" />
<xi:include href="administration/running.xml" />
<xi:include href="development/development.xml" />
<xi:include href="./from_md/contributing-to-this-manual.chapter.xml" />
<appendix xml:id="ch-options">
<title>Configuration Options</title>
<xi:include href="./generated/options-db.xml"
xpointer="configuration-variable-list" />
</appendix>
<xi:include href="release-notes/release-notes.xml" />
</book>

View file

@ -0,0 +1,7 @@
# Configuration Options {#ch-options}
```{=include=} options
id-prefix: opt-
list-id: configuration-variable-list
source: @NIXOS_OPTIONS_JSON@
```

View file

@ -0,0 +1,11 @@
# Preface {#preface}
This manual describes how to install, use and extend NixOS, a Linux distribution based on the purely functional package management system [Nix](https://nixos.org/nix), that is composed using modules and packages defined in the [Nixpkgs](https://nixos.org/nixpkgs) project.
Additional information regarding the Nix package manager and the Nixpkgs project can be found in respectively the [Nix manual](https://nixos.org/nix/manual) and the [Nixpkgs manual](https://nixos.org/nixpkgs/manual).
If you encounter problems, please report them on the [`Discourse`](https://discourse.nixos.org), the [Matrix room](https://matrix.to/#nix:nixos.org), or on the [`#nixos` channel on Libera.Chat](irc://irc.libera.chat/#nixos). Alternatively, consider [contributing to this manual](#chap-contributing). Bugs should be reported in [NixOS GitHub issue tracker](https://github.com/NixOS/nixpkgs/issues).
::: {.note}
Commands prefixed with `#` have to be run as root, either requiring to login as root user or temporarily switching to it using `sudo` for example.
:::

View file

@ -1,42 +0,0 @@
<preface xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="preface">
<title>Preface</title>
<para>
This manual describes how to install, use and extend NixOS, a Linux
distribution based on the purely functional package management system
<link xlink:href="https://nixos.org/nix">Nix</link>, that is composed
using modules and packages defined in the
<link xlink:href="https://nixos.org/nixpkgs">Nixpkgs</link> project.
</para>
<para>
Additional information regarding the Nix package manager and the Nixpkgs
project can be found in respectively the
<link xlink:href="https://nixos.org/nix/manual">Nix manual</link> and the
<link xlink:href="https://nixos.org/nixpkgs/manual">Nixpkgs manual</link>.
</para>
<para>
If you encounter problems, please report them on the
<literal
xlink:href="https://discourse.nixos.org">Discourse</literal>,
the <link
xlink:href="https://matrix.to/#nix:nixos.org">Matrix room</link>,
or on the <link
xlink:href="irc://irc.libera.chat/#nixos">
<literal>#nixos</literal> channel on Libera.Chat</link>.
Alternatively, consider <link
xlink:href="#chap-contributing">
contributing to this manual</link>. Bugs should be
reported in
<link
xlink:href="https://github.com/NixOS/nixpkgs/issues">NixOS
GitHub issue tracker</link>.
</para>
<note>
<para>
Commands prefixed with <literal>#</literal> have to be run as root, either
requiring to login as root user or temporarily switching to it using
<literal>sudo</literal> for example.
</para>
</note>
</preface>

View file

@ -0,0 +1,25 @@
# Release Notes {#ch-release-notes}
This section lists the release notes for each stable version of NixOS and current unstable revision.
```{=include=} sections
rl-2305.section.md
rl-2211.section.md
rl-2205.section.md
rl-2111.section.md
rl-2105.section.md
rl-2009.section.md
rl-2003.section.md
rl-1909.section.md
rl-1903.section.md
rl-1809.section.md
rl-1803.section.md
rl-1709.section.md
rl-1703.section.md
rl-1609.section.md
rl-1603.section.md
rl-1509.section.md
rl-1412.section.md
rl-1404.section.md
rl-1310.section.md
```

View file

@ -1,30 +0,0 @@
<appendix xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
version="5.0"
xml:id="ch-release-notes">
<title>Release Notes</title>
<para>
This section lists the release notes for each stable version of NixOS and
current unstable revision.
</para>
<xi:include href="../from_md/release-notes/rl-2305.section.xml" />
<xi:include href="../from_md/release-notes/rl-2211.section.xml" />
<xi:include href="../from_md/release-notes/rl-2205.section.xml" />
<xi:include href="../from_md/release-notes/rl-2111.section.xml" />
<xi:include href="../from_md/release-notes/rl-2105.section.xml" />
<xi:include href="../from_md/release-notes/rl-2009.section.xml" />
<xi:include href="../from_md/release-notes/rl-2003.section.xml" />
<xi:include href="../from_md/release-notes/rl-1909.section.xml" />
<xi:include href="../from_md/release-notes/rl-1903.section.xml" />
<xi:include href="../from_md/release-notes/rl-1809.section.xml" />
<xi:include href="../from_md/release-notes/rl-1803.section.xml" />
<xi:include href="../from_md/release-notes/rl-1709.section.xml" />
<xi:include href="../from_md/release-notes/rl-1703.section.xml" />
<xi:include href="../from_md/release-notes/rl-1609.section.xml" />
<xi:include href="../from_md/release-notes/rl-1603.section.xml" />
<xi:include href="../from_md/release-notes/rl-1509.section.xml" />
<xi:include href="../from_md/release-notes/rl-1412.section.xml" />
<xi:include href="../from_md/release-notes/rl-1404.section.xml" />
<xi:include href="../from_md/release-notes/rl-1310.section.xml" />
</appendix>

View file

@ -40,8 +40,12 @@ In addition to numerous new and upgraded packages, this release has the followin
- [goeland](https://github.com/slurdge/goeland), an alternative to rss2email written in golang with many filters. Available as [services.goeland](#opt-services.goeland.enable). - [goeland](https://github.com/slurdge/goeland), an alternative to rss2email written in golang with many filters. Available as [services.goeland](#opt-services.goeland.enable).
- [tts](https://github.com/coqui-ai/TTS), a battle-tested deep learning toolkit for Text-to-Speech. Mutiple servers may be configured below [services.tts.servers](#opt-services.tts.servers).
- [atuin](https://github.com/ellie/atuin), a sync server for shell history. Available as [services.atuin](#opt-services.atuin.enable). - [atuin](https://github.com/ellie/atuin), a sync server for shell history. Available as [services.atuin](#opt-services.atuin.enable).
- [networkd-dispatcher](https://gitlab.com/craftyguy/networkd-dispatcher), a dispatcher service for systemd-networkd connection status changes. Available as [services.networkd-dispatcher](#opt-services.networkd-dispatcher.enable).
- [mmsd](https://gitlab.com/kop316/mmsd), a lower level daemon that transmits and recieves MMSes. Available as [services.mmsd](#opt-services.mmsd.enable). - [mmsd](https://gitlab.com/kop316/mmsd), a lower level daemon that transmits and recieves MMSes. Available as [services.mmsd](#opt-services.mmsd.enable).
- [QDMR](https://dm3mat.darc.de/qdmr/), a GUI application and command line tool for programming DMR radios [programs.qdmr](#opt-programs.qdmr.enable) - [QDMR](https://dm3mat.darc.de/qdmr/), a GUI application and command line tool for programming DMR radios [programs.qdmr](#opt-programs.qdmr.enable)

View file

@ -1,8 +0,0 @@
let
pkgs = import ../../.. { };
in
pkgs.mkShell {
name = "nixos-manual";
packages = with pkgs; [ xmlformat jing xmloscopy ruby ];
}

View file

@ -1,124 +0,0 @@
#!/usr/bin/env ruby
# This script is written intended as a living, evolving tooling
# to fix oopsies within the docbook documentation.
#
# This is *not* a formatter. It, instead, handles some known cases
# where something bad happened, and fixing it manually is tedious.
#
# Read the code to see the different cases it handles.
#
# ALWAYS `make format` after fixing with this!
# ALWAYS read the changes, this tool isn't yet proven to be always right.
require "rexml/document"
include REXML
if ARGV.length < 1 then
$stderr.puts "Needs a filename."
exit 1
end
filename = ARGV.shift
doc = Document.new(File.open(filename))
$touched = false
# Fixing varnames having a sibling element without spacing.
# This is to fix an initial `xmlformat` issue where `term`
# would mangle as spaces.
#
# <varlistentry>
# <term><varname>types.separatedString</varname><replaceable>sep</replaceable> <----
# </term>
# ...
#
# Generates: types.separatedStringsep
# ^^^^
#
# <varlistentry xml:id='fun-makeWrapper'>
# <term>
# <function>makeWrapper</function><replaceable>executable</replaceable><replaceable>wrapperfile</replaceable><replaceable>args</replaceable> <----
# </term>
#
# Generates: makeWrapperexecutablewrapperfileargs
# ^^^^ ^^^^ ^^ ^^
#
# <term>
# <option>--option</option><replaceable>name</replaceable><replaceable>value</replaceable> <-----
# </term>
#
# Generates: --optionnamevalue
# ^^ ^^
doc.elements.each("//varlistentry/term") do |term|
["varname", "function", "option", "replaceable"].each do |prev_name|
term.elements.each(prev_name) do |el|
if el.next_element and
el.next_element.name == "replaceable" and
el.next_sibling_node.class == Element
then
$touched = true
term.insert_after(el, Text.new(" "))
end
end
end
end
# <cmdsynopsis>
# <command>nixos-option</command>
# <arg>
# <option>-I</option><replaceable>path</replaceable> <------
# </arg>
#
# Generates: -Ipath
# ^^
doc.elements.each("//cmdsynopsis/arg") do |term|
["option", "replaceable"].each do |prev_name|
term.elements.each(prev_name) do |el|
if el.next_element and
el.next_element.name == "replaceable" and
el.next_sibling_node.class == Element
then
$touched = true
term.insert_after(el, Text.new(" "))
end
end
end
end
# <cmdsynopsis>
# <arg>
# <group choice='req'>
# <arg choice='plain'>
# <option>--profile-name</option>
# </arg>
#
# <arg choice='plain'>
# <option>-p</option>
# </arg>
# </group><replaceable>name</replaceable> <----
# </arg>
#
# Generates: [{--profile-name | -p }name]
# ^^^^
doc.elements.each("//cmdsynopsis/arg") do |term|
["group"].each do |prev_name|
term.elements.each(prev_name) do |el|
if el.next_element and
el.next_element.name == "replaceable" and
el.next_sibling_node.class == Element
then
$touched = true
term.insert_after(el, Text.new(" "))
end
end
end
end
if $touched then
doc.context[:attribute_quote] = :quote
doc.write(output: File.open(filename, "w"))
end

View file

@ -91,18 +91,24 @@ let
in rec { in rec {
inherit optionsNix; inherit optionsNix;
optionsAsciiDoc = pkgs.runCommand "options.adoc" {} '' optionsAsciiDoc = pkgs.runCommand "options.adoc" {
${pkgs.python3Minimal}/bin/python ${./generateDoc.py} \ nativeBuildInputs = [ pkgs.nixos-render-docs ];
--format asciidoc \ } ''
nixos-render-docs -j $NIX_BUILD_CORES options asciidoc \
--manpage-urls ${pkgs.path + "/doc/manpage-urls.json"} \
--revision ${lib.escapeShellArg revision} \
${optionsJSON}/share/doc/nixos/options.json \ ${optionsJSON}/share/doc/nixos/options.json \
> $out $out
''; '';
optionsCommonMark = pkgs.runCommand "options.md" {} '' optionsCommonMark = pkgs.runCommand "options.md" {
${pkgs.python3Minimal}/bin/python ${./generateDoc.py} \ nativeBuildInputs = [ pkgs.nixos-render-docs ];
--format commonmark \ } ''
nixos-render-docs -j $NIX_BUILD_CORES options commonmark \
--manpage-urls ${pkgs.path + "/doc/manpage-urls.json"} \
--revision ${lib.escapeShellArg revision} \
${optionsJSON}/share/doc/nixos/options.json \ ${optionsJSON}/share/doc/nixos/options.json \
> $out $out
''; '';
optionsJSON = pkgs.runCommand "options.json" optionsJSON = pkgs.runCommand "options.json"
@ -152,7 +158,7 @@ in rec {
pkgs.nixos-render-docs pkgs.nixos-render-docs
]; ];
} '' } ''
nixos-render-docs options docbook \ nixos-render-docs -j $NIX_BUILD_CORES options docbook \
--manpage-urls ${pkgs.path + "/doc/manpage-urls.json"} \ --manpage-urls ${pkgs.path + "/doc/manpage-urls.json"} \
--revision ${lib.escapeShellArg revision} \ --revision ${lib.escapeShellArg revision} \
--document-type ${lib.escapeShellArg documentType} \ --document-type ${lib.escapeShellArg documentType} \

View file

@ -1,112 +0,0 @@
import argparse
import json
import sys
formats = ['commonmark', 'asciidoc']
parser = argparse.ArgumentParser(
description = 'Generate documentation for a set of JSON-formatted NixOS options'
)
parser.add_argument(
'nix_options_path',
help = 'a path to a JSON file containing the NixOS options'
)
parser.add_argument(
'-f',
'--format',
choices = formats,
required = True,
help = f'the documentation format to generate'
)
args = parser.parse_args()
class OptionsEncoder(json.JSONEncoder):
def encode(self, obj):
# Unpack literal expressions and other Nix types.
# Don't escape the strings: they were escaped when initially serialized to JSON.
if isinstance(obj, dict):
_type = obj.get('_type')
if _type is not None:
if _type == 'literalExpression' or _type == 'literalDocBook':
return obj['text']
if _type == 'derivation':
return obj['name']
raise Exception(f'Unexpected type `{_type}` in {json.dumps(obj)}')
return super().encode(obj)
def generate_commonmark(options):
for (name, value) in options.items():
print('##', name.replace('<', '&lt;').replace('>', '&gt;'))
print(value['description'])
print()
if 'type' in value:
print('*_Type_*')
print ('```')
print(value['type'])
print ('```')
print()
print()
if 'default' in value:
print('*_Default_*')
print('```')
print(json.dumps(value['default'], cls=OptionsEncoder, ensure_ascii=False, separators=(',', ':')))
print('```')
print()
print()
if 'example' in value:
print('*_Example_*')
print('```')
print(json.dumps(value['example'], cls=OptionsEncoder, ensure_ascii=False, separators=(',', ':')))
print('```')
print()
print()
# TODO: declarations: link to github
def generate_asciidoc(options):
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'], cls=OptionsEncoder, 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'], cls=OptionsEncoder, ensure_ascii=False, separators=(',', ':')))
print('----')
print()
else:
print('No Example:: {blank}')
print()
with open(args.nix_options_path) as nix_options_json:
options = json.load(nix_options_json)
if args.format == 'commonmark':
generate_commonmark(options)
elif args.format == 'asciidoc':
generate_asciidoc(options)
else:
raise Exception(f'Unsupported documentation format `--format {args.format}`')

View file

@ -22,7 +22,7 @@ in
}; };
timeout = lib.mkOption { timeout = lib.mkOption {
type = types.nullOr types.int; type = types.nullOr types.int;
default = null; # NOTE: null values are filtered out by `meta`. default = 3600; # 1 hour
description = mdDoc '' description = mdDoc ''
The [{option}`test`](#test-opt-test)'s [`meta.timeout`](https://nixos.org/manual/nixpkgs/stable/#var-meta-timeout) in seconds. The [{option}`test`](#test-opt-test)'s [`meta.timeout`](https://nixos.org/manual/nixpkgs/stable/#var-meta-timeout) in seconds.
''; '';

View file

@ -168,7 +168,6 @@ in
"${config.boot.initrd.systemd.package.kbd}/bin/setfont" "${config.boot.initrd.systemd.package.kbd}/bin/setfont"
"${config.boot.initrd.systemd.package.kbd}/bin/loadkeys" "${config.boot.initrd.systemd.package.kbd}/bin/loadkeys"
"${config.boot.initrd.systemd.package.kbd.gzip}/bin/gzip" # Fonts and keyboard layouts are compressed "${config.boot.initrd.systemd.package.kbd.gzip}/bin/gzip" # Fonts and keyboard layouts are compressed
"${config.boot.initrd.systemd.package.kbd.gzip}/bin/.gzip-wrapped"
] ++ optionals (hasPrefix builtins.storeDir cfg.font) [ ] ++ optionals (hasPrefix builtins.storeDir cfg.font) [
"${cfg.font}" "${cfg.font}"
] ++ optionals (hasPrefix builtins.storeDir cfg.keyMap) [ ] ++ optionals (hasPrefix builtins.storeDir cfg.keyMap) [

View file

@ -67,6 +67,7 @@ with lib;
stoken = super.stoken.override { withGTK3 = false; }; stoken = super.stoken.override { withGTK3 = false; };
# translateManpages -> perlPackages.po4a -> texlive-combined-basic -> texlive-core-big -> libX11 # translateManpages -> perlPackages.po4a -> texlive-combined-basic -> texlive-core-big -> libX11
util-linux = super.util-linux.override { translateManpages = false; }; util-linux = super.util-linux.override { translateManpages = false; };
vim-full = super.vim-full.override { guiSupport = false; };
zbar = super.zbar.override { enableVideo = false; withXorg = false; }; zbar = super.zbar.override { enableVideo = false; withXorg = false; };
})); }));
}; };

View file

@ -65,8 +65,6 @@ in {
] ++ optional pkgs.stdenv.hostPlatform.isAarch raspberrypiWirelessFirmware ] ++ optional pkgs.stdenv.hostPlatform.isAarch raspberrypiWirelessFirmware
++ optionals (versionOlder config.boot.kernelPackages.kernel.version "4.13") [ ++ optionals (versionOlder config.boot.kernelPackages.kernel.version "4.13") [
rtl8723bs-firmware rtl8723bs-firmware
] ++ optionals (versionOlder config.boot.kernelPackages.kernel.version "5.16") [
rtw89-firmware
]; ];
hardware.wirelessRegulatoryDatabase = true; hardware.wirelessRegulatoryDatabase = true;
}) })

View file

@ -0,0 +1,18 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.hardware.flipperzero;
in
{
options.hardware.flipperzero.enable = mkEnableOption (mdDoc "udev rules and software for Flipper Zero devices");
config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.qFlipper ];
services.udev.packages = [ pkgs.qFlipper ];
};
}

View file

@ -392,7 +392,7 @@ in
tape = 25; tape = 25;
video = 26; video = 26;
dialout = 27; dialout = 27;
#polkituser = 28; # currently unused, polkitd doesn't need a group polkituser = 28;
utmp = 29; utmp = 29;
# ddclient = 30; # converted to DynamicUser = true # ddclient = 30; # converted to DynamicUser = true
davfs2 = 31; davfs2 = 31;

View file

@ -53,6 +53,7 @@
./hardware/cpu/intel-sgx.nix ./hardware/cpu/intel-sgx.nix
./hardware/device-tree.nix ./hardware/device-tree.nix
./hardware/digitalbitbox.nix ./hardware/digitalbitbox.nix
./hardware/flipperzero.nix
./hardware/flirc.nix ./hardware/flirc.nix
./hardware/gkraken.nix ./hardware/gkraken.nix
./hardware/gpgsmartcards.nix ./hardware/gpgsmartcards.nix
@ -314,6 +315,7 @@
./services/audio/snapserver.nix ./services/audio/snapserver.nix
./services/audio/spotifyd.nix ./services/audio/spotifyd.nix
./services/audio/squeezelite.nix ./services/audio/squeezelite.nix
./services/audio/tts.nix
./services/audio/ympd.nix ./services/audio/ympd.nix
./services/backup/automysqlbackup.nix ./services/backup/automysqlbackup.nix
./services/backup/bacula.nix ./services/backup/bacula.nix
@ -912,6 +914,7 @@
./services/networking/ndppd.nix ./services/networking/ndppd.nix
./services/networking/nebula.nix ./services/networking/nebula.nix
./services/networking/netbird.nix ./services/networking/netbird.nix
./services/networking/networkd-dispatcher.nix
./services/networking/networkmanager.nix ./services/networking/networkmanager.nix
./services/networking/nextdns.nix ./services/networking/nextdns.nix
./services/networking/nftables.nix ./services/networking/nftables.nix

View file

@ -22,6 +22,5 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
services.udev.packages = [ cfg.package ]; services.udev.packages = [ cfg.package ];
environment.systemPackages = [ cfg.package ]; environment.systemPackages = [ cfg.package ];
users.groups.flashrom = { };
}; };
} }

View file

@ -113,7 +113,7 @@ in
group = "polkituser"; group = "polkituser";
}; };
users.groups.polkituser = {}; users.groups.polkituser.gid = config.ids.gids.polkituser;
}; };
} }

View file

@ -0,0 +1,151 @@
{ config
, lib
, pkgs
, ...
}:
let
cfg = config.services.tts;
in
{
options.services.tts = let
inherit (lib) literalExpression mkOption mdDoc mkEnableOption types;
in {
servers = mkOption {
type = types.attrsOf (types.submodule (
{ ... }: {
options = {
enable = mkEnableOption (mdDoc "Coqui TTS server");
port = mkOption {
type = types.port;
example = 5000;
description = mdDoc ''
Port to bind the TTS server to.
'';
};
model = mkOption {
type = types.nullOr types.str;
default = "tts_models/en/ljspeech/tacotron2-DDC";
example = null;
description = mdDoc ''
Name of the model to download and use for speech synthesis.
Check `tts-server --list_models` for possible values.
Set to `null` to use a custom model.
'';
};
useCuda = mkOption {
type = types.bool;
default = false;
example = true;
description = mdDoc ''
Whether to offload computation onto a CUDA compatible GPU.
'';
};
extraArgs = mkOption {
type = types.listOf types.str;
default = [];
description = mdDoc ''
Extra arguments to pass to the server commandline.
'';
};
};
}
));
default = {};
example = literalExpression ''
{
english = {
port = 5300;
model = "tts_models/en/ljspeech/tacotron2-DDC";
};
german = {
port = 5301;
model = "tts_models/de/thorsten/tacotron2-DDC";
};
dutch = {
port = 5302;
model = "tts_models/nl/mai/tacotron2-DDC";
};
}
'';
description = mdDoc ''
TTS server instances.
'';
};
};
config = let
inherit (lib) mkIf mapAttrs' nameValuePair optionalString concatMapStringsSep escapeShellArgs;
in mkIf (cfg.servers != {}) {
systemd.services = mapAttrs' (server: options:
nameValuePair "tts-${server}" {
description = "Coqui TTS server instance ${server}";
after = [
"network-online.target"
];
wantedBy = [
"multi-user.target"
];
path = with pkgs; [
espeak-ng
];
environment.HOME = "/var/lib/tts";
serviceConfig = {
DynamicUser = true;
User = "tts";
StateDirectory = "tts";
ExecStart = "${pkgs.tts}/bin/tts-server --port ${toString options.port}"
+ optionalString (options.model != null) " --model_name ${options.model}"
+ optionalString (options.useCuda) " --use_cuda"
+ (concatMapStringsSep " " escapeShellArgs options.extraArgs);
CapabilityBoundingSet = "";
DeviceAllow = if options.useCuda then [
# https://docs.nvidia.com/dgx/pdf/dgx-os-5-user-guide.pdf
"/dev/nvidia1"
"/dev/nvidia2"
"/dev/nvidia3"
"/dev/nvidia4"
"/dev/nvidia-caps/nvidia-cap1"
"/dev/nvidia-caps/nvidia-cap2"
"/dev/nvidiactl"
"/dev/nvidia-modeset"
"/dev/nvidia-uvm"
"/dev/nvidia-uvm-tools"
] else "";
DevicePolicy = "closed";
LockPersonality = true;
# jit via numba->llvmpipe
MemoryDenyWriteExecute = false;
PrivateDevices = true;
PrivateUsers = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectControlGroups = true;
ProtectProc = "invisible";
ProcSubset = "pid";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
];
UMask = "0077";
};
}) cfg.servers;
};
}

View file

@ -128,7 +128,7 @@ To backup your home directory to borgbase you have to:
- Initialize the repository on the server. Eg. - Initialize the repository on the server. Eg.
sudo borg init --encryption=repokey-blake2 \ sudo borg init --encryption=repokey-blake2 \
-rsh "ssh -i /run/keys/id_ed25519_borgbase" \ --rsh "ssh -i /run/keys/id_ed25519_borgbase" \
zzz2aaaaa@zzz2aaaaa.repo.borgbase.com:repo zzz2aaaaa@zzz2aaaaa.repo.borgbase.com:repo
- Add it to your NixOS configuration, e.g. - Add it to your NixOS configuration, e.g.

View file

@ -34,7 +34,7 @@ let
text = if (cfg.configFile != null) then '' text = if (cfg.configFile != null) then ''
cp ${cfg.configFile} ${configPath} cp ${cfg.configFile} ${configPath}
# make config file readable by service # make config file readable by service
chown -R --reference=$HOME $(dirname ${configPath}) chown -R --reference="$HOME" "$(dirname ${configPath})"
'' else '' '' else ''
export CONFIG_FILE=${configPath} export CONFIG_FILE=${configPath}

View file

@ -8,19 +8,9 @@ let
keyboard = { keyboard = {
options = { options = {
devices = mkOption { devices = mkOption {
type = types.addCheck (types.listOf types.str) type = types.listOf types.str;
(devices: (length devices) > 0);
example = [ "/dev/input/by-id/usb-0000_0000-event-kbd" ]; example = [ "/dev/input/by-id/usb-0000_0000-event-kbd" ];
# TODO replace note with tip, which has not been implemented yet in description = mdDoc "Paths to keyboard devices.";
# nixos/lib/make-options-doc/mergeJSON.py
description = mdDoc ''
Paths to keyboard devices.
::: {.note}
To avoid unnecessary triggers of the service unit, unplug devices in
the order of the list.
:::
'';
}; };
config = mkOption { config = mkOption {
type = types.lines; type = types.lines;
@ -44,8 +34,10 @@ let
cap (tap-hold 100 100 caps lctl)) cap (tap-hold 100 100 caps lctl))
''; '';
description = mdDoc '' description = mdDoc ''
Configuration other than `defcfg`. See [example config Configuration other than `defcfg`.
files](https://github.com/jtroo/kanata) for more information.
See [example config files](https://github.com/jtroo/kanata)
for more information.
''; '';
}; };
extraDefCfg = mkOption { extraDefCfg = mkOption {
@ -53,8 +45,12 @@ let
default = ""; default = "";
example = "danger-enable-cmd yes"; example = "danger-enable-cmd yes";
description = mdDoc '' description = mdDoc ''
Configuration of `defcfg` other than `linux-dev`. See [example Configuration of `defcfg` other than `linux-dev` (generated
config files](https://github.com/jtroo/kanata) for more information. from the devices option) and
`linux-continue-if-no-devs-found` (hardcoded to be yes).
See [example config files](https://github.com/jtroo/kanata)
for more information.
''; '';
}; };
extraArgs = mkOption { extraArgs = mkOption {
@ -67,8 +63,7 @@ let
default = null; default = null;
example = 6666; example = 6666;
description = mdDoc '' description = mdDoc ''
Port to run the notification server on. `null` will not run the Port to run the TCP server on. `null` will not run the server.
server.
''; '';
}; };
}; };
@ -76,28 +71,23 @@ let
mkName = name: "kanata-${name}"; mkName = name: "kanata-${name}";
mkDevices = devices: concatStringsSep ":" devices; mkDevices = devices:
optionalString ((length devices) > 0) "linux-dev ${concatStringsSep ":" devices}";
mkConfig = name: keyboard: pkgs.writeText "${mkName name}-config.kdb" '' mkConfig = name: keyboard: pkgs.writeText "${mkName name}-config.kdb" ''
(defcfg (defcfg
${keyboard.extraDefCfg} ${keyboard.extraDefCfg}
linux-dev ${mkDevices keyboard.devices}) ${mkDevices keyboard.devices}
linux-continue-if-no-devs-found yes)
${keyboard.config} ${keyboard.config}
''; '';
mkService = name: keyboard: nameValuePair (mkName name) { mkService = name: keyboard: nameValuePair (mkName name) {
description = "kanata for ${mkDevices keyboard.devices}"; wantedBy = [ "multi-user.target" ];
# Because path units are used to activate service units, which
# will start the old stopped services during "nixos-rebuild
# switch", stopIfChanged here is a workaround to make sure new
# services are running after "nixos-rebuild switch".
stopIfChanged = false;
serviceConfig = { serviceConfig = {
ExecStart = '' ExecStart = ''
${cfg.package}/bin/kanata \ ${getExe cfg.package} \
--cfg ${mkConfig name keyboard} \ --cfg ${mkConfig name keyboard} \
--symlink-path ''${RUNTIME_DIRECTORY}/${name} \ --symlink-path ''${RUNTIME_DIRECTORY}/${name} \
${optionalString (keyboard.port != null) "--port ${toString keyboard.port}"} \ ${optionalString (keyboard.port != null) "--port ${toString keyboard.port}"} \
@ -146,37 +136,10 @@ let
UMask = "0077"; UMask = "0077";
}; };
}; };
mkPathName = i: name: "${mkName name}-${toString i}";
mkPath = name: n: i: device:
nameValuePair (mkPathName i name) {
description =
"${toString (i+1)}/${toString n} kanata trigger for ${name}, watching ${device}";
wantedBy = optional (i == 0) "multi-user.target";
pathConfig = {
PathExists = device;
# (ab)use systemd.path to construct a trigger chain so that the
# service unit is only started when all paths exist
# however, manual of systemd.path says Unit's suffix is not ".path"
Unit =
if (i + 1) == n
then "${mkName name}.service"
else "${mkPathName (i + 1) name}.path";
};
unitConfig.StopPropagatedFrom = optional (i > 0) "${mkName name}.service";
};
mkPaths = name: keyboard:
let
n = length keyboard.devices;
in
imap0 (mkPath name n) keyboard.devices
;
in in
{ {
options.services.kanata = { options.services.kanata = {
enable = mkEnableOption (lib.mdDoc "kanata"); enable = mkEnableOption (mdDoc "kanata");
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = pkgs.kanata; default = pkgs.kanata;
@ -201,14 +164,7 @@ in
config = mkIf cfg.enable { config = mkIf cfg.enable {
hardware.uinput.enable = true; hardware.uinput.enable = true;
systemd = { systemd.services = mapAttrs' mkService cfg.keyboards;
paths = trivial.pipe cfg.keyboards [
(mapAttrsToList mkPaths)
concatLists
listToAttrs
];
services = mapAttrs' mkService cfg.keyboards;
};
}; };
meta.maintainers = with maintainers; [ linj ]; meta.maintainers = with maintainers; [ linj ];

View file

@ -409,6 +409,7 @@ in {
(optionalString (cfg.config != null) copyConfig) + (optionalString (cfg.config != null) copyConfig) +
(optionalString (cfg.lovelaceConfig != null) copyLovelaceConfig) (optionalString (cfg.lovelaceConfig != null) copyLovelaceConfig)
; ;
environment.PYTHONPATH = package.pythonPath;
serviceConfig = let serviceConfig = let
# List of capabilities to equip home-assistant with, depending on configured components # List of capabilities to equip home-assistant with, depending on configured components
capabilities = lib.unique ([ capabilities = lib.unique ([

View file

@ -223,22 +223,59 @@ in {
''; '';
}; };
ensureAccounts = mkOption {
type = types.listOf types.str;
default = [];
description = lib.mdDoc ''
List of IMAP accounts which get automatically created. Note that for
a complete setup, user credentials for these accounts are required too
and can be created using the command `maddyctl creds`.
This option does not delete accounts which are not (anymore) listed.
'';
example = [
"user1@localhost"
"user2@localhost"
];
};
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
systemd = { systemd = {
packages = [ pkgs.maddy ]; packages = [ pkgs.maddy ];
services.maddy = { services = {
serviceConfig = { maddy = {
User = cfg.user; serviceConfig = {
Group = cfg.group; User = cfg.user;
StateDirectory = [ "maddy" ]; Group = cfg.group;
StateDirectory = [ "maddy" ];
};
restartTriggers = [ config.environment.etc."maddy/maddy.conf".source ];
wantedBy = [ "multi-user.target" ];
}; };
restartTriggers = [ config.environment.etc."maddy/maddy.conf".source ]; maddy-ensure-accounts = {
wantedBy = [ "multi-user.target" ]; script = ''
${optionalString (cfg.ensureAccounts != []) ''
${concatMapStrings (account: ''
if ! ${pkgs.maddy}/bin/maddyctl imap-acct list | grep "${account}"; then
${pkgs.maddy}/bin/maddyctl imap-acct create ${account}
fi
'') cfg.ensureAccounts}
''}
'';
serviceConfig = {
Type = "oneshot";
User= "maddy";
};
after = [ "maddy.service" ];
wantedBy = [ "multi-user.target" ];
};
}; };
}; };
environment.etc."maddy/maddy.conf" = { environment.etc."maddy/maddy.conf" = {

View file

@ -96,7 +96,7 @@ in {
type = types.nullOr types.path; type = types.nullOr types.path;
default = null; default = null;
description = lib.mdDoc '' description = lib.mdDoc ''
File containing environment variables to be passed to the mautrix-telegram service. File containing environment variables to be passed to the mautrix-facebook service.
Any config variable can be overridden by setting `MAUTRIX_FACEBOOK_SOME_KEY` to override the `some.key` variable. Any config variable can be overridden by setting `MAUTRIX_FACEBOOK_SOME_KEY` to override the `some.key` variable.
''; '';

View file

@ -137,7 +137,7 @@ in {
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ] ++ cfg.serviceDependencies; wants = [ "network-online.target" ] ++ cfg.serviceDependencies;
after = [ "network-online.target" ] ++ cfg.serviceDependencies; after = [ "network-online.target" ] ++ cfg.serviceDependencies;
path = [ pkgs.lottieconverter ]; path = [ pkgs.lottieconverter pkgs.ffmpeg-full ];
# mautrix-telegram tries to generate a dotfile in the home directory of # mautrix-telegram tries to generate a dotfile in the home directory of
# the running user if using a postgresql database: # the running user if using a postgresql database:

View file

@ -1,5 +1,4 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
with lib; with lib;
let let
@ -16,17 +15,19 @@ in {
type = types.package; type = types.package;
default = pkgs.mbpfan; default = pkgs.mbpfan;
defaultText = literalExpression "pkgs.mbpfan"; defaultText = literalExpression "pkgs.mbpfan";
description = lib.mdDoc '' description = lib.mdDoc "The package used for the mbpfan daemon.";
The package used for the mbpfan daemon.
'';
}; };
verbose = mkOption { verbose = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = lib.mdDoc '' description = lib.mdDoc "If true, sets the log level to verbose.";
If true, sets the log level to verbose. };
'';
aggressive = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc "If true, favors higher default fan speeds.";
}; };
settings = mkOption { settings = mkOption {
@ -35,24 +36,14 @@ in {
type = types.submodule { type = types.submodule {
freeformType = settingsFormat.type; freeformType = settingsFormat.type;
options.general.min_fan1_speed = mkOption {
type = types.nullOr types.int;
default = 2000;
description = lib.mdDoc ''
You can check minimum and maximum fan limits with
`cat /sys/devices/platform/applesmc.768/fan*_min` and
`cat /sys/devices/platform/applesmc.768/fan*_max` respectively.
Setting to null implies using default value from applesmc.
'';
};
options.general.low_temp = mkOption { options.general.low_temp = mkOption {
type = types.int; type = types.int;
default = 55; default = 63;
description = lib.mdDoc "If temperature is below this, fans will run at minimum speed."; description = lib.mdDoc "If temperature is below this, fans will run at minimum speed.";
}; };
options.general.high_temp = mkOption { options.general.high_temp = mkOption {
type = types.int; type = types.int;
default = 58; default = 66;
description = lib.mdDoc "If temperature is above this, fan speed will gradually increase."; description = lib.mdDoc "If temperature is above this, fan speed will gradually increase.";
}; };
options.general.max_temp = mkOption { options.general.max_temp = mkOption {
@ -79,10 +70,16 @@ in {
]; ];
config = mkIf cfg.enable { config = mkIf cfg.enable {
boot.kernelModules = [ "coretemp" "applesmc" ]; services.mbpfan.settings = mkIf cfg.aggressive {
general.min_fan1_speed = mkDefault 2000;
general.low_temp = mkDefault 55;
general.high_temp = mkDefault 58;
general.max_temp = mkDefault 70;
};
environment.etc."mbpfan.conf".source = settingsFile; boot.kernelModules = [ "coretemp" "applesmc" ];
environment.systemPackages = [ cfg.package ]; environment.systemPackages = [ cfg.package ];
environment.etc."mbpfan.conf".source = settingsFile;
systemd.services.mbpfan = { systemd.services.mbpfan = {
description = "A fan manager daemon for MacBook Pro"; description = "A fan manager daemon for MacBook Pro";

View file

@ -25,6 +25,13 @@ in {
Specify a configuration file that Mimir should use. Specify a configuration file that Mimir should use.
''; '';
}; };
package = mkOption {
default = pkgs.mimir;
defaultText = lib.literalExpression "pkgs.mimir";
type = types.package;
description = lib.mdDoc ''Mimir package to use.'';
};
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
@ -53,7 +60,7 @@ in {
else cfg.configFile; else cfg.configFile;
in in
{ {
ExecStart = "${pkgs.mimir}/bin/mimir --config.file=${conf}"; ExecStart = "${cfg.package}/bin/mimir --config.file=${conf}";
DynamicUser = true; DynamicUser = true;
Restart = "always"; Restart = "always";
ProtectSystem = "full"; ProtectSystem = "full";

View file

@ -409,7 +409,7 @@ in
provision = { provision = {
enable = cfg.provision.grafana.datasource || cfg.provision.grafana.dashboard; enable = cfg.provision.grafana.datasource || cfg.provision.grafana.dashboard;
datasources = datasources.settings.datasources =
let let
esVersion = lib.getVersion config.services.elasticsearch.package; esVersion = lib.getVersion config.services.elasticsearch.package;
in in
@ -435,7 +435,7 @@ in
}; };
} }
]; ];
dashboards = lib.mkIf cfg.provision.grafana.dashboard [{ dashboards.settings.providers = lib.mkIf cfg.provision.grafana.dashboard [{
name = "parsedmarc"; name = "parsedmarc";
options.path = "${pkgs.python3Packages.parsedmarc.dashboard}"; options.path = "${pkgs.python3Packages.parsedmarc.dashboard}";
}]; }];

View file

@ -0,0 +1,63 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.networkd-dispatcher;
in {
options = {
services.networkd-dispatcher = {
enable = mkEnableOption (mdDoc ''
Networkd-dispatcher service for systemd-networkd connection status
change. See [https://gitlab.com/craftyguy/networkd-dispatcher](upstream instructions)
for usage.
'');
scriptDir = mkOption {
type = types.path;
default = "/var/lib/networkd-dispatcher";
description = mdDoc ''
This directory is used for keeping various scripts read and run by
networkd-dispatcher. See [https://gitlab.com/craftyguy/networkd-dispatcher](upstream instructions)
for directory structure and script usage.
'';
};
};
};
config = mkIf cfg.enable {
systemd = {
packages = [ pkgs.networkd-dispatcher ];
services.networkd-dispatcher = {
wantedBy = [ "multi-user.target" ];
# Override existing ExecStart definition
serviceConfig.ExecStart = [
""
"${pkgs.networkd-dispatcher}/bin/networkd-dispatcher -v --script-dir ${cfg.scriptDir} $networkd_dispatcher_args"
];
};
# Directory structure required according to upstream instructions
# https://gitlab.com/craftyguy/networkd-dispatcher
tmpfiles.rules = [
"d '${cfg.scriptDir}' 0750 root root - -"
"d '${cfg.scriptDir}/routable.d' 0750 root root - -"
"d '${cfg.scriptDir}/dormant.d' 0750 root root - -"
"d '${cfg.scriptDir}/no-carrier.d' 0750 root root - -"
"d '${cfg.scriptDir}/off.d' 0750 root root - -"
"d '${cfg.scriptDir}/carrier.d' 0750 root root - -"
"d '${cfg.scriptDir}/degraded.d' 0750 root root - -"
"d '${cfg.scriptDir}/configuring.d' 0750 root root - -"
"d '${cfg.scriptDir}/configured.d' 0750 root root - -"
];
};
};
}

View file

@ -82,8 +82,8 @@ in {
}; };
boot.kernel.sysctl = mkIf (cfg.useRoutingFeatures == "server" || cfg.useRoutingFeatures == "both") { boot.kernel.sysctl = mkIf (cfg.useRoutingFeatures == "server" || cfg.useRoutingFeatures == "both") {
"net.ipv4.conf.all.forwarding" = mkDefault true; "net.ipv4.conf.all.forwarding" = mkOverride 97 true;
"net.ipv6.conf.all.forwarding" = mkDefault true; "net.ipv6.conf.all.forwarding" = mkOverride 97 true;
}; };
networking.firewall.checkReversePath = mkIf (cfg.useRoutingFeatures == "client" || cfg.useRoutingFeatures == "both") "loose"; networking.firewall.checkReversePath = mkIf (cfg.useRoutingFeatures == "client" || cfg.useRoutingFeatures == "both") "loose";

View file

@ -12,27 +12,38 @@ with lib;
config = mkIf config.services.v2raya.enable { config = mkIf config.services.v2raya.enable {
environment.systemPackages = [ pkgs.v2raya ]; environment.systemPackages = [ pkgs.v2raya ];
systemd.services.v2raya = { systemd.services.v2raya =
unitConfig = { let
Description = "v2rayA service"; nftablesEnabled = config.networking.nftables.enable;
Documentation = "https://github.com/v2rayA/v2rayA/wiki"; iptablesServices = [
After = [ "network.target" "nss-lookup.target" "iptables.service" "ip6tables.service" ]; "iptables.service"
Wants = [ "network.target" ]; ] ++ optional config.networking.enableIPv6 "ip6tables.service";
}; tableServices = if nftablesEnabled then [ "nftables.service" ] else iptablesServices;
in
{
unitConfig = {
Description = "v2rayA service";
Documentation = "https://github.com/v2rayA/v2rayA/wiki";
After = [
"network.target"
"nss-lookup.target"
] ++ tableServices;
Wants = [ "network.target" ];
};
serviceConfig = { serviceConfig = {
User = "root"; User = "root";
ExecStart = "${getExe pkgs.v2raya} --log-disable-timestamp"; ExecStart = "${getExe pkgs.v2raya} --log-disable-timestamp";
Environment = [ "V2RAYA_LOG_FILE=/var/log/v2raya/v2raya.log" ]; Environment = [ "V2RAYA_LOG_FILE=/var/log/v2raya/v2raya.log" ];
LimitNPROC = 500; LimitNPROC = 500;
LimitNOFILE = 1000000; LimitNOFILE = 1000000;
Restart = "on-failure"; Restart = "on-failure";
Type = "simple"; Type = "simple";
}; };
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
path = with pkgs; [ iptables bash iproute2 ]; # required by v2rayA TProxy functionality path = with pkgs; [ iptables bash iproute2 ]; # required by v2rayA TProxy functionality
}; };
}; };
meta.maintainers = with maintainers; [ elliot ]; meta.maintainers = with maintainers; [ elliot ];

View file

@ -615,6 +615,7 @@ in
s3_endpoint = null; s3_endpoint = null;
s3_http_continue_timeout = null; s3_http_continue_timeout = null;
s3_install_cors_rule = null; s3_install_cors_rule = null;
s3_asset_cdn_url = null;
max_user_api_reqs_per_minute = 20; max_user_api_reqs_per_minute = 20;
max_user_api_reqs_per_day = 2880; max_user_api_reqs_per_day = 2880;
@ -647,6 +648,9 @@ in
multisite_config_path = "config/multisite.yml"; multisite_config_path = "config/multisite.yml";
enable_long_polling = null; enable_long_polling = null;
long_polling_interval = null; long_polling_interval = null;
preload_link_header = false;
redirect_avatar_requests = false;
pg_force_readonly_mode = false;
}; };
services.redis.servers.discourse = services.redis.servers.discourse =
@ -1011,6 +1015,7 @@ in
notification_email = cfg.mail.notificationEmailAddress; notification_email = cfg.mail.notificationEmailAddress;
contact_email = cfg.mail.contactEmailAddress; contact_email = cfg.mail.contactEmailAddress;
}; };
security.force_https = tlsEnabled;
email = { email = {
manual_polling_enabled = cfg.mail.incoming.enable; manual_polling_enabled = cfg.mail.incoming.enable;
reply_by_email_enabled = cfg.mail.incoming.enable; reply_by_email_enabled = cfg.mail.incoming.enable;

View file

@ -270,7 +270,7 @@ in
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
serviceConfig = { serviceConfig = {
ExecStart = "${cfg.package.fhs}/bin/onlyoffice-wrapper DocService/docservice /run/onlyoffice/config"; ExecStart = "${cfg.package.fhs}/bin/onlyoffice-wrapper DocService/docservice /run/onlyoffice/config";
ExecStartPre = onlyoffice-prestart; ExecStartPre = [ onlyoffice-prestart ];
Group = "onlyoffice"; Group = "onlyoffice";
Restart = "always"; Restart = "always";
RuntimeDirectory = "onlyoffice"; RuntimeDirectory = "onlyoffice";

View file

@ -316,11 +316,13 @@ in {
mkdir -p -m 0755 /run/binfmt mkdir -p -m 0755 /run/binfmt
${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet config.boot.binfmt.registrations)} ${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet config.boot.binfmt.registrations)}
''; '';
systemd.additionalUpstreamSystemUnits = lib.mkIf (config.boot.binfmt.registrations != {}) [ systemd = lib.mkIf (config.boot.binfmt.registrations != {}) {
"proc-sys-fs-binfmt_misc.automount" additionalUpstreamSystemUnits = [
"proc-sys-fs-binfmt_misc.mount" "proc-sys-fs-binfmt_misc.automount"
"systemd-binfmt.service" "proc-sys-fs-binfmt_misc.mount"
]; "systemd-binfmt.service"
systemd.services.systemd-binfmt.restartTriggers = [ (builtins.toJSON config.boot.binfmt.registrations) ]; ];
services.systemd-binfmt.restartTriggers = [ (builtins.toJSON config.boot.binfmt.registrations) ];
};
}; };
} }

View file

@ -427,9 +427,6 @@ in {
# fido2 support # fido2 support
"${cfg.package}/lib/cryptsetup/libcryptsetup-token-systemd-fido2.so" "${cfg.package}/lib/cryptsetup/libcryptsetup-token-systemd-fido2.so"
"${pkgs.libfido2}/lib/libfido2.so.1" "${pkgs.libfido2}/lib/libfido2.so.1"
# the unwrapped systemd-cryptsetup executable
"${cfg.package}/lib/systemd/.systemd-cryptsetup-wrapped"
] ++ jobScripts; ] ++ jobScripts;
targets.initrd.aliases = ["default.target"]; targets.initrd.aliases = ["default.target"];

View file

@ -1,7 +1,8 @@
{ config, pkgs, lib, ... }: { config, pkgs, lib, ... }:
let let
cfg = config.boot.initrd.systemd.repart; cfg = config.systemd.repart;
initrdCfg = config.boot.initrd.systemd.repart;
writeDefinition = name: partitionConfig: pkgs.writeText writeDefinition = name: partitionConfig: pkgs.writeText
"${name}.conf" "${name}.conf"
@ -24,45 +25,59 @@ let
''; '';
in in
{ {
options.boot.initrd.systemd.repart = { options = {
enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // { boot.initrd.systemd.repart.enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // {
description = lib.mdDoc '' description = lib.mdDoc ''
Grow and add partitions to a partition table a boot time in the initrd. Grow and add partitions to a partition table at boot time in the initrd.
systemd-repart only works with GPT partition tables. systemd-repart only works with GPT partition tables.
To run systemd-repart after the initrd, see
`options.systemd.repart.enable`.
''; '';
}; };
partitions = lib.mkOption { systemd.repart = {
type = with lib.types; attrsOf (attrsOf (oneOf [ str int bool ])); enable = lib.mkEnableOption (lib.mdDoc "systemd-repart") // {
default = { }; description = lib.mdDoc ''
example = { Grow and add partitions to a partition table.
"10-root" = { systemd-repart only works with GPT partition tables.
Type = "root";
}; To run systemd-repart while in the initrd, see
"20-home" = { `options.boot.initrd.systemd.repart.enable`.
Type = "home"; '';
SizeMinBytes = "512M"; };
SizeMaxBytes = "2G";
}; partitions = lib.mkOption {
type = with lib.types; attrsOf (attrsOf (oneOf [ str int bool ]));
default = { };
example = {
"10-root" = {
Type = "root";
};
"20-home" = {
Type = "home";
SizeMinBytes = "512M";
SizeMaxBytes = "2G";
};
};
description = lib.mdDoc ''
Specify partitions as a set of the names of the definition files as the
key and the partition configuration as its value. The partition
configuration can use all upstream options. See <link
xlink:href="https://www.freedesktop.org/software/systemd/man/repart.d.html"/>
for all available options.
'';
}; };
description = lib.mdDoc ''
Specify partitions as a set of the names of the definition files as the
key and the partition configuration as its value. The partition
configuration can use all upstream options. See <link
xlink:href="https://www.freedesktop.org/software/systemd/man/repart.d.html"/>
for all available options.
'';
}; };
}; };
config = lib.mkIf cfg.enable { config = lib.mkIf (cfg.enable || initrdCfg.enable) {
# Link the definitions into /etc so that they are included in the # Always link the definitions into /etc so that they are also included in
# /nix/store of the sysroot. This also allows the user to run the # the /nix/store of the sysroot during early userspace (i.e. while in the
# systemd-repart binary after activation manually while automatically # initrd).
# picking up the definition files.
environment.etc."repart.d".source = definitionsDirectory; environment.etc."repart.d".source = definitionsDirectory;
boot.initrd.systemd = { boot.initrd.systemd = lib.mkIf initrdCfg.enable {
additionalUpstreamUnits = [ additionalUpstreamUnits = [
"systemd-repart.service" "systemd-repart.service"
]; ];
@ -73,7 +88,7 @@ in
# Override defaults in upstream unit. # Override defaults in upstream unit.
services.systemd-repart = { services.systemd-repart = {
# Unset the coniditions as they cannot be met before activation because # Unset the conditions as they cannot be met before activation because
# the definition files are not stored in the expected locations. # the definition files are not stored in the expected locations.
unitConfig.ConditionDirectoryNotEmpty = [ unitConfig.ConditionDirectoryNotEmpty = [
" " # required to unset the previous value. " " # required to unset the previous value.
@ -97,5 +112,12 @@ in
after = [ "sysroot.mount" ]; after = [ "sysroot.mount" ];
}; };
}; };
systemd = lib.mkIf cfg.enable {
additionalUpstreamSystemUnits = [
"systemd-repart.service"
];
};
}; };
} }

View file

@ -163,7 +163,7 @@ in
###### implementation ###### implementation
config = mkIf cfg.enable (mkMerge [{ config = mkIf cfg.enable (mkMerge [{
boot.kernelModules = [ "bridge" "veth" ]; boot.kernelModules = [ "bridge" "veth" "br_netfilter" "xt_nat" ];
boot.kernel.sysctl = { boot.kernel.sysctl = {
"net.ipv4.conf.all.forwarding" = mkOverride 98 true; "net.ipv4.conf.all.forwarding" = mkOverride 98 true;
"net.ipv4.conf.default.forwarding" = mkOverride 98 true; "net.ipv4.conf.default.forwarding" = mkOverride 98 true;

View file

@ -514,6 +514,7 @@ in
}; };
in [ extraConfig ] ++ (map (x: x.value) defs); in [ extraConfig ] ++ (map (x: x.value) defs);
prefix = [ "containers" name ]; prefix = [ "containers" name ];
inherit (config) specialArgs;
}).config; }).config;
}; };
}; };
@ -555,6 +556,16 @@ in
''; '';
}; };
specialArgs = mkOption {
type = types.attrsOf types.unspecified;
default = {};
description = lib.mdDoc ''
A set of special arguments to be passed to NixOS modules.
This will be merged into the `specialArgs` used to evaluate
the NixOS configurations.
'';
};
ephemeral = mkOption { ephemeral = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;

View file

@ -9,8 +9,7 @@ let
extraPackages = cfg.extraPackages extraPackages = cfg.extraPackages
# setuid shadow # setuid shadow
++ [ "/run/wrappers" ] ++ [ "/run/wrappers" ]
# include pkgs.zfs by default in the wrapped podman used by the module so it is cached ++ lib.optional (builtins.elem "zfs" config.boot.supportedFilesystems) config.boot.zfs.package;
++ (if (builtins.elem "zfs" config.boot.supportedFilesystems) then [ config.boot.zfs.package ] else [ pkgs.zfs ]);
}); });
# Provides a fake "docker" binary mapping to podman # Provides a fake "docker" binary mapping to podman
@ -184,6 +183,10 @@ in
systemd.packages = [ cfg.package ]; systemd.packages = [ cfg.package ];
systemd.services.podman.serviceConfig = {
ExecStart = [ "" "${cfg.package}/bin/podman $LOGGING system service" ];
};
systemd.services.podman-prune = { systemd.services.podman-prune = {
description = "Prune podman resources"; description = "Prune podman resources";
@ -204,6 +207,10 @@ in
systemd.sockets.podman.wantedBy = [ "sockets.target" ]; systemd.sockets.podman.wantedBy = [ "sockets.target" ];
systemd.sockets.podman.socketConfig.SocketGroup = "podman"; systemd.sockets.podman.socketConfig.SocketGroup = "podman";
systemd.user.services.podman.serviceConfig = {
ExecStart = [ "" "${cfg.package}/bin/podman $LOGGING system service" ];
};
systemd.user.sockets.podman.wantedBy = [ "sockets.target" ]; systemd.user.sockets.podman.wantedBy = [ "sockets.target" ];
systemd.tmpfiles.packages = [ systemd.tmpfiles.packages = [

View file

@ -144,7 +144,6 @@ in rec {
manual = manualHTML; # TODO(@oxij): remove eventually manual = manualHTML; # TODO(@oxij): remove eventually
manualEpub = (buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manualEpub)); manualEpub = (buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manualEpub));
manpages = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manpages); manpages = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.manpages);
manualGeneratedSources = buildFromConfig ({ ... }: { }) (config: config.system.build.manual.generatedSources);
options = (buildFromConfig ({ ... }: { }) (config: config.system.build.manual.optionsJSON)).x86_64-linux; options = (buildFromConfig ({ ... }: { }) (config: config.system.build.manual.optionsJSON)).x86_64-linux;

View file

@ -368,6 +368,7 @@ in {
login = handleTest ./login.nix {}; login = handleTest ./login.nix {};
logrotate = handleTest ./logrotate.nix {}; logrotate = handleTest ./logrotate.nix {};
loki = handleTest ./loki.nix {}; loki = handleTest ./loki.nix {};
luks = handleTest ./luks.nix {};
lvm2 = handleTest ./lvm2 {}; lvm2 = handleTest ./lvm2 {};
lxd = handleTest ./lxd.nix {}; lxd = handleTest ./lxd.nix {};
lxd-nftables = handleTest ./lxd-nftables.nix {}; lxd-nftables = handleTest ./lxd-nftables.nix {};
@ -646,6 +647,7 @@ in {
systemd-confinement = handleTest ./systemd-confinement.nix {}; systemd-confinement = handleTest ./systemd-confinement.nix {};
systemd-coredump = handleTest ./systemd-coredump.nix {}; systemd-coredump = handleTest ./systemd-coredump.nix {};
systemd-cryptenroll = handleTest ./systemd-cryptenroll.nix {}; systemd-cryptenroll = handleTest ./systemd-cryptenroll.nix {};
systemd-credentials-tpm2 = handleTest ./systemd-credentials-tpm2.nix {};
systemd-escaping = handleTest ./systemd-escaping.nix {}; systemd-escaping = handleTest ./systemd-escaping.nix {};
systemd-initrd-btrfs-raid = handleTest ./systemd-initrd-btrfs-raid.nix {}; systemd-initrd-btrfs-raid = handleTest ./systemd-initrd-btrfs-raid.nix {};
systemd-initrd-luks-fido2 = handleTest ./systemd-initrd-luks-fido2.nix {}; systemd-initrd-luks-fido2 = handleTest ./systemd-initrd-luks-fido2.nix {};
@ -656,6 +658,7 @@ in {
systemd-initrd-shutdown = handleTest ./systemd-shutdown.nix { systemdStage1 = true; }; systemd-initrd-shutdown = handleTest ./systemd-shutdown.nix { systemdStage1 = true; };
systemd-initrd-simple = handleTest ./systemd-initrd-simple.nix {}; systemd-initrd-simple = handleTest ./systemd-initrd-simple.nix {};
systemd-initrd-swraid = handleTest ./systemd-initrd-swraid.nix {}; systemd-initrd-swraid = handleTest ./systemd-initrd-swraid.nix {};
systemd-initrd-vconsole = handleTest ./systemd-initrd-vconsole.nix {};
systemd-journal = handleTest ./systemd-journal.nix {}; systemd-journal = handleTest ./systemd-journal.nix {};
systemd-machinectl = handleTest ./systemd-machinectl.nix {}; systemd-machinectl = handleTest ./systemd-machinectl.nix {};
systemd-networkd = handleTest ./systemd-networkd.nix {}; systemd-networkd = handleTest ./systemd-networkd.nix {};

View file

@ -40,7 +40,7 @@ import ./make-test-python.nix (
networking.extraHosts = '' networking.extraHosts = ''
127.0.0.1 ${discourseDomain} 127.0.0.1 ${discourseDomain}
${nodes.client.config.networking.primaryIPAddress} ${clientDomain} ${nodes.client.networking.primaryIPAddress} ${clientDomain}
''; '';
services.postfix = { services.postfix = {
@ -90,7 +90,7 @@ import ./make-test-python.nix (
networking.extraHosts = '' networking.extraHosts = ''
127.0.0.1 ${clientDomain} 127.0.0.1 ${clientDomain}
${nodes.discourse.config.networking.primaryIPAddress} ${discourseDomain} ${nodes.discourse.networking.primaryIPAddress} ${discourseDomain}
''; '';
services.dovecot2 = { services.dovecot2 = {
@ -178,8 +178,8 @@ import ./make-test-python.nix (
discourse.wait_until_succeeds("curl -sS -f https://${discourseDomain}") discourse.wait_until_succeeds("curl -sS -f https://${discourseDomain}")
discourse.succeed( discourse.succeed(
"curl -sS -f https://${discourseDomain}/session/csrf -c cookie -b cookie -H 'Accept: application/json' | jq -r '\"X-CSRF-Token: \" + .csrf' > csrf_token", "curl -sS -f https://${discourseDomain}/session/csrf -c cookie -b cookie -H 'Accept: application/json' | jq -r '\"X-CSRF-Token: \" + .csrf' > csrf_token",
"curl -sS -f https://${discourseDomain}/session -c cookie -b cookie -H @csrf_token -H 'Accept: application/json' -d 'login=${nodes.discourse.config.services.discourse.admin.username}' -d \"password=${adminPassword}\" | jq -e '.user.username == \"${nodes.discourse.config.services.discourse.admin.username}\"'", "curl -sS -f https://${discourseDomain}/session -c cookie -b cookie -H @csrf_token -H 'Accept: application/json' -d 'login=${nodes.discourse.services.discourse.admin.username}' -d \"password=${adminPassword}\" | jq -e '.user.username == \"${nodes.discourse.services.discourse.admin.username}\"'",
"curl -sS -f https://${discourseDomain}/login -v -H 'Accept: application/json' -c cookie -b cookie 2>&1 | grep ${nodes.discourse.config.services.discourse.admin.username}", "curl -sS -f https://${discourseDomain}/login -v -H 'Accept: application/json' -c cookie -b cookie 2>&1 | grep ${nodes.discourse.services.discourse.admin.username}",
) )
client.wait_for_unit("postfix.service") client.wait_for_unit("postfix.service")

View file

@ -103,6 +103,16 @@ class ReqHandler(BaseHTTPRequestHandler):
self._send_json_ok(gen_mockuser(username=username, uid=uid, gid=uid, home_directory=f"/home/{username}", snakeoil_pubkey=SNAKEOIL_PUBLIC_KEY)) self._send_json_ok(gen_mockuser(username=username, uid=uid, gid=uid, home_directory=f"/home/{username}", snakeoil_pubkey=SNAKEOIL_PUBLIC_KEY))
return return
# we need to provide something at the groups endpoint.
# the nss module does segfault if we don't.
elif pu.path == "/computeMetadata/v1/oslogin/groups":
self._send_json_ok({
"posixGroups": [
{"name" : "demo", "gid" : 4294967295}
],
})
return
# authorize endpoint # authorize endpoint
elif pu.path == "/computeMetadata/v1/oslogin/authorize": elif pu.path == "/computeMetadata/v1/oslogin/authorize":
# is user allowed to login? # is user allowed to login?

View file

@ -22,22 +22,23 @@ in {
enable = true; enable = true;
inherit configDir; inherit configDir;
# tests loading components by overriding the package # provide dependencies through package overrides
package = (pkgs.home-assistant.override { package = (pkgs.home-assistant.override {
extraPackages = ps: with ps; [ extraPackages = ps: with ps; [
colorama colorama
]; ];
extraComponents = [ "zha" ]; extraComponents = [
}).overrideAttrs (oldAttrs: { # test char-tty device allow propagation into the service
doInstallCheck = false; "zha"
];
}); });
# tests loading components from the module # provide component dependencies explicitly from the module
extraComponents = [ extraComponents = [
"wake_on_lan" "mqtt"
]; ];
# test extra package passing from the module # provide package for postgresql support
extraPackages = python3Packages: with python3Packages; [ extraPackages = python3Packages: with python3Packages; [
psycopg2 psycopg2
]; ];
@ -111,36 +112,38 @@ in {
}; };
testScript = { nodes, ... }: let testScript = { nodes, ... }: let
system = nodes.hass.config.system.build.toplevel; system = nodes.hass.system.build.toplevel;
in in
'' ''
import re
import json import json
start_all() start_all()
# Parse the package path out of the systemd unit, as we cannot
# access the final package, that is overridden inside the module,
# by any other means.
pattern = re.compile(r"path=(?P<path>[\/a-z0-9-.]+)\/bin\/hass")
response = hass.execute("systemctl show -p ExecStart home-assistant.service")[1]
match = pattern.search(response)
assert match
package = match.group('path')
def get_journal_cursor() -> str:
def get_journal_cursor(host) -> str: exit, out = hass.execute("journalctl -u home-assistant.service -n1 -o json-pretty --output-fields=__CURSOR")
exit, out = host.execute("journalctl -u home-assistant.service -n1 -o json-pretty --output-fields=__CURSOR")
assert exit == 0 assert exit == 0
return json.loads(out)["__CURSOR"] return json.loads(out)["__CURSOR"]
def wait_for_homeassistant(host, cursor): def get_journal_since(cursor) -> str:
host.wait_until_succeeds(f"journalctl --after-cursor='{cursor}' -u home-assistant.service | grep -q 'Home Assistant initialized in'") exit, out = hass.execute(f"journalctl --after-cursor='{cursor}' -u home-assistant.service")
assert exit == 0
return out
def get_unit_property(property) -> str:
exit, out = hass.execute(f"systemctl show --property={property} home-assistant.service")
assert exit == 0
return out
def wait_for_homeassistant(cursor):
hass.wait_until_succeeds(f"journalctl --after-cursor='{cursor}' -u home-assistant.service | grep -q 'Home Assistant initialized in'")
hass.wait_for_unit("home-assistant.service") hass.wait_for_unit("home-assistant.service")
cursor = get_journal_cursor(hass) cursor = get_journal_cursor()
with subtest("Check that YAML configuration file is in place"): with subtest("Check that YAML configuration file is in place"):
hass.succeed("test -L ${configDir}/configuration.yaml") hass.succeed("test -L ${configDir}/configuration.yaml")
@ -148,19 +151,22 @@ in {
with subtest("Check the lovelace config is copied because lovelaceConfigWritable = true"): with subtest("Check the lovelace config is copied because lovelaceConfigWritable = true"):
hass.succeed("test -f ${configDir}/ui-lovelace.yaml") hass.succeed("test -f ${configDir}/ui-lovelace.yaml")
with subtest("Check extraComponents and extraPackages are considered from the package"):
hass.succeed(f"grep -q 'colorama' {package}/extra_packages")
hass.succeed(f"grep -q 'zha' {package}/extra_components")
with subtest("Check extraComponents and extraPackages are considered from the module"):
hass.succeed(f"grep -q 'psycopg2' {package}/extra_packages")
hass.succeed(f"grep -q 'wake_on_lan' {package}/extra_components")
with subtest("Check that Home Assistant's web interface and API can be reached"): with subtest("Check that Home Assistant's web interface and API can be reached"):
wait_for_homeassistant(hass, cursor) wait_for_homeassistant(cursor)
hass.wait_for_open_port(8123) hass.wait_for_open_port(8123)
hass.succeed("curl --fail http://localhost:8123/lovelace") hass.succeed("curl --fail http://localhost:8123/lovelace")
with subtest("Check that optional dependencies are in the PYTHONPATH"):
env = get_unit_property("Environment")
python_path = env.split("PYTHONPATH=")[1].split()[0]
for package in ["colorama", "paho-mqtt", "psycopg2"]:
assert package in python_path, f"{package} not in PYTHONPATH"
with subtest("Check that declaratively configured components get setup"):
journal = get_journal_since(cursor)
for domain in ["emulated_hue", "wake_on_lan"]:
assert f"Setup of domain {domain} took" in journal, f"{domain} setup missing"
with subtest("Check that capabilities are passed for emulated_hue to bind to port 80"): with subtest("Check that capabilities are passed for emulated_hue to bind to port 80"):
hass.wait_for_open_port(80) hass.wait_for_open_port(80)
hass.succeed("curl --fail http://localhost:80/description.xml") hass.succeed("curl --fail http://localhost:80/description.xml")
@ -169,25 +175,28 @@ in {
hass.succeed("systemctl show -p DeviceAllow home-assistant.service | grep -q char-ttyUSB") hass.succeed("systemctl show -p DeviceAllow home-assistant.service | grep -q char-ttyUSB")
with subtest("Check service reloads when configuration changes"): with subtest("Check service reloads when configuration changes"):
# store the old pid of the process pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
pid = hass.succeed("systemctl show --property=MainPID home-assistant.service") cursor = get_journal_cursor()
cursor = get_journal_cursor(hass) hass.succeed("${system}/specialisation/differentName/bin/switch-to-configuration test")
hass.succeed("${system}/specialisation/differentName/bin/switch-to-configuration test") new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service") assert pid == new_pid, "The PID of the process should not change between process reloads"
assert pid == new_pid, "The PID of the process should not change between process reloads" wait_for_homeassistant(cursor)
wait_for_homeassistant(hass, cursor)
with subtest("check service restarts when package changes"): with subtest("Check service restarts when dependencies change"):
pid = new_pid pid = new_pid
cursor = get_journal_cursor(hass) cursor = get_journal_cursor()
hass.succeed("${system}/specialisation/newFeature/bin/switch-to-configuration test") hass.succeed("${system}/specialisation/newFeature/bin/switch-to-configuration test")
new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service") new_pid = hass.succeed("systemctl show --property=MainPID home-assistant.service")
assert pid != new_pid, "The PID of the process shoudl change when the HA binary changes" assert pid != new_pid, "The PID of the process should change when its PYTHONPATH changess"
wait_for_homeassistant(hass, cursor) wait_for_homeassistant(cursor)
with subtest("Check that new components get setup after restart"):
journal = get_journal_since(cursor)
for domain in ["esphome"]:
assert f"Setup of domain {domain} took" in journal, f"{domain} setup missing"
with subtest("Check that no errors were logged"): with subtest("Check that no errors were logged"):
output_log = hass.succeed("cat ${configDir}/home-assistant.log") hass.fail("journalctl -u home-assistant -o cat | grep -q ERROR")
assert "ERROR" not in output_log
with subtest("Check systemd unit hardening"): with subtest("Check systemd unit hardening"):
hass.log(hass.succeed("systemctl cat home-assistant.service")) hass.log(hass.succeed("systemctl cat home-assistant.service"))

View file

@ -77,6 +77,9 @@ import ../make-test-python.nix ({ pkgs, lib, k3s, ... }:
machine.succeed("k3s kubectl wait --for 'condition=Ready' pod/test") machine.succeed("k3s kubectl wait --for 'condition=Ready' pod/test")
machine.succeed("k3s kubectl delete -f ${testPodYaml}") machine.succeed("k3s kubectl delete -f ${testPodYaml}")
# regression test for #176445
machine.fail("journalctl -o cat -u k3s.service | grep 'ipset utility not found'")
machine.shutdown() machine.shutdown()
''; '';
}) })

View file

@ -4,6 +4,7 @@ import ./make-test-python.nix ({ pkgs, ...} :
name = "keepassxc"; name = "keepassxc";
meta = with pkgs.lib.maintainers; { meta = with pkgs.lib.maintainers; {
maintainers = [ turion ]; maintainers = [ turion ];
timeout = 1800;
}; };
nodes.machine = { ... }: nodes.machine = { ... }:
@ -55,9 +56,12 @@ import ./make-test-python.nix ({ pkgs, ...} :
machine.sleep(5) machine.sleep(5)
# Regression #163482: keepassxc did not crash # Regression #163482: keepassxc did not crash
machine.succeed("ps -e | grep keepassxc") machine.succeed("ps -e | grep keepassxc")
machine.wait_for_text("foo.kdbx") machine.wait_for_text("Open database")
machine.send_key("ret") machine.send_key("ret")
machine.sleep(1)
# Wait for the enter password screen to appear.
machine.wait_for_text("/home/alice/foo.kdbx")
# Click on "Browse" button to select keyfile # Click on "Browse" button to select keyfile
machine.send_key("tab") machine.send_key("tab")
machine.send_chars("/home/alice/foo.keyfile") machine.send_chars("/home/alice/foo.keyfile")

View file

@ -0,0 +1,69 @@
import ./make-test-python.nix ({ lib, pkgs, ... }: {
name = "luks";
nodes.machine = { pkgs, ... }: {
# Use systemd-boot
virtualisation = {
emptyDiskImages = [ 512 512 ];
useBootLoader = true;
useEFIBoot = true;
};
boot.loader.systemd-boot.enable = true;
boot.kernelParams = lib.mkOverride 5 [ "console=tty1" ];
environment.systemPackages = with pkgs; [ cryptsetup ];
specialisation = rec {
boot-luks.configuration = {
boot.initrd.luks.devices = lib.mkVMOverride {
# We have two disks and only type one password - key reuse is in place
cryptroot.device = "/dev/vdc";
cryptroot2.device = "/dev/vdd";
};
virtualisation.bootDevice = "/dev/mapper/cryptroot";
};
boot-luks-custom-keymap.configuration = lib.mkMerge [
boot-luks.configuration
{
console.keyMap = "neo";
}
];
};
};
enableOCR = true;
testScript = ''
# Create encrypted volume
machine.wait_for_unit("multi-user.target")
machine.succeed("echo -n supersecret | cryptsetup luksFormat -q --iter-time=1 /dev/vdc -")
machine.succeed("echo -n supersecret | cryptsetup luksFormat -q --iter-time=1 /dev/vdd -")
# Boot from the encrypted disk
machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks.conf")
machine.succeed("sync")
machine.crash()
# Boot and decrypt the disk
machine.start()
machine.wait_for_text("Passphrase for")
machine.send_chars("supersecret\n")
machine.wait_for_unit("multi-user.target")
assert "/dev/mapper/cryptroot on / type ext4" in machine.succeed("mount")
# Boot from the encrypted disk with custom keymap
machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-luks-custom-keymap.conf")
machine.succeed("sync")
machine.crash()
# Boot and decrypt the disk
machine.start()
machine.wait_for_text("Passphrase for")
machine.send_chars("havfkhfrkfl\n")
machine.wait_for_unit("multi-user.target")
assert "/dev/mapper/cryptroot on / type ext4" in machine.succeed("mount")
'';
})

View file

@ -9,6 +9,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
hostname = "server"; hostname = "server";
primaryDomain = "server"; primaryDomain = "server";
openFirewall = true; openFirewall = true;
ensureAccounts = [ "postmaster@server" ];
}; };
}; };
@ -50,7 +51,6 @@ import ./make-test-python.nix ({ pkgs, ... }: {
server.wait_for_open_port(587) server.wait_for_open_port(587)
server.succeed("maddyctl creds create --password test postmaster@server") server.succeed("maddyctl creds create --password test postmaster@server")
server.succeed("maddyctl imap-acct create postmaster@server")
client.succeed("send-testmail") client.succeed("send-testmail")
client.succeed("test-imap") client.succeed("test-imap")

View file

@ -3,7 +3,10 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
meta = { meta = {
maintainers = with lib.maintainers; [ OPNA2608 ]; maintainers = with lib.maintainers; [ OPNA2608 ];
# FIXME On ARM Miriway inside the VM doesn't receive keyboard inputs, why? # Natively running Mir has problems with capturing the first registered libinput device.
# In our VM runners on ARM and on some hardware configs (my RPi4, distro-independent), this misses the keyboard.
# It can be worked around by dis- and reconnecting the affected hardware, but we can't do this in these tests.
# https://github.com/MirServer/mir/issues/2837
broken = pkgs.stdenv.hostPlatform.isAarch; broken = pkgs.stdenv.hostPlatform.isAarch;
}; };
@ -30,6 +33,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
enable = true; enable = true;
config = '' config = ''
add-wayland-extensions=all add-wayland-extensions=all
enable-x11=
ctrl-alt=t:foot --maximized ctrl-alt=t:foot --maximized
ctrl-alt=a:env WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY=invalid alacritty --option window.startup_mode=maximized ctrl-alt=a:env WINIT_UNIX_BACKEND=x11 WAYLAND_DISPLAY=invalid alacritty --option window.startup_mode=maximized

View file

@ -1,6 +1,6 @@
import ./make-test-python.nix ({ pkgs, lib, ... }: { import ./make-test-python.nix ({ pkgs, lib, ... }: {
name = "pass-secret-service"; name = "pass-secret-service";
meta.maintainers = with lib; [ aidalgol ]; meta.maintainers = [ lib.maintainers.aidalgol ];
nodes.machine = { nodes, pkgs, ... }: nodes.machine = { nodes, pkgs, ... }:
{ {

View file

@ -6,7 +6,10 @@ import ../make-test-python.nix (
}; };
nodes = { nodes = {
podman = { pkgs, ... }: { rootful = { pkgs, ... }: {
virtualisation.podman.enable = true;
};
rootless = { pkgs, ... }: {
virtualisation.podman.enable = true; virtualisation.podman.enable = true;
users.users.alice = { users.users.alice = {
@ -49,101 +52,109 @@ import ../make-test-python.nix (
return f"su {user} -l -c {cmd}" return f"su {user} -l -c {cmd}"
podman.wait_for_unit("sockets.target") rootful.wait_for_unit("sockets.target")
rootless.wait_for_unit("sockets.target")
dns.wait_for_unit("sockets.target") dns.wait_for_unit("sockets.target")
docker.wait_for_unit("sockets.target") docker.wait_for_unit("sockets.target")
start_all() start_all()
with subtest("Run container as root with runc"): with subtest("Run container as root with runc"):
podman.succeed("tar cv --files-from /dev/null | podman import - scratchimg") rootful.succeed("tar cv --files-from /dev/null | podman import - scratchimg")
podman.succeed( rootful.succeed(
"podman run --runtime=runc -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10" "podman run --runtime=runc -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10"
) )
podman.succeed("podman ps | grep sleeping") rootful.succeed("podman ps | grep sleeping")
podman.succeed("podman stop sleeping") rootful.succeed("podman stop sleeping")
podman.succeed("podman rm sleeping") rootful.succeed("podman rm sleeping")
with subtest("Run container as root with crun"): with subtest("Run container as root with crun"):
podman.succeed("tar cv --files-from /dev/null | podman import - scratchimg") rootful.succeed("tar cv --files-from /dev/null | podman import - scratchimg")
podman.succeed( rootful.succeed(
"podman run --runtime=crun -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10" "podman run --runtime=crun -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10"
) )
podman.succeed("podman ps | grep sleeping") rootful.succeed("podman ps | grep sleeping")
podman.succeed("podman stop sleeping") rootful.succeed("podman stop sleeping")
podman.succeed("podman rm sleeping") rootful.succeed("podman rm sleeping")
with subtest("Run container as root with the default backend"): with subtest("Run container as root with the default backend"):
podman.succeed("tar cv --files-from /dev/null | podman import - scratchimg") rootful.succeed("tar cv --files-from /dev/null | podman import - scratchimg")
podman.succeed( rootful.succeed(
"podman run -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10" "podman run -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10"
) )
podman.succeed("podman ps | grep sleeping") rootful.succeed("podman ps | grep sleeping")
podman.succeed("podman stop sleeping") rootful.succeed("podman stop sleeping")
podman.succeed("podman rm sleeping") rootful.succeed("podman rm sleeping")
# start systemd session for rootless # start systemd session for rootless
podman.succeed("loginctl enable-linger alice") rootless.succeed("loginctl enable-linger alice")
podman.succeed(su_cmd("whoami")) rootless.succeed(su_cmd("whoami"))
podman.sleep(1) rootless.sleep(1)
with subtest("Run container rootless with runc"): with subtest("Run container rootless with runc"):
podman.succeed(su_cmd("tar cv --files-from /dev/null | podman import - scratchimg")) rootless.succeed(su_cmd("tar cv --files-from /dev/null | podman import - scratchimg"))
podman.succeed( rootless.succeed(
su_cmd( su_cmd(
"podman run --runtime=runc -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10" "podman run --runtime=runc -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10"
) )
) )
podman.succeed(su_cmd("podman ps | grep sleeping")) rootless.succeed(su_cmd("podman ps | grep sleeping"))
podman.succeed(su_cmd("podman stop sleeping")) rootless.succeed(su_cmd("podman stop sleeping"))
podman.succeed(su_cmd("podman rm sleeping")) rootless.succeed(su_cmd("podman rm sleeping"))
with subtest("Run container rootless with crun"): with subtest("Run container rootless with crun"):
podman.succeed(su_cmd("tar cv --files-from /dev/null | podman import - scratchimg")) rootless.succeed(su_cmd("tar cv --files-from /dev/null | podman import - scratchimg"))
podman.succeed( rootless.succeed(
su_cmd( su_cmd(
"podman run --runtime=crun -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10" "podman run --runtime=crun -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10"
) )
) )
podman.succeed(su_cmd("podman ps | grep sleeping")) rootless.succeed(su_cmd("podman ps | grep sleeping"))
podman.succeed(su_cmd("podman stop sleeping")) rootless.succeed(su_cmd("podman stop sleeping"))
podman.succeed(su_cmd("podman rm sleeping")) rootless.succeed(su_cmd("podman rm sleeping"))
with subtest("Run container rootless with the default backend"): with subtest("Run container rootless with the default backend"):
podman.succeed(su_cmd("tar cv --files-from /dev/null | podman import - scratchimg")) rootless.succeed(su_cmd("tar cv --files-from /dev/null | podman import - scratchimg"))
podman.succeed( rootless.succeed(
su_cmd( su_cmd(
"podman run -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10" "podman run -d --name=sleeping -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg /bin/sleep 10"
) )
) )
podman.succeed(su_cmd("podman ps | grep sleeping")) rootless.succeed(su_cmd("podman ps | grep sleeping"))
podman.succeed(su_cmd("podman stop sleeping")) rootless.succeed(su_cmd("podman stop sleeping"))
podman.succeed(su_cmd("podman rm sleeping")) rootless.succeed(su_cmd("podman rm sleeping"))
with subtest("rootlessport"):
rootless.succeed(su_cmd("tar cv --files-from /dev/null | podman import - scratchimg"))
rootless.succeed(
su_cmd(
"podman run -d -p 9000:8888 --name=rootlessport -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin -w ${pkgs.writeTextDir "index.html" "<h1>Testing</h1>"} scratchimg ${pkgs.python3}/bin/python -m http.server 8888"
)
)
rootless.succeed(su_cmd("podman ps | grep rootlessport"))
rootless.wait_until_succeeds(su_cmd("${pkgs.curl}/bin/curl localhost:9000 | grep Testing"))
rootless.succeed(su_cmd("podman stop rootlessport"))
rootless.succeed(su_cmd("podman rm rootlessport"))
with subtest("Run container with init"): with subtest("Run container with init"):
podman.succeed( rootful.succeed(
"tar cv -C ${pkgs.pkgsStatic.busybox} . | podman import - busybox" "tar cv -C ${pkgs.pkgsStatic.busybox} . | podman import - busybox"
) )
pid = podman.succeed("podman run --rm busybox readlink /proc/self").strip() pid = rootful.succeed("podman run --rm busybox readlink /proc/self").strip()
assert pid == "1" assert pid == "1"
pid = podman.succeed("podman run --rm --init busybox readlink /proc/self").strip() pid = rootful.succeed("podman run --rm --init busybox readlink /proc/self").strip()
assert pid == "2" assert pid == "2"
with subtest("aardvark-dns"): with subtest("aardvark-dns"):
dns.succeed("tar cv --files-from /dev/null | podman import - scratchimg") dns.succeed("tar cv --files-from /dev/null | podman import - scratchimg")
dns.succeed( dns.succeed(
"podman run -d --name=webserver -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin -w ${pkgs.writeTextDir "index.html" "<h1>Hi</h1>"} scratchimg ${pkgs.python3}/bin/python -m http.server 8000" "podman run -d --name=webserver -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin -w ${pkgs.writeTextDir "index.html" "<h1>Testing</h1>"} scratchimg ${pkgs.python3}/bin/python -m http.server 8000"
) )
dns.succeed("podman ps | grep webserver") dns.succeed("podman ps | grep webserver")
dns.succeed(""" dns.wait_until_succeeds(
for i in `seq 0 120`; do "podman run --rm --name=client -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg ${pkgs.curl}/bin/curl http://webserver:8000 | grep Testing"
podman run --rm --name=client -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg ${pkgs.curl}/bin/curl http://webserver:8000 >/dev/console \ )
&& exit 0 dns.succeed("podman stop webserver")
sleep 0.5 dns.succeed("podman rm webserver")
done
exit 1
""")
dns.succeed("podman stop webserver")
dns.succeed("podman rm webserver")
with subtest("A podman member can use the docker cli"): with subtest("A podman member can use the docker cli"):
docker.succeed(su_cmd("docker version")) docker.succeed(su_cmd("docker version"))

View file

@ -1,4 +1,4 @@
import ./make-test-python.nix ({ pkgs, ...} : import ./make-test-python.nix ({ pkgs, lib, ...} :
let let
@ -11,9 +11,9 @@ let
}; };
# Only allow the demo data to be used (only if it's unfreeRedistributable). # Only allow the demo data to be used (only if it's unfreeRedistributable).
unfreePredicate = pkg: with pkgs.lib; let unfreePredicate = pkg: with lib; let
allowPackageNames = [ "quake3-demodata" "quake3-pointrelease" ]; allowPackageNames = [ "quake3-demodata" "quake3-pointrelease" ];
allowLicenses = [ pkgs.lib.licenses.unfreeRedistributable ]; allowLicenses = [ lib.licenses.unfreeRedistributable ];
in elem pkg.pname allowPackageNames && in elem pkg.pname allowPackageNames &&
elem (pkg.meta.license or null) allowLicenses; elem (pkg.meta.license or null) allowLicenses;
@ -31,7 +31,7 @@ in
rec { rec {
name = "quake3"; name = "quake3";
meta = with pkgs.stdenv.lib.maintainers; { meta = with lib.maintainers; {
maintainers = [ domenkozar eelco ]; maintainers = [ domenkozar eelco ];
}; };

View file

@ -0,0 +1,124 @@
import ./make-test-python.nix ({ lib, pkgs, system, ... }:
let
tpmSocketPath = "/tmp/swtpm-sock";
tpmDeviceModels = {
x86_64-linux = "tpm-tis";
aarch64-linux = "tpm-tis-device";
};
in
{
name = "systemd-credentials-tpm2";
meta = {
maintainers = with pkgs.lib.maintainers; [ tmarkus ];
};
nodes.machine = { pkgs, ... }: {
virtualisation = {
qemu.options = [
"-chardev socket,id=chrtpm,path=${tpmSocketPath}"
"-tpmdev emulator,id=tpm_dev_0,chardev=chrtpm"
"-device ${tpmDeviceModels.${system}},tpmdev=tpm_dev_0"
];
};
boot.initrd.availableKernelModules = [ "tpm_tis" ];
environment.systemPackages = with pkgs; [ diffutils ];
};
testScript = ''
import subprocess
from tempfile import TemporaryDirectory
# From systemd-initrd-luks-tpm2.nix
class Tpm:
def __init__(self):
self.state_dir = TemporaryDirectory()
self.start()
def start(self):
self.proc = subprocess.Popen(["${pkgs.swtpm}/bin/swtpm",
"socket",
"--tpmstate", f"dir={self.state_dir.name}",
"--ctrl", "type=unixio,path=${tpmSocketPath}",
"--tpm2",
])
# Check whether starting swtpm failed
try:
exit_code = self.proc.wait(timeout=0.2)
if exit_code is not None and exit_code != 0:
raise Exception("failed to start swtpm")
except subprocess.TimeoutExpired:
pass
"""Check whether the swtpm process exited due to an error"""
def check(self):
exit_code = self.proc.poll()
if exit_code is not None and exit_code != 0:
raise Exception("swtpm process died")
CRED_NAME = "testkey"
CRED_RAW_FILE = f"/root/{CRED_NAME}"
CRED_FILE = f"/root/{CRED_NAME}.cred"
def systemd_run(machine, cmd):
machine.log(f"Executing command (via systemd-run): \"{cmd}\"")
(status, out) = machine.execute( " ".join([
"systemd-run",
"--service-type=exec",
"--quiet",
"--wait",
"-E PATH=\"$PATH\"",
"-p StandardOutput=journal",
"-p StandardError=journal",
f"-p LoadCredentialEncrypted={CRED_NAME}:{CRED_FILE}",
f"$SHELL -c '{cmd}'"
]) )
if status != 0:
raise Exception(f"systemd_run failed (status {status})")
machine.log("systemd-run finished successfully")
tpm = Tpm()
@polling_condition
def swtpm_running():
tpm.check()
machine.wait_for_unit("multi-user.target")
with subtest("Check whether TPM device exists"):
machine.succeed("test -e /dev/tpm0")
machine.succeed("test -e /dev/tpmrm0")
with subtest("Check whether systemd-creds detects TPM2 correctly"):
cmd = "systemd-creds has-tpm2"
machine.log(f"Running \"{cmd}\"")
(status, _) = machine.execute(cmd)
# Check exit code equals 0 or 1 (1 means firmware support is missing, which is OK here)
if status != 0 and status != 1:
raise Exception("systemd-creds failed to detect TPM2")
with subtest("Encrypt credential using systemd-creds"):
machine.succeed(f"dd if=/dev/urandom of={CRED_RAW_FILE} bs=1k count=16")
machine.succeed(f"systemd-creds --with-key=host+tpm2 encrypt --name=testkey {CRED_RAW_FILE} {CRED_FILE}")
with subtest("Write provided credential and check for equality"):
CRED_OUT_FILE = f"/root/{CRED_NAME}.out"
systemd_run(machine, f"systemd-creds cat testkey > {CRED_OUT_FILE}")
machine.succeed(f"cmp --silent -- {CRED_RAW_FILE} {CRED_OUT_FILE}")
with subtest("Check whether systemd service can see credential in systemd-creds list"):
systemd_run(machine, f"systemd-creds list | grep {CRED_NAME}")
with subtest("Check whether systemd service can access credential in $CREDENTIALS_DIRECTORY"):
systemd_run(machine, f"cmp --silent -- $CREDENTIALS_DIRECTORY/{CRED_NAME} {CRED_RAW_FILE}")
'';
})

View file

@ -0,0 +1,33 @@
import ./make-test-python.nix ({ lib, pkgs, ... }: {
name = "systemd-initrd-vconsole";
nodes.machine = { pkgs, ... }: {
boot.kernelParams = [ "rd.systemd.unit=rescue.target" ];
boot.initrd.systemd = {
enable = true;
emergencyAccess = true;
};
console = {
earlySetup = true;
keyMap = "colemak";
};
};
testScript = ''
# Boot into rescue shell in initrd
machine.start()
machine.wait_for_console_text("Press Enter for maintenance")
machine.send_console("\n")
machine.wait_for_console_text("Logging in with home")
# Check keymap
machine.send_console("(printf '%s to receive text: \\n' Ready && read text && echo \"$text\") </dev/tty1\n")
machine.wait_for_console_text("Ready to receive text:")
for key in "asdfjkl;\n":
machine.send_key(key)
machine.wait_for_console_text("arstneio")
machine.send_console("systemctl poweroff\n")
'';
})

View file

@ -52,9 +52,6 @@ let
}; };
}; };
boot.initrd.systemd.enable = true;
boot.initrd.systemd.repart.enable = true;
# systemd-repart operates on disks with a partition table. The qemu module, # systemd-repart operates on disks with a partition table. The qemu module,
# however, creates separate filesystem images without a partition table, so # however, creates separate filesystem images without a partition table, so
# we have to create a disk image manually. # we have to create a disk image manually.
@ -88,7 +85,10 @@ in
nodes.machine = { config, pkgs, ... }: { nodes.machine = { config, pkgs, ... }: {
imports = [ common ]; imports = [ common ];
boot.initrd.systemd.repart.partitions = { boot.initrd.systemd.enable = true;
boot.initrd.systemd.repart.enable = true;
systemd.repart.partitions = {
"10-root" = { "10-root" = {
Type = "linux-generic"; Type = "linux-generic";
}; };
@ -105,4 +105,30 @@ in
assert "Growing existing partition 1." in systemd_repart_logs assert "Growing existing partition 1." in systemd_repart_logs
''; '';
}; };
after-initrd = makeTest {
name = "systemd-repart-after-initrd";
meta.maintainers = with maintainers; [ nikstur ];
nodes.machine = { config, pkgs, ... }: {
imports = [ common ];
systemd.repart.enable = true;
systemd.repart.partitions = {
"10-root" = {
Type = "linux-generic";
};
};
};
testScript = { nodes, ... }: ''
${useDiskImage nodes.machine}
machine.start()
machine.wait_for_unit("multi-user.target")
systemd_repart_logs = machine.succeed("journalctl --unit systemd-repart.service")
assert "Growing existing partition 1." in systemd_repart_logs
'';
};
} }

View file

@ -19,20 +19,20 @@
stdenv.mkDerivation rec { stdenv.mkDerivation rec {
pname = "amberol"; pname = "amberol";
version = "0.9.2"; version = "unstable-2023-01-12";
src = fetchFromGitLab { src = fetchFromGitLab {
domain = "gitlab.gnome.org"; domain = "gitlab.gnome.org";
owner = "World"; owner = "World";
repo = pname; repo = pname;
rev = version; rev = "0623386c813d0d68564002324958cef7217cec7f";
hash = "sha256-L8yHKwtCAZC1myIouL0Oq3lj0QPWn5dVe0g3nkyAKI8="; hash = "sha256-nVL4ydTg4ncDCA9J9qWv+RPDC0Txr/qpo5XxIUiV0zQ=";
}; };
cargoDeps = rustPlatform.fetchCargoTarball { cargoDeps = rustPlatform.fetchCargoTarball {
inherit src; inherit src;
name = "${pname}-${version}"; name = "${pname}-${version}";
hash = "sha256-0XuWBUG37GNHRXgjz0/Vv6VSqaPG36xTj7oN0ukFIJY="; hash = "sha256-E0ivUWD3jP/T1GOJ11grDwcF+m92I+W2a2HhZX1bCso=";
}; };
postPatch = '' postPatch = ''

View file

@ -39,7 +39,7 @@ stdenv.mkDerivation rec {
meta = with lib; { meta = with lib; {
description = "Realtime modular synthesizer for ALSA"; description = "Realtime modular synthesizer for ALSA";
homepage = "http://alsamodular.sourceforge.net"; homepage = "https://alsamodular.sourceforge.net";
license = licenses.gpl2; license = licenses.gpl2;
platforms = platforms.linux; platforms = platforms.linux;
maintainers = with maintainers; [ sjfloat ]; maintainers = with maintainers; [ sjfloat ];

View file

@ -11,13 +11,13 @@
stdenv.mkDerivation rec { stdenv.mkDerivation rec {
pname = "ashuffle"; pname = "ashuffle";
version = "3.13.4"; version = "3.13.6";
src = fetchFromGitHub { src = fetchFromGitHub {
owner = "joshkunz"; owner = "joshkunz";
repo = "ashuffle"; repo = "ashuffle";
rev = "v${version}"; rev = "v${version}";
sha256 = "sha256-J6NN0Rsc9Zw9gagksDlwpwEErs+4XmrGF9YHKlAE1FA="; sha256 = "sha256-8XjLs4MI5MXvA6veCoTAj8tlYDe7YTggutO3F9eNyMM=";
fetchSubmodules = true; fetchSubmodules = true;
}; };

View file

@ -32,7 +32,7 @@ stdenv.mkDerivation rec {
meta = with lib; { meta = with lib; {
description = "A range of synthesiser, electric piano and organ emulations"; description = "A range of synthesiser, electric piano and organ emulations";
homepage = "http://bristol.sourceforge.net"; homepage = "https://bristol.sourceforge.net";
license = licenses.gpl3; license = licenses.gpl3;
platforms = ["x86_64-linux" "i686-linux"]; platforms = ["x86_64-linux" "i686-linux"];
maintainers = [ maintainers.goibhniu ]; maintainers = [ maintainers.goibhniu ];

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