Project import generated by Copybara.

GitOrigin-RevId: be0b453d7c7eee2090962c9a83749b024ff9acf5
This commit is contained in:
Default email 2020-12-25 14:55:36 +01:00
parent 0801daec24
commit b6d97fd731
1188 changed files with 43141 additions and 22988 deletions

View file

@ -7,11 +7,12 @@
## Suggestions for PRs
1. If it is unfinished but you plan to finish it, please mark it as a draft.
2. If you don't expect to work on it any time soon, closing it with a short comment may encourage someone else to pick up your work.
3. To get things rolling again, rebase the PR against the target branch and address valid comments.
4. If you need a review to move forward, ask in [the Discourse thread for PRs that need help](https://discourse.nixos.org/t/prs-in-distress/3604).
5. If all you need is a merge, check the git history to find and [request reviews](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/requesting-a-pull-request-review) from people who usually merge related contributions.
1. GitHub sometimes doesn't notify people who commented / reviewed a PR previously, when you (force) push commits. If you have addressed the reviews you can [officially ask for a review](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests/requesting-a-pull-request-review) from those who commented to you or anyone else.
2. If it is unfinished but you plan to finish it, please mark it as a draft.
3. If you don't expect to work on it any time soon, closing it with a short comment may encourage someone else to pick up your work.
4. To get things rolling again, rebase the PR against the target branch and address valid comments.
5. If you need a review to move forward, ask in [the Discourse thread for PRs that need help](https://discourse.nixos.org/t/prs-in-distress/3604).
6. If all you need is a merge, check the git history to find and [request reviews](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/requesting-a-pull-request-review) from people who usually merge related contributions.
## Suggestions for issues

View file

@ -0,0 +1,70 @@
# Fetchers {#chap-pkgs-fetchers}
When using Nix, you will frequently need to download source code and other files from the internet. Nixpkgs comes with a few helper functions that allow you to fetch fixed-output derivations in a structured way.
The two fetcher primitives are `fetchurl` and `fetchzip`. Both of these have two required arguments, a URL and a hash. The hash is typically `sha256`, although many more hash algorithms are supported. Nixpkgs contributors are currently recommended to use `sha256`. This hash will be used by Nix to identify your source. A typical usage of fetchurl is provided below.
```nix
{ stdenv, fetchurl }:
stdenv.mkDerivation {
name = "hello";
src = fetchurl {
url = "http://www.example.org/hello.tar.gz";
sha256 = "1111111111111111111111111111111111111111111111111111";
};
}
```
The main difference between `fetchurl` and `fetchzip` is in how they store the contents. `fetchurl` will store the unaltered contents of the URL within the Nix store. `fetchzip` on the other hand will decompress the archive for you, making files and directories directly accessible in the future. `fetchzip` can only be used with archives. Despite the name, `fetchzip` is not limited to .zip files and can also be used with any tarball.
`fetchpatch` works very similarly to `fetchurl` with the same arguments expected. It expects patch files as a source and and performs normalization on them before computing the checksum. For example it will remove comments or other unstable parts that are sometimes added by version control systems and can change over time.
Other fetcher functions allow you to add source code directly from a VCS such as subversion or git. These are mostly straightforward nambes based on the name of the command used with the VCS system. Because they give you a working repository, they act most like `fetchzip`.
## `fetchsvn`
Used with Subversion. Expects `url` to a Subversion directory, `rev`, and `sha256`.
## `fetchgit`
Used with Git. Expects `url` to a Git repo, `rev`, and `sha256`. `rev` in this case can be full the git commit id (SHA1 hash) or a tag name like `refs/tags/v1.0`.
## `fetchfossil`
Used with Fossil. Expects `url` to a Fossil archive, `rev`, and `sha256`.
## `fetchcvs`
Used with CVS. Expects `cvsRoot`, `tag`, and `sha256`.
## `fetchhg`
Used with Mercurial. Expects `url`, `rev`, and `sha256`.
A number of fetcher functions wrap part of `fetchurl` and `fetchzip`. They are mainly convenience functions intended for commonly used destinations of source code in Nixpkgs. These wrapper fetchers are listed below.
## `fetchFromGitHub`
`fetchFromGitHub` expects four arguments. `owner` is a string corresponding to the GitHub user or organization that controls this repository. `repo` corresponds to the name of the software repository. These are located at the top of every GitHub HTML page as `owner`/`repo`. `rev` corresponds to the Git commit hash or tag (e.g `v1.0`) that will be downloaded from Git. Finally, `sha256` corresponds to the hash of the extracted directory. Again, other hash algorithms are also available but `sha256` is currently preferred.
## `fetchFromGitLab`
This is used with GitLab repositories. The arguments expected are very similar to fetchFromGitHub above.
## `fetchFromGitiles`
This is used with Gitiles repositories. The arguments expected are similar to fetchgit.
## `fetchFromBitbucket`
This is used with BitBucket repositories. The arguments expected are very similar to fetchFromGitHub above.
## `fetchFromSavannah`
This is used with Savannah repositories. The arguments expected are very similar to fetchFromGitHub above.
## `fetchFromRepoOrCz`
This is used with repo.or.cz repositories. The arguments expected are very similar to fetchFromGitHub above.

View file

@ -1,150 +0,0 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="chap-pkgs-fetchers">
<title>Fetchers</title>
<para>
When using Nix, you will frequently need to download source code and other files from the internet. Nixpkgs comes with a few helper functions that allow you to fetch fixed-output derivations in a structured way.
</para>
<para>
The two fetcher primitives are <function>fetchurl</function> and <function>fetchzip</function>. Both of these have two required arguments, a URL and a hash. The hash is typically <literal>sha256</literal>, although many more hash algorithms are supported. Nixpkgs contributors are currently recommended to use <literal>sha256</literal>. This hash will be used by Nix to identify your source. A typical usage of fetchurl is provided below.
</para>
<programlisting><![CDATA[
{ stdenv, fetchurl }:
stdenv.mkDerivation {
name = "hello";
src = fetchurl {
url = "http://www.example.org/hello.tar.gz";
sha256 = "1111111111111111111111111111111111111111111111111111";
};
}
]]></programlisting>
<para>
The main difference between <function>fetchurl</function> and <function>fetchzip</function> is in how they store the contents. <function>fetchurl</function> will store the unaltered contents of the URL within the Nix store. <function>fetchzip</function> on the other hand will decompress the archive for you, making files and directories directly accessible in the future. <function>fetchzip</function> can only be used with archives. Despite the name, <function>fetchzip</function> is not limited to .zip files and can also be used with any tarball.
</para>
<para>
<function>fetchpatch</function> works very similarly to <function>fetchurl</function> with the same arguments expected. It expects patch files as a source and and performs normalization on them before computing the checksum. For example it will remove comments or other unstable parts that are sometimes added by version control systems and can change over time.
</para>
<para>
Other fetcher functions allow you to add source code directly from a VCS such as subversion or git. These are mostly straightforward names based on the name of the command used with the VCS system. Because they give you a working repository, they act most like <function>fetchzip</function>.
</para>
<variablelist>
<varlistentry>
<term>
<literal>fetchsvn</literal>
</term>
<listitem>
<para>
Used with Subversion. Expects <literal>url</literal> to a Subversion directory, <literal>rev</literal>, and <literal>sha256</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>fetchgit</literal>
</term>
<listitem>
<para>
Used with Git. Expects <literal>url</literal> to a Git repo, <literal>rev</literal>, and <literal>sha256</literal>. <literal>rev</literal> in this case can be full the git commit id (SHA1 hash) or a tag name like <literal>refs/tags/v1.0</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>fetchfossil</literal>
</term>
<listitem>
<para>
Used with Fossil. Expects <literal>url</literal> to a Fossil archive, <literal>rev</literal>, and <literal>sha256</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>fetchcvs</literal>
</term>
<listitem>
<para>
Used with CVS. Expects <literal>cvsRoot</literal>, <literal>tag</literal>, and <literal>sha256</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>fetchhg</literal>
</term>
<listitem>
<para>
Used with Mercurial. Expects <literal>url</literal>, <literal>rev</literal>, and <literal>sha256</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
A number of fetcher functions wrap part of <function>fetchurl</function> and <function>fetchzip</function>. They are mainly convenience functions intended for commonly used destinations of source code in Nixpkgs. These wrapper fetchers are listed below.
</para>
<variablelist>
<varlistentry>
<term>
<literal>fetchFromGitHub</literal>
</term>
<listitem>
<para>
<function>fetchFromGitHub</function> expects four arguments. <literal>owner</literal> is a string corresponding to the GitHub user or organization that controls this repository. <literal>repo</literal> corresponds to the name of the software repository. These are located at the top of every GitHub HTML page as <literal>owner</literal>/<literal>repo</literal>. <literal>rev</literal> corresponds to the Git commit hash or tag (e.g <literal>v1.0</literal>) that will be downloaded from Git. Finally, <literal>sha256</literal> corresponds to the hash of the extracted directory. Again, other hash algorithms are also available but <literal>sha256</literal> is currently preferred.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>fetchFromGitLab</literal>
</term>
<listitem>
<para>
This is used with GitLab repositories. The arguments expected are very similar to fetchFromGitHub above.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>fetchFromGitiles</literal>
</term>
<listitem>
<para>
This is used with Gitiles repositories. The arguments expected
are similar to fetchgit.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>fetchFromBitbucket</literal>
</term>
<listitem>
<para>
This is used with BitBucket repositories. The arguments expected are very similar to fetchFromGitHub above.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>fetchFromSavannah</literal>
</term>
<listitem>
<para>
This is used with Savannah repositories. The arguments expected are very similar to fetchFromGitHub above.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>fetchFromRepoOrCz</literal>
</term>
<listitem>
<para>
This is used with repo.or.cz repositories. The arguments expected are very similar to fetchFromGitHub above.
</para>
</listitem>
</varlistentry>
</variablelist>
</chapter>

View file

@ -9,7 +9,7 @@ The `wrapFirefox` function allows to pass policies, preferences and extension th
myFirefox = wrapFirefox firefox-unwrapped {
nixExtensions = [
(fetchFirefoxAddon {
name = "ublock";
name = "ublock"; # Has to be unique!
url = "https://addons.mozilla.org/firefox/downloads/file/3679754/ublock_origin-1.31.0-an+fx.xpi";
sha256 = "1h768ljlh3pi23l27qp961v1hd0nbj2vasgy11bmcrlqp40zgvnr";
})
@ -42,7 +42,7 @@ The `wrapFirefox` function allows to pass policies, preferences and extension th
If `nixExtensions != null` then all manually installed addons will be uninstalled from your browser profile.
To view available enterprise policies visit [enterprise policies](https://github.com/mozilla/policy-templates#enterprisepoliciesenabled)
or type into the Firefox url bar: `about:policies#documentation`.
Nix installed addons do not have a valid signature, which is why signature verification is disabled. This does not compromise security because downloaded addons are checksumed and manual addons can't be installed.
Nix installed addons do not have a valid signature, which is why signature verification is disabled. This does not compromise security because downloaded addons are checksumed and manual addons can't be installed. Also make sure that the `name` field of fetchFirefoxAddon is unique. If you remove an addon from the nixExtensions array, rebuild and start Firefox the removed addon will be completly removed with all of its settings.
## Troubleshooting {#sec-firefox-troubleshooting}
If addons do not appear installed although they have been defined in your nix configuration file reset the local addon state of your Firefox profile by clicking `help -> restart with addons disabled -> restart -> refresh firefox`. This can happen if you switch from manual addon mode to nix addon mode and then back to manual mode and then again to nix addon mode.

View file

@ -14,11 +14,11 @@
<xi:include href="ibus.xml" />
<xi:include href="kakoune.section.xml" />
<xi:include href="linux.section.xml" />
<xi:include href="locales.xml" />
<xi:include href="locales.section.xml" />
<xi:include href="nginx.section.xml" />
<xi:include href="opengl.section.xml" />
<xi:include href="shell-helpers.section.xml" />
<xi:include href="steam.xml" />
<xi:include href="steam.section.xml" />
<xi:include href="cataclysm-dda.section.xml" />
<xi:include href="urxvt.section.xml" />
<xi:include href="weechat.section.xml" />

View file

@ -0,0 +1,5 @@
# Locales {#locales}
To allow simultaneous use of packages linked against different versions of `glibc` with different locale archive formats Nixpkgs patches `glibc` to rely on `LOCALE_ARCHIVE` environment variable.
On non-NixOS distributions this variable is obviously not set. This can cause regressions in language support or even crashes in some Nixpkgs-provided programs. The simplest way to mitigate this problem is exporting the `LOCALE_ARCHIVE` variable pointing to `${glibcLocales}/lib/locale/locale-archive`. The drawback (and the reason this is not the default) is the relatively large (a hundred MiB) size of the full set of locales. It is possible to build a custom set of locales by overriding parameters `allLocales` and `locales` of the package.

View file

@ -1,13 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="locales">
<title>Locales</title>
<para>
To allow simultaneous use of packages linked against different versions of <literal>glibc</literal> with different locale archive formats Nixpkgs patches <literal>glibc</literal> to rely on <literal>LOCALE_ARCHIVE</literal> environment variable.
</para>
<para>
On non-NixOS distributions this variable is obviously not set. This can cause regressions in language support or even crashes in some Nixpkgs-provided programs. The simplest way to mitigate this problem is exporting the <literal>LOCALE_ARCHIVE</literal> variable pointing to <literal>${glibcLocales}/lib/locale/locale-archive</literal>. The drawback (and the reason this is not the default) is the relatively large (a hundred MiB) size of the full set of locales. It is possible to build a custom set of locales by overriding parameters <literal>allLocales</literal> and <literal>locales</literal> of the package.
</para>
</section>

View file

@ -0,0 +1,69 @@
# Steam {#sec-steam}
## Steam in Nix {#sec-steam-nix}
Steam is distributed as a `.deb` file, for now only as an i686 package (the amd64 package only has documentation). When unpacked, it has a script called `steam` that in Ubuntu (their target distro) would go to `/usr/bin`. When run for the first time, this script copies some files to the user's home, which include another script that is the ultimate responsible for launching the steam binary, which is also in \$HOME.
Nix problems and constraints:
- We don't have `/bin/bash` and many scripts point there. Similarly for `/usr/bin/python`.
- We don't have the dynamic loader in `/lib`.
- The `steam.sh` script in \$HOME can not be patched, as it is checked and rewritten by steam.
- The steam binary cannot be patched, it's also checked.
The current approach to deploy Steam in NixOS is composing a FHS-compatible chroot environment, as documented [here](http://sandervanderburg.blogspot.nl/2013/09/composing-fhs-compatible-chroot.html). This allows us to have binaries in the expected paths without disrupting the system, and to avoid patching them to work in a non FHS environment.
## How to play {#sec-steam-play}
Use `programs.steam.enable = true;` if you want to add steam to systemPackages and also enable a few workarrounds aswell as Steam controller support or other Steam supported controllers such as the DualShock 4 or Nintendo Switch Pr.
## Troubleshooting {#sec-steam-troub}
- **Steam fails to start. What do I do?**
Try to run
```ShellSession
strace steam
```
to see what is causing steam to fail.
- **Using the FOSS Radeon or nouveau (nvidia) drivers**
- The `newStdcpp` parameter was removed since NixOS 17.09 and should not be needed anymore.
- Steam ships statically linked with a version of libcrypto that conflics with the one dynamically loaded by radeonsi_dri.so. If you get the error
```
steam.sh: line 713: 7842 Segmentation fault (core dumped)
```
have a look at [this pull request](https://github.com/NixOS/nixpkgs/pull/20269).
- **Java**
1. There is no java in steam chrootenv by default. If you get a message like
```
/home/foo/.local/share/Steam/SteamApps/common/towns/towns.sh: line 1: java: command not found
```
You need to add
```nix
steam.override { withJava = true; };
```
## steam-run {#sec-steam-run}
The FHS-compatible chroot used for steam can also be used to run other linux games that expect a FHS environment. To do it, add
```nix
pkgs.steam.override ({
nativeOnly = true;
newStdcpp = true;
}).run
```
to your configuration, rebuild, and run the game with
```
steam-run ./foo
```

View file

@ -1,125 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="sec-steam">
<title>Steam</title>
<section xml:id="sec-steam-nix">
<title>Steam in Nix</title>
<para>
Steam is distributed as a <filename>.deb</filename> file, for now only as an i686 package (the amd64 package only has documentation). When unpacked, it has a script called <filename>steam</filename> that in Ubuntu (their target distro) would go to <filename>/usr/bin </filename>. When run for the first time, this script copies some files to the user's home, which include another script that is the ultimate responsible for launching the steam binary, which is also in $HOME.
</para>
<para>
Nix problems and constraints:
<itemizedlist>
<listitem>
<para>
We don't have <filename>/bin/bash</filename> and many scripts point there. Similarly for <filename>/usr/bin/python</filename> .
</para>
</listitem>
<listitem>
<para>
We don't have the dynamic loader in <filename>/lib </filename>.
</para>
</listitem>
<listitem>
<para>
The <filename>steam.sh</filename> script in $HOME can not be patched, as it is checked and rewritten by steam.
</para>
</listitem>
<listitem>
<para>
The steam binary cannot be patched, it's also checked.
</para>
</listitem>
</itemizedlist>
</para>
<para>
The current approach to deploy Steam in NixOS is composing a FHS-compatible chroot environment, as documented <link xlink:href="http://sandervanderburg.blogspot.nl/2013/09/composing-fhs-compatible-chroot.html">here</link>. This allows us to have binaries in the expected paths without disrupting the system, and to avoid patching them to work in a non FHS environment.
</para>
</section>
<section xml:id="sec-steam-play">
<title>How to play</title>
<para>
Use <programlisting>programs.steam.enable = true;</programlisting> if you want to add steam to systemPackages and also enable a few workarrounds aswell as Steam controller support or other Steam supported controllers such as the DualShock 4 or Nintendo Switch Pr.
</para>
</section>
<section xml:id="sec-steam-troub">
<title>Troubleshooting</title>
<para>
<variablelist>
<varlistentry>
<term>
Steam fails to start. What do I do?
</term>
<listitem>
<para>
Try to run
<programlisting>strace steam</programlisting>
to see what is causing steam to fail.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
Using the FOSS Radeon or nouveau (nvidia) drivers
</term>
<listitem>
<itemizedlist>
<listitem>
<para>
The <literal>newStdcpp</literal> parameter was removed since NixOS 17.09 and should not be needed anymore.
</para>
</listitem>
<listitem>
<para>
Steam ships statically linked with a version of libcrypto that conflics with the one dynamically loaded by radeonsi_dri.so. If you get the error
<programlisting>steam.sh: line 713: 7842 Segmentation fault (core dumped)</programlisting>
have a look at <link xlink:href="https://github.com/NixOS/nixpkgs/pull/20269">this pull request</link>.
</para>
</listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term>
Java
</term>
<listitem>
<orderedlist>
<listitem>
<para>
There is no java in steam chrootenv by default. If you get a message like
<programlisting>/home/foo/.local/share/Steam/SteamApps/common/towns/towns.sh: line 1: java: command not found</programlisting>
You need to add
<programlisting> steam.override { withJava = true; };</programlisting>
to your configuration.
</para>
</listitem>
</orderedlist>
</listitem>
</varlistentry>
</variablelist>
</para>
</section>
<section xml:id="sec-steam-run">
<title>steam-run</title>
<para>
The FHS-compatible chroot used for steam can also be used to run other linux games that expect a FHS environment. To do it, add
<programlisting>pkgs.(steam.override {
nativeOnly = true;
newStdcpp = true;
}).run</programlisting>
to your configuration, rebuild, and run the game with
<programlisting>steam-run ./foo</programlisting>
</para>
</section>
</section>

View file

@ -5,6 +5,6 @@
<para>
This chapter describes several special builders.
</para>
<xi:include href="special/fhs-environments.xml" />
<xi:include href="special/mkshell.xml" />
<xi:include href="special/fhs-environments.section.xml" />
<xi:include href="special/mkshell.section.xml" />
</chapter>

View file

@ -0,0 +1,45 @@
# buildFHSUserEnv {#sec-fhs-environments}
`buildFHSUserEnv` provides a way to build and run FHS-compatible lightweight sandboxes. It creates an isolated root with bound `/nix/store`, so its footprint in terms of disk space needed is quite small. This allows one to run software which is hard or unfeasible to patch for NixOS -- 3rd-party source trees with FHS assumptions, games distributed as tarballs, software with integrity checking and/or external self-updated binaries. It uses Linux namespaces feature to create temporary lightweight environments which are destroyed after all child processes exit, without root user rights requirement. Accepted arguments are:
- `name`
Environment name.
- `targetPkgs`
Packages to be installed for the main host's architecture (i.e. x86_64 on x86_64 installations). Along with libraries binaries are also installed.
- `multiPkgs`
Packages to be installed for all architectures supported by a host (i.e. i686 and x86_64 on x86_64 installations). Only libraries are installed by default.
- `extraBuildCommands`
Additional commands to be executed for finalizing the directory structure.
- `extraBuildCommandsMulti`
Like `extraBuildCommands`, but executed only on multilib architectures.
- `extraOutputsToInstall`
Additional derivation outputs to be linked for both target and multi-architecture packages.
- `extraInstallCommands`
Additional commands to be executed for finalizing the derivation with runner script.
- `runScript`
A command that would be executed inside the sandbox and passed all the command line arguments. It defaults to `bash`.
One can create a simple environment using a `shell.nix` like that:
```nix
{ pkgs ? import <nixpkgs> {} }:
(pkgs.buildFHSUserEnv {
name = "simple-x11-env";
targetPkgs = pkgs: (with pkgs;
[ udev
alsaLib
]) ++ (with pkgs.xorg;
[ libX11
libXcursor
libXrandr
]);
multiPkgs = pkgs: (with pkgs;
[ udev
alsaLib
]);
runScript = "bash";
}).env
```
Running `nix-shell` would then drop you into a shell with these libraries and binaries available. You can use this to run closed-source applications which expect FHS structure without hassles: simply change `runScript` to the application path, e.g. `./bin/start.sh` -- relative paths are supported.

View file

@ -1,122 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="sec-fhs-environments">
<title>buildFHSUserEnv</title>
<para>
<function>buildFHSUserEnv</function> provides a way to build and run FHS-compatible lightweight sandboxes. It creates an isolated root with bound <filename>/nix/store</filename>, so its footprint in terms of disk space needed is quite small. This allows one to run software which is hard or unfeasible to patch for NixOS -- 3rd-party source trees with FHS assumptions, games distributed as tarballs, software with integrity checking and/or external self-updated binaries. It uses Linux namespaces feature to create temporary lightweight environments which are destroyed after all child processes exit, without root user rights requirement. Accepted arguments are:
</para>
<variablelist>
<varlistentry>
<term>
<literal>name</literal>
</term>
<listitem>
<para>
Environment name.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>targetPkgs</literal>
</term>
<listitem>
<para>
Packages to be installed for the main host's architecture (i.e. x86_64 on x86_64 installations). Along with libraries binaries are also installed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>multiPkgs</literal>
</term>
<listitem>
<para>
Packages to be installed for all architectures supported by a host (i.e. i686 and x86_64 on x86_64 installations). Only libraries are installed by default.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>extraBuildCommands</literal>
</term>
<listitem>
<para>
Additional commands to be executed for finalizing the directory structure.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>extraBuildCommandsMulti</literal>
</term>
<listitem>
<para>
Like <literal>extraBuildCommands</literal>, but executed only on multilib architectures.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>extraOutputsToInstall</literal>
</term>
<listitem>
<para>
Additional derivation outputs to be linked for both target and multi-architecture packages.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>extraInstallCommands</literal>
</term>
<listitem>
<para>
Additional commands to be executed for finalizing the derivation with runner script.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>runScript</literal>
</term>
<listitem>
<para>
A command that would be executed inside the sandbox and passed all the command line arguments. It defaults to <literal>bash</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
One can create a simple environment using a <literal>shell.nix</literal> like that:
</para>
<programlisting><![CDATA[
{ pkgs ? import <nixpkgs> {} }:
(pkgs.buildFHSUserEnv {
name = "simple-x11-env";
targetPkgs = pkgs: (with pkgs;
[ udev
alsaLib
]) ++ (with pkgs.xorg;
[ libX11
libXcursor
libXrandr
]);
multiPkgs = pkgs: (with pkgs;
[ udev
alsaLib
]);
runScript = "bash";
}).env
]]></programlisting>
<para>
Running <literal>nix-shell</literal> would then drop you into a shell with these libraries and binaries available. You can use this to run closed-source applications which expect FHS structure without hassles: simply change <literal>runScript</literal> to the application path, e.g. <filename>./bin/start.sh</filename> -- relative paths are supported.
</para>
</section>

View file

@ -0,0 +1,15 @@
# pkgs.mkShell {#sec-pkgs-mkShell}
`pkgs.mkShell` is a special kind of derivation that is only useful when using it combined with `nix-shell`. It will in fact fail to instantiate when invoked with `nix-build`.
## Usage {#sec-pkgs-mkShell-usage}
```nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
# this will make all the build inputs from hello and gnutar
# available to the shell environment
inputsFrom = with pkgs; [ hello gnutar ];
buildInputs = [ pkgs.gnumake ];
}
```

View file

@ -1,24 +0,0 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="sec-pkgs-mkShell">
<title>pkgs.mkShell</title>
<para>
<function>pkgs.mkShell</function> is a special kind of derivation that is only useful when using it combined with <command>nix-shell</command>. It will in fact fail to instantiate when invoked with <command>nix-build</command>.
</para>
<section xml:id="sec-pkgs-mkShell-usage">
<title>Usage</title>
<programlisting><![CDATA[
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
# this will make all the build inputs from hello and gnutar
# available to the shell environment
inputsFrom = with pkgs; [ hello gnutar ];
buildInputs = [ pkgs.gnumake ];
}
]]></programlisting>
</section>
</section>

View file

@ -0,0 +1,52 @@
# Trivial builders {#chap-trivial-builders}
Nixpkgs provides a couple of functions that help with building derivations. The most important one, `stdenv.mkDerivation`, has already been documented above. The following functions wrap `stdenv.mkDerivation`, making it easier to use in certain cases.
## `runCommand` {#trivial-builder-runCommand}
This takes three arguments, `name`, `env`, and `buildCommand`. `name` is just the name that Nix will append to the store path in the same way that `stdenv.mkDerivation` uses its `name` attribute. `env` is an attribute set specifying environment variables that will be set for this derivation. These attributes are then passed to the wrapped `stdenv.mkDerivation`. `buildCommand` specifies the commands that will be run to create this derivation. Note that you will need to create `$out` for Nix to register the command as successful.
An example of using `runCommand` is provided below.
```nix
(import <nixpkgs> {}).runCommand "my-example" {} ''
echo My example command is running
mkdir $out
echo I can write data to the Nix store > $out/message
echo I can also run basic commands like:
echo ls
ls
echo whoami
whoami
echo date
date
''
```
## `runCommandCC` {#trivial-builder-runCommandCC}
This works just like `runCommand`. The only difference is that it also provides a C compiler in `buildCommand`'s environment. To minimize your dependencies, you should only use this if you are sure you will need a C compiler as part of running your command.
## `runCommandLocal` {#trivial-builder-runCommandLocal}
Variant of `runCommand` that forces the derivation to be built locally, it is not substituted. This is intended for very cheap commands (<1s execution time). It saves on the network roundrip and can speed up a build.
::: {.note}
This sets [`allowSubstitutes` to `false`](https://nixos.org/nix/manual/#adv-attr-allowSubstitutes), so only use `runCommandLocal` if you are certain the user will always have a builder for the `system` of the derivation. This should be true for most trivial use cases (e.g. just copying some files to a different location or adding symlinks), because there the `system` is usually the same as `builtins.currentSystem`.
:::
## `writeTextFile`, `writeText`, `writeTextDir`, `writeScript`, `writeScriptBin` {#trivial-builder-writeText}
These functions write `text` to the Nix store. This is useful for creating scripts from Nix expressions. `writeTextFile` takes an attribute set and expects two arguments, `name` and `text`. `name` corresponds to the name used in the Nix store path. `text` will be the contents of the file. You can also set `executable` to true to make this file have the executable bit set.
Many more commands wrap `writeTextFile` including `writeText`, `writeTextDir`, `writeScript`, and `writeScriptBin`. These are convenience functions over `writeTextFile`.
## `symlinkJoin` {#trivial-builder-symlinkJoin}
This can be used to put many derivations into the same directory structure. It works by creating a new derivation and adding symlinks to each of the paths listed. It expects two arguments, `name`, and `paths`. `name` is the name used in the Nix store path for the created derivation. `paths` is a list of paths that will be symlinked. These paths can be to Nix store derivations or any other subdirectory contained within.

View file

@ -1,90 +0,0 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude"
xml:id="chap-trivial-builders">
<title>Trivial builders</title>
<para>
Nixpkgs provides a couple of functions that help with building derivations. The most important one, <function>stdenv.mkDerivation</function>, has already been documented above. The following functions wrap <function>stdenv.mkDerivation</function>, making it easier to use in certain cases.
</para>
<variablelist>
<varlistentry xml:id="trivial-builder-runCommand">
<term>
<literal>runCommand</literal>
</term>
<listitem>
<para>
This takes three arguments, <literal>name</literal>, <literal>env</literal>, and <literal>buildCommand</literal>. <literal>name</literal> is just the name that Nix will append to the store path in the same way that <literal>stdenv.mkDerivation</literal> uses its <literal>name</literal> attribute. <literal>env</literal> is an attribute set specifying environment variables that will be set for this derivation. These attributes are then passed to the wrapped <literal>stdenv.mkDerivation</literal>. <literal>buildCommand</literal> specifies the commands that will be run to create this derivation. Note that you will need to create <literal>$out</literal> for Nix to register the command as successful.
</para>
<para>
An example of using <literal>runCommand</literal> is provided below.
</para>
<programlisting>
(import &lt;nixpkgs&gt; {}).runCommand "my-example" {} ''
echo My example command is running
mkdir $out
echo I can write data to the Nix store > $out/message
echo I can also run basic commands like:
echo ls
ls
echo whoami
whoami
echo date
date
''
</programlisting>
</listitem>
</varlistentry>
<varlistentry xml:id="trivial-builder-runCommandCC">
<term>
<literal>runCommandCC</literal>
</term>
<listitem>
<para>
This works just like <literal>runCommand</literal>. The only difference is that it also provides a C compiler in <literal>buildCommand</literal>s environment. To minimize your dependencies, you should only use this if you are sure you will need a C compiler as part of running your command.
</para>
</listitem>
</varlistentry>
<varlistentry xml:id="trivial-builder-runCommandLocal">
<term>
<literal>runCommandLocal</literal>
</term>
<listitem>
<para>
Variant of <literal>runCommand</literal> that forces the derivation to be built locally, it is not substituted. This is intended for very cheap commands (&lt;1s execution time). It saves on the network roundrip and can speed up a build.
</para>
<note><para>
This sets <link xlink:href="https://nixos.org/nix/manual/#adv-attr-allowSubstitutes"><literal>allowSubstitutes</literal> to <literal>false</literal></link>, so only use <literal>runCommandLocal</literal> if you are certain the user will always have a builder for the <literal>system</literal> of the derivation. This should be true for most trivial use cases (e.g. just copying some files to a different location or adding symlinks), because there the <literal>system</literal> is usually the same as <literal>builtins.currentSystem</literal>.
</para></note>
</listitem>
</varlistentry>
<varlistentry xml:id="trivial-builder-writeText">
<term>
<literal>writeTextFile</literal>, <literal>writeText</literal>, <literal>writeTextDir</literal>, <literal>writeScript</literal>, <literal>writeScriptBin</literal>
</term>
<listitem>
<para>
These functions write <literal>text</literal> to the Nix store. This is useful for creating scripts from Nix expressions. <literal>writeTextFile</literal> takes an attribute set and expects two arguments, <literal>name</literal> and <literal>text</literal>. <literal>name</literal> corresponds to the name used in the Nix store path. <literal>text</literal> will be the contents of the file. You can also set <literal>executable</literal> to true to make this file have the executable bit set.
</para>
<para>
Many more commands wrap <literal>writeTextFile</literal> including <literal>writeText</literal>, <literal>writeTextDir</literal>, <literal>writeScript</literal>, and <literal>writeScriptBin</literal>. These are convenience functions over <literal>writeTextFile</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry xml:id="trivial-builder-symlinkJoin">
<term>
<literal>symlinkJoin</literal>
</term>
<listitem>
<para>
This can be used to put many derivations into the same directory structure. It works by creating a new derivation and adding symlinks to each of the paths listed. It expects two arguments, <literal>name</literal>, and <literal>paths</literal>. <literal>name</literal> is the name used in the Nix store path for the created derivation. <literal>paths</literal> is a list of paths that will be symlinked. These paths can be to Nix store derivations or any other subdirectory contained within.
</para>
</listitem>
</varlistentry>
</variablelist>
</chapter>

View file

@ -135,3 +135,21 @@ Example of building `composer` with additional extensions:
enabled ++ (with all; [ imagick redis ]))
).packages.composer
```
### Overriding PHP packages {#ssec-php-user-guide-overriding-packages}
`php-packages.nix` form a scope, allowing us to override the packages defined within. For example, to apply a patch to a `mysqlnd` extension, you can simply pass an overlay-style function to `php`s `packageOverrides` argument:
```nix
php.override {
packageOverrides = final: prev: {
extensions = prev.extensions // {
mysqlnd = prev.extensions.mysqlnd.overrideAttrs (attrs: {
patches = attrs.patches or [] ++ [
];
});
};
};
}
```

View file

@ -18,13 +18,13 @@
<xi:include href="stdenv/stdenv.xml" />
<xi:include href="stdenv/meta.xml" />
<xi:include href="stdenv/multiple-output.xml" />
<xi:include href="stdenv/cross-compilation.xml" />
<xi:include href="stdenv/cross-compilation.chapter.xml" />
<xi:include href="stdenv/platform-notes.xml" />
</part>
<part>
<title>Builders</title>
<xi:include href="builders/fetchers.xml" />
<xi:include href="builders/trivial-builders.xml" />
<xi:include href="builders/fetchers.chapter.xml" />
<xi:include href="builders/trivial-builders.chapter.xml" />
<xi:include href="builders/special.xml" />
<xi:include href="builders/images.xml" />
<xi:include href="languages-frameworks/index.xml" />

View file

@ -0,0 +1,197 @@
# Cross-compilation {#chap-cross}
## Introduction {#sec-cross-intro}
"Cross-compilation" means compiling a program on one machine for another type of machine. For example, a typical use of cross-compilation is to compile programs for embedded devices. These devices often don't have the computing power and memory to compile their own programs. One might think that cross-compilation is a fairly niche concern. However, there are significant advantages to rigorously distinguishing between build-time and run-time environments! Significant, because the benefits apply even when one is developing and deploying on the same machine. Nixpkgs is increasingly adopting the opinion that packages should be written with cross-compilation in mind, and Nixpkgs should evaluate in a similar way (by minimizing cross-compilation-specific special cases) whether or not one is cross-compiling.
This chapter will be organized in three parts. First, it will describe the basics of how to package software in a way that supports cross-compilation. Second, it will describe how to use Nixpkgs when cross-compiling. Third, it will describe the internal infrastructure supporting cross-compilation.
## Packaging in a cross-friendly manner {#sec-cross-packaging}
### Platform parameters {#ssec-cross-platform-parameters}
Nixpkgs follows the [conventions of GNU autoconf](https://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html). We distinguish between 3 types of platforms when building a derivation: _build_, _host_, and _target_. In summary, _build_ is the platform on which a package is being built, _host_ is the platform on which it will run. The third attribute, _target_, is relevant only for certain specific compilers and build tools.
In Nixpkgs, these three platforms are defined as attribute sets under the names `buildPlatform`, `hostPlatform`, and `targetPlatform`. They are always defined as attributes in the standard environment. That means one can access them like:
```nix
{ stdenv, fooDep, barDep, .. }: ...stdenv.buildPlatform...
```
`buildPlatform`
: The "build platform" is the platform on which a package is built. Once someone has a built package, or pre-built binary package, the build platform should not matter and can be ignored.
`hostPlatform`
: The "host platform" is the platform on which a package will be run. This is the simplest platform to understand, but also the one with the worst name.
`targetPlatform`
: The "target platform" attribute is, unlike the other two attributes, not actually fundamental to the process of building software. Instead, it is only relevant for compatibility with building certain specific compilers and build tools. It can be safely ignored for all other packages.
: The build process of certain compilers is written in such a way that the compiler resulting from a single build can itself only produce binaries for a single platform. The task of specifying this single "target platform" is thus pushed to build time of the compiler. The root cause of this is that the compiler (which will be run on the host) and the standard library/runtime (which will be run on the target) are built by a single build process.
: There is no fundamental need to think about a single target ahead of time like this. If the tool supports modular or pluggable backends, both the need to specify the target at build time and the constraint of having only a single target disappear. An example of such a tool is LLVM.
: Although the existence of a "target platform" is arguably a historical mistake, it is a common one: examples of tools that suffer from it are GCC, Binutils, GHC and Autoconf. Nixpkgs tries to avoid sharing in the mistake where possible. Still, because the concept of a target platform is so ingrained, it is best to support it as is.
The exact schema these fields follow is a bit ill-defined due to a long and convoluted evolution, but this is slowly being cleaned up. You can see examples of ones used in practice in `lib.systems.examples`; note how they are not all very consistent. For now, here are few fields can count on them containing:
`system`
: This is a two-component shorthand for the platform. Examples of this would be "x86_64-darwin" and "i686-linux"; see `lib.systems.doubles` for more. The first component corresponds to the CPU architecture of the platform and the second to the operating system of the platform (`[cpu]-[os]`). This format has built-in support in Nix, such as the `builtins.currentSystem` impure string.
`config`
: This is a 3- or 4- component shorthand for the platform. Examples of this would be `x86_64-unknown-linux-gnu` and `aarch64-apple-darwin14`. This is a standard format called the "LLVM target triple", as they are pioneered by LLVM. In the 4-part form, this corresponds to `[cpu]-[vendor]-[os]-[abi]`. This format is strictly more informative than the "Nix host double", as the previous format could analogously be termed. This needs a better name than `config`!
`parsed`
: This is a Nix representation of a parsed LLVM target triple with white-listed components. This can be specified directly, or actually parsed from the `config`. See `lib.systems.parse` for the exact representation.
`libc`
: This is a string identifying the standard C library used. Valid identifiers include "glibc" for GNU libc, "libSystem" for Darwin's Libsystem, and "uclibc" for µClibc. It should probably be refactored to use the module system, like `parse`.
`is*`
: These predicates are defined in `lib.systems.inspect`, and slapped onto every platform. They are superior to the ones in `stdenv` as they force the user to be explicit about which platform they are inspecting. Please use these instead of those.
`platform`
: This is, quite frankly, a dumping ground of ad-hoc settings (it's an attribute set). See `lib.systems.platforms` for examples—there's hopefully one in there that will work verbatim for each platform that is working. Please help us triage these flags and give them better homes!
### Theory of dependency categorization {#ssec-cross-dependency-categorization}
::: note
This is a rather philosophical description that isn't very Nixpkgs-specific. For an overview of all the relevant attributes given to `mkDerivation`, see <xref linkend="ssec-stdenv-dependencies"/>. For a description of how everything is implemented, see <xref linkend="ssec-cross-dependency-implementation"/>.
:::
In this section we explore the relationship between both runtime and build-time dependencies and the 3 Autoconf platforms.
A run time dependency between two packages requires that their host platforms match. This is directly implied by the meaning of "host platform" and "runtime dependency": The package dependency exists while both packages are running on a single host platform.
A build time dependency, however, has a shift in platforms between the depending package and the depended-on package. "build time dependency" means that to build the depending package we need to be able to run the depended-on's package. The depending package's build platform is therefore equal to the depended-on package's host platform.
If both the dependency and depending packages aren't compilers or other machine-code-producing tools, we're done. And indeed `buildInputs` and `nativeBuildInputs` have covered these simpler cases for many years. But if the dependency does produce machine code, we might need to worry about its target platform too. In principle, that target platform might be any of the depending package's build, host, or target platforms, but we prohibit dependencies from a "later" platform to an earlier platform to limit confusion because we've never seen a legitimate use for them.
Finally, if the depending package is a compiler or other machine-code-producing tool, it might need dependencies that run at "emit time". This is for compilers that (regrettably) insist on being built together with their source languages' standard libraries. Assuming build != host != target, a run-time dependency of the standard library cannot be run at the compiler's build time or run time, but only at the run time of code emitted by the compiler.
Putting this all together, that means we have dependencies in the form "host → target", in at most the following six combinations:
#### Possible dependency types
| Dependency's host platform | Dependency's target platform |
| -- | -- |
| build | build |
| build | host |
| build | target |
| host | host |
| host | target |
| target | target |
Some examples will make this table clearer. Suppose there's some package that is being built with a `(build, host, target)` platform triple of `(foo, bar, baz)`. If it has a build-time library dependency, that would be a "host → build" dependency with a triple of `(foo, foo, *)` (the target platform is irrelevant). If it needs a compiler to be built, that would be a "build → host" dependency with a triple of `(foo, foo, *)` (the target platform is irrelevant). That compiler, would be built with another compiler, also "build → host" dependency, with a triple of `(foo, foo, foo)`.
### Cross packaging cookbook {#ssec-cross-cookbook}
Some frequently encountered problems when packaging for cross-compilation should be answered here. Ideally, the information above is exhaustive, so this section cannot provide any new information, but it is ludicrous and cruel to expect everyone to spend effort working through the interaction of many features just to figure out the same answer to the same common problem. Feel free to add to this list!
#### What if my package's build system needs to build a C program to be run under the build environment? {#cross-qa-build-c-program-in-build-environment}
Add the following to your `mkDerivation` invocation.
```nix
depsBuildBuild = [ buildPackages.stdenv.cc ];
```
#### My package fails to find `ar`. {#cross-qa-fails-to-find-ar}
Many packages assume that an unprefixed `ar` is available, but Nix doesn't provide one. It only provides a prefixed one, just as it only does for all the other binutils programs. It may be necessary to patch the package to fix the build system to use a prefixed `ar`.
#### My package's testsuite needs to run host platform code. {#cross-testsuite-runs-host-code}
Add the following to your `mkDerivation` invocation.
```nix
doCheck = stdenv.hostPlatform == stdenv.buildPlatfrom;
```
## Cross-building packages {#sec-cross-usage}
Nixpkgs can be instantiated with `localSystem` alone, in which case there is no cross-compiling and everything is built by and for that system, or also with `crossSystem`, in which case packages run on the latter, but all building happens on the former. Both parameters take the same schema as the 3 (build, host, and target) platforms defined in the previous section. As mentioned above, `lib.systems.examples` has some platforms which are used as arguments for these parameters in practice. You can use them programmatically, or on the command line:
```ShellSession
$ nix-build '<nixpkgs>' --arg crossSystem '(import <nixpkgs/lib>).systems.examples.fooBarBaz' -A whatever
```
::: note
Eventually we would like to make these platform examples an unnecessary convenience so that
```ShellSession
$ nix-build '<nixpkgs>' --arg crossSystem '{ config = "<arch>-<os>-<vendor>-<abi>"; }' -A whatever
```
works in the vast majority of cases. The problem today is dependencies on other sorts of configuration which aren't given proper defaults. We rely on the examples to crudely to set those configuration parameters in some vaguely sane manner on the users behalf. Issue [\#34274](https://github.com/NixOS/nixpkgs/issues/34274) tracks this inconvenience along with its root cause in crufty configuration options.
:::
While one is free to pass both parameters in full, there's a lot of logic to fill in missing fields. As discussed in the previous section, only one of `system`, `config`, and `parsed` is needed to infer the other two. Additionally, `libc` will be inferred from `parse`. Finally, `localSystem.system` is also _impurely_ inferred based on the platform evaluation occurs. This means it is often not necessary to pass `localSystem` at all, as in the command-line example in the previous paragraph.
::: note
Many sources (manual, wiki, etc) probably mention passing `system`, `platform`, along with the optional `crossSystem` to Nixpkgs: `import <nixpkgs> { system = ..; platform = ..; crossSystem = ..; }`. Passing those two instead of `localSystem` is still supported for compatibility, but is discouraged. Indeed, much of the inference we do for these parameters is motivated by compatibility as much as convenience.
:::
One would think that `localSystem` and `crossSystem` overlap horribly with the three `*Platforms` (`buildPlatform`, `hostPlatform,` and `targetPlatform`; see `stage.nix` or the manual). Actually, those identifiers are purposefully not used here to draw a subtle but important distinction: While the granularity of having 3 platforms is necessary to properly *build* packages, it is overkill for specifying the user's *intent* when making a build plan or package set. A simple "build vs deploy" dichotomy is adequate: the sliding window principle described in the previous section shows how to interpolate between the these two "end points" to get the 3 platform triple for each bootstrapping stage. That means for any package a given package set, even those not bound on the top level but only reachable via dependencies or `buildPackages`, the three platforms will be defined as one of `localSystem` or `crossSystem`, with the former replacing the latter as one traverses build-time dependencies. A last simple difference is that `crossSystem` should be null when one doesn't want to cross-compile, while the `*Platform`s are always non-null. `localSystem` is always non-null.
## Cross-compilation infrastructure {#sec-cross-infra}
### Implementation of dependencies {#ssec-cross-dependency-implementation}
The categories of dependencies developed in <xref linkend="ssec-cross-dependency-categorization"/> are specified as lists of derivations given to `mkDerivation`, as documented in <xref linkend="ssec-stdenv-dependencies"/>. In short, each list of dependencies for "host → target" of "foo → bar" is called `depsFooBar`, with exceptions for backwards compatibility that `depsBuildHost` is instead called `nativeBuildInputs` and `depsHostTarget` is instead called `buildInputs`. Nixpkgs is now structured so that each `depsFooBar` is automatically taken from `pkgsFooBar`. (These `pkgsFooBar`s are quite new, so there is no special case for `nativeBuildInputs` and `buildInputs`.) For example, `pkgsBuildHost.gcc` should be used at build-time, while `pkgsHostTarget.gcc` should be used at run-time.
Now, for most of Nixpkgs's history, there were no `pkgsFooBar` attributes, and most packages have not been refactored to use it explicitly. Prior to those, there were just `buildPackages`, `pkgs`, and `targetPackages`. Those are now redefined as aliases to `pkgsBuildHost`, `pkgsHostTarget`, and `pkgsTargetTarget`. It is acceptable, even recommended, to use them for libraries to show that the host platform is irrelevant.
But before that, there was just `pkgs`, even though both `buildInputs` and `nativeBuildInputs` existed. \[Cross barely worked, and those were implemented with some hacks on `mkDerivation` to override dependencies.\] What this means is the vast majority of packages do not use any explicit package set to populate their dependencies, just using whatever `callPackage` gives them even if they do correctly sort their dependencies into the multiple lists described above. And indeed, asking that users both sort their dependencies, _and_ take them from the right attribute set, is both too onerous and redundant, so the recommended approach (for now) is to continue just categorizing by list and not using an explicit package set.
To make this work, we "splice" together the six `pkgsFooBar` package sets and have `callPackage` actually take its arguments from that. This is currently implemented in `pkgs/top-level/splice.nix`. `mkDerivation` then, for each dependency attribute, pulls the right derivation out from the splice. This splicing can be skipped when not cross-compiling as the package sets are the same, but still is a bit slow for cross-compiling. We'd like to do something better, but haven't come up with anything yet.
### Bootstrapping {#ssec-bootstrapping}
Each of the package sets described above come from a single bootstrapping stage. While `pkgs/top-level/default.nix`, coordinates the composition of stages at a high level, `pkgs/top-level/stage.nix` "ties the knot" (creates the fixed point) of each stage. The package sets are defined per-stage however, so they can be thought of as edges between stages (the nodes) in a graph. Compositions like `pkgsBuildTarget.targetPackages` can be thought of as paths to this graph.
While there are many package sets, and thus many edges, the stages can also be arranged in a linear chain. In other words, many of the edges are redundant as far as connectivity is concerned. This hinges on the type of bootstrapping we do. Currently for cross it is:
1. `(native, native, native)`
2. `(native, native, foreign)`
3. `(native, foreign, foreign)`
In each stage, `pkgsBuildHost` refers to the previous stage, `pkgsBuildBuild` refers to the one before that, and `pkgsHostTarget` refers to the current one, and `pkgsTargetTarget` refers to the next one. When there is no previous or next stage, they instead refer to the current stage. Note how all the invariants regarding the mapping between dependency and depending packages' build host and target platforms are preserved. `pkgsBuildTarget` and `pkgsHostHost` are more complex in that the stage fitting the requirements isn't always a fixed chain of "prevs" and "nexts" away (modulo the "saturating" self-references at the ends). We just special case each instead. All the primary edges are implemented is in `pkgs/stdenv/booter.nix`, and secondarily aliases in `pkgs/top-level/stage.nix`.
::: note
The native stages are bootstrapped in legacy ways that predate the current cross implementation. This is why the bootstrapping stages leading up to the final stages are ignored in the previous paragraph.
:::
If one looks at the 3 platform triples, one can see that they overlap such that one could put them together into a chain like:
```
(native, native, native, foreign, foreign)
```
If one imagines the saturating self references at the end being replaced with infinite stages, and then overlays those platform triples, one ends up with the infinite tuple:
```
(native..., native, native, native, foreign, foreign, foreign...)
```
On can then imagine any sequence of platforms such that there are bootstrap stages with their 3 platforms determined by "sliding a window" that is the 3 tuple through the sequence. This was the original model for bootstrapping. Without a target platform (assume a better world where all compilers are multi-target and all standard libraries are built in their own derivation), this is sufficient. Conversely if one wishes to cross compile "faster", with a "Canadian Cross" bootstrapping stage where `build != host != target`, more bootstrapping stages are needed since no sliding window provides the pesky `pkgsBuildTarget` package set since it skips the Canadian cross stage's "host".
::: note
It is much better to refer to `buildPackages` than `targetPackages`, or more broadly package sets that do not mention "target". There are three reasons for this.
First, it is because bootstrapping stages do not have a unique `targetPackages`. For example a `(x86-linux, x86-linux, arm-linux)` and `(x86-linux, x86-linux, x86-windows)` package set both have a `(x86-linux, x86-linux, x86-linux)` package set. Because there is no canonical `targetPackages` for such a native (`build == host == target`) package set, we set their `targetPackages`
Second, it is because this is a frequent source of hard-to-follow "infinite recursions" / cycles. When only package sets that don't mention target are used, the package set forms a directed acyclic graph. This means that all cycles that exist are confined to one stage. This means they are a lot smaller, and easier to follow in the code or a backtrace. It also means they are present in native and cross builds alike, and so more likely to be caught by CI and other users.
Thirdly, it is because everything target-mentioning only exists to accommodate compilers with lousy build systems that insist on the compiler itself and standard library being built together. Of course that is bad because bigger derivations means longer rebuilds. It is also problematic because it tends to make the standard libraries less like other libraries than they could be, complicating code and build systems alike. Because of the other problems, and because of these innate disadvantages, compilers ought to be packaged another way where possible.
:::
::: note
If one explores Nixpkgs, they will see derivations with names like `gccCross`. Such `*Cross` derivations is a holdover from before we properly distinguished between the host and target platforms—the derivation with "Cross" in the name covered the `build = host != target` case, while the other covered the `host = target`, with build platform the same or not based on whether one was using its `.nativeDrv` or `.crossDrv`. This ugliness will disappear soon.
:::

View file

@ -1,394 +0,0 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="chap-cross">
<title>Cross-compilation</title>
<section xml:id="sec-cross-intro">
<title>Introduction</title>
<para>
"Cross-compilation" means compiling a program on one machine for another type of machine. For example, a typical use of cross-compilation is to compile programs for embedded devices. These devices often don't have the computing power and memory to compile their own programs. One might think that cross-compilation is a fairly niche concern. However, there are significant advantages to rigorously distinguishing between build-time and run-time environments! Significant, because the benefits apply even when one is developing and deploying on the same machine. Nixpkgs is increasingly adopting the opinion that packages should be written with cross-compilation in mind, and nixpkgs should evaluate in a similar way (by minimizing cross-compilation-specific special cases) whether or not one is cross-compiling.
</para>
<para>
This chapter will be organized in three parts. First, it will describe the basics of how to package software in a way that supports cross-compilation. Second, it will describe how to use Nixpkgs when cross-compiling. Third, it will describe the internal infrastructure supporting cross-compilation.
</para>
</section>
<!--============================================================-->
<section xml:id="sec-cross-packaging">
<title>Packaging in a cross-friendly manner</title>
<section xml:id="ssec-cross-platform-parameters">
<title>Platform parameters</title>
<para>
Nixpkgs follows the <link
xlink:href="https://gcc.gnu.org/onlinedocs/gccint/Configure-Terms.html">conventions of GNU autoconf</link>. We distinguish between 3 types of platforms when building a derivation: <wordasword>build</wordasword>, <wordasword>host</wordasword>, and <wordasword>target</wordasword>. In summary, <wordasword>build</wordasword> is the platform on which a package is being built, <wordasword>host</wordasword> is the platform on which it will run. The third attribute, <wordasword>target</wordasword>, is relevant only for certain specific compilers and build tools.
</para>
<para>
In Nixpkgs, these three platforms are defined as attribute sets under the names <literal>buildPlatform</literal>, <literal>hostPlatform</literal>, and <literal>targetPlatform</literal>. They are always defined as attributes in the standard environment. That means one can access them like:
<programlisting>{ stdenv, fooDep, barDep, .. }: ...stdenv.buildPlatform...</programlisting>
.
</para>
<variablelist>
<varlistentry>
<term>
<varname>buildPlatform</varname>
</term>
<listitem>
<para>
The "build platform" is the platform on which a package is built. Once someone has a built package, or pre-built binary package, the build platform should not matter and can be ignored.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>hostPlatform</varname>
</term>
<listitem>
<para>
The "host platform" is the platform on which a package will be run. This is the simplest platform to understand, but also the one with the worst name.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>targetPlatform</varname>
</term>
<listitem>
<para>
The "target platform" attribute is, unlike the other two attributes, not actually fundamental to the process of building software. Instead, it is only relevant for compatibility with building certain specific compilers and build tools. It can be safely ignored for all other packages.
</para>
<para>
The build process of certain compilers is written in such a way that the compiler resulting from a single build can itself only produce binaries for a single platform. The task of specifying this single "target platform" is thus pushed to build time of the compiler. The root cause of this is that the compiler (which will be run on the host) and the standard library/runtime (which will be run on the target) are built by a single build process.
</para>
<para>
There is no fundamental need to think about a single target ahead of time like this. If the tool supports modular or pluggable backends, both the need to specify the target at build time and the constraint of having only a single target disappear. An example of such a tool is LLVM.
</para>
<para>
Although the existence of a "target platfom" is arguably a historical mistake, it is a common one: examples of tools that suffer from it are GCC, Binutils, GHC and Autoconf. Nixpkgs tries to avoid sharing in the mistake where possible. Still, because the concept of a target platform is so ingrained, it is best to support it as is.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
The exact schema these fields follow is a bit ill-defined due to a long and convoluted evolution, but this is slowly being cleaned up. You can see examples of ones used in practice in <literal>lib.systems.examples</literal>; note how they are not all very consistent. For now, here are few fields can count on them containing:
</para>
<variablelist>
<varlistentry>
<term>
<varname>system</varname>
</term>
<listitem>
<para>
This is a two-component shorthand for the platform. Examples of this would be "x86_64-darwin" and "i686-linux"; see <literal>lib.systems.doubles</literal> for more. The first component corresponds to the CPU architecture of the platform and the second to the operating system of the platform (<literal>[cpu]-[os]</literal>). This format has built-in support in Nix, such as the <varname>builtins.currentSystem</varname> impure string.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>config</varname>
</term>
<listitem>
<para>
This is a 3- or 4- component shorthand for the platform. Examples of this would be <literal>x86_64-unknown-linux-gnu</literal> and <literal>aarch64-apple-darwin14</literal>. This is a standard format called the "LLVM target triple", as they are pioneered by LLVM. In the 4-part form, this corresponds to <literal>[cpu]-[vendor]-[os]-[abi]</literal>. This format is strictly more informative than the "Nix host double", as the previous format could analogously be termed. This needs a better name than <varname>config</varname>!
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>parsed</varname>
</term>
<listitem>
<para>
This is a Nix representation of a parsed LLVM target triple with white-listed components. This can be specified directly, or actually parsed from the <varname>config</varname>. See <literal>lib.systems.parse</literal> for the exact representation.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>libc</varname>
</term>
<listitem>
<para>
This is a string identifying the standard C library used. Valid identifiers include "glibc" for GNU libc, "libSystem" for Darwin's Libsystem, and "uclibc" for µClibc. It should probably be refactored to use the module system, like <varname>parse</varname>.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>is*</varname>
</term>
<listitem>
<para>
These predicates are defined in <literal>lib.systems.inspect</literal>, and slapped onto every platform. They are superior to the ones in <varname>stdenv</varname> as they force the user to be explicit about which platform they are inspecting. Please use these instead of those.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<varname>platform</varname>
</term>
<listitem>
<para>
This is, quite frankly, a dumping ground of ad-hoc settings (it's an attribute set). See <literal>lib.systems.platforms</literal> for examples—there's hopefully one in there that will work verbatim for each platform that is working. Please help us triage these flags and give them better homes!
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="ssec-cross-dependency-categorization">
<title>Theory of dependency categorization</title>
<note>
<para>
This is a rather philosophical description that isn't very Nixpkgs-specific. For an overview of all the relevant attributes given to <varname>mkDerivation</varname>, see <xref
linkend="ssec-stdenv-dependencies"/>. For a description of how everything is implemented, see <xref linkend="ssec-cross-dependency-implementation" />.
</para>
</note>
<para>
In this section we explore the relationship between both runtime and build-time dependencies and the 3 Autoconf platforms.
</para>
<para>
A run time dependency between two packages requires that their host platforms match. This is directly implied by the meaning of "host platform" and "runtime dependency": The package dependency exists while both packages are running on a single host platform.
</para>
<para>
A build time dependency, however, has a shift in platforms between the depending package and the depended-on package. "build time dependency" means that to build the depending package we need to be able to run the depended-on's package. The depending package's build platform is therefore equal to the depended-on package's host platform.
</para>
<para>
If both the dependency and depending packages aren't compilers or other machine-code-producing tools, we're done. And indeed <varname>buildInputs</varname> and <varname>nativeBuildInputs</varname> have covered these simpler build-time and run-time (respectively) changes for many years. But if the dependency does produce machine code, we might need to worry about its target platform too. In principle, that target platform might be any of the depending package's build, host, or target platforms, but we prohibit dependencies from a "later" platform to an earlier platform to limit confusion because we've never seen a legitimate use for them.
</para>
<para>
Finally, if the depending package is a compiler or other machine-code-producing tool, it might need dependencies that run at "emit time". This is for compilers that (regrettably) insist on being built together with their source langauges' standard libraries. Assuming build != host != target, a run-time dependency of the standard library cannot be run at the compiler's build time or run time, but only at the run time of code emitted by the compiler.
</para>
<para>
Putting this all together, that means we have dependencies in the form "host → target", in at most the following six combinations:
<table>
<caption>Possible dependency types</caption>
<thead>
<tr>
<th>Dependency's host platform</th>
<th>Dependency's target platform</th>
</tr>
</thead>
<tbody>
<tr>
<td>build</td>
<td>build</td>
</tr>
<tr>
<td>build</td>
<td>host</td>
</tr>
<tr>
<td>build</td>
<td>target</td>
</tr>
<tr>
<td>host</td>
<td>host</td>
</tr>
<tr>
<td>host</td>
<td>target</td>
</tr>
<tr>
<td>target</td>
<td>target</td>
</tr>
</tbody>
</table>
</para>
<para>
Some examples will make this table clearer. Suppose there's some package that is being built with a <literal>(build, host, target)</literal> platform triple of <literal>(foo, bar, baz)</literal>. If it has a build-time library dependency, that would be a "host → build" dependency with a triple of <literal>(foo, foo, *)</literal> (the target platform is irrelevant). If it needs a compiler to be built, that would be a "build → host" dependency with a triple of <literal>(foo, foo, *)</literal> (the target platform is irrelevant). That compiler, would be built with another compiler, also "build → host" dependency, with a triple of <literal>(foo, foo, foo)</literal>.
</para>
</section>
<section xml:id="ssec-cross-cookbook">
<title>Cross packaging cookbook</title>
<para>
Some frequently encountered problems when packaging for cross-compilation should be answered here. Ideally, the information above is exhaustive, so this section cannot provide any new information, but it is ludicrous and cruel to expect everyone to spend effort working through the interaction of many features just to figure out the same answer to the same common problem. Feel free to add to this list!
</para>
<qandaset>
<qandaentry xml:id="cross-qa-build-c-program-in-build-environment">
<question>
<para>
What if my package's build system needs to build a C program to be run under the build environment?
</para>
</question>
<answer>
<para>
<programlisting>depsBuildBuild = [ buildPackages.stdenv.cc ];</programlisting>
Add it to your <function>mkDerivation</function> invocation.
</para>
</answer>
</qandaentry>
<qandaentry xml:id="cross-qa-fails-to-find-ar">
<question>
<para>
My package fails to find <command>ar</command>.
</para>
</question>
<answer>
<para>
Many packages assume that an unprefixed <command>ar</command> is available, but Nix doesn't provide one. It only provides a prefixed one, just as it only does for all the other binutils programs. It may be necessary to patch the package to fix the build system to use a prefixed <command>ar</command>.
</para>
</answer>
</qandaentry>
<qandaentry xml:id="cross-testsuite-runs-host-code">
<question>
<para>
My package's testsuite needs to run host platform code.
</para>
</question>
<answer>
<para>
<programlisting>doCheck = stdenv.hostPlatform == stdenv.buildPlatfrom;</programlisting>
Add it to your <function>mkDerivation</function> invocation.
</para>
</answer>
</qandaentry>
</qandaset>
</section>
</section>
<!--============================================================-->
<section xml:id="sec-cross-usage">
<title>Cross-building packages</title>
<para>
Nixpkgs can be instantiated with <varname>localSystem</varname> alone, in which case there is no cross-compiling and everything is built by and for that system, or also with <varname>crossSystem</varname>, in which case packages run on the latter, but all building happens on the former. Both parameters take the same schema as the 3 (build, host, and target) platforms defined in the previous section. As mentioned above, <literal>lib.systems.examples</literal> has some platforms which are used as arguments for these parameters in practice. You can use them programmatically, or on the command line:
<programlisting>
nix-build '&lt;nixpkgs&gt;' --arg crossSystem '(import &lt;nixpkgs/lib&gt;).systems.examples.fooBarBaz' -A whatever</programlisting>
</para>
<note>
<para>
Eventually we would like to make these platform examples an unnecessary convenience so that
<programlisting>
nix-build '&lt;nixpkgs&gt;' --arg crossSystem '{ config = "&lt;arch&gt;-&lt;os&gt;-&lt;vendor&gt;-&lt;abi&gt;"; }' -A whatever</programlisting>
works in the vast majority of cases. The problem today is dependencies on other sorts of configuration which aren't given proper defaults. We rely on the examples to crudely to set those configuration parameters in some vaguely sane manner on the users behalf. Issue <link xlink:href="https://github.com/NixOS/nixpkgs/issues/34274">#34274</link> tracks this inconvenience along with its root cause in crufty configuration options.
</para>
</note>
<para>
While one is free to pass both parameters in full, there's a lot of logic to fill in missing fields. As discussed in the previous section, only one of <varname>system</varname>, <varname>config</varname>, and <varname>parsed</varname> is needed to infer the other two. Additionally, <varname>libc</varname> will be inferred from <varname>parse</varname>. Finally, <literal>localSystem.system</literal> is also <emphasis>impurely</emphasis> inferred based on the platform evaluation occurs. This means it is often not necessary to pass <varname>localSystem</varname> at all, as in the command-line example in the previous paragraph.
</para>
<note>
<para>
Many sources (manual, wiki, etc) probably mention passing <varname>system</varname>, <varname>platform</varname>, along with the optional <varname>crossSystem</varname> to nixpkgs: <literal>import &lt;nixpkgs&gt; { system = ..; platform = ..; crossSystem = ..; }</literal>. Passing those two instead of <varname>localSystem</varname> is still supported for compatibility, but is discouraged. Indeed, much of the inference we do for these parameters is motivated by compatibility as much as convenience.
</para>
</note>
<para>
One would think that <varname>localSystem</varname> and <varname>crossSystem</varname> overlap horribly with the three <varname>*Platforms</varname> (<varname>buildPlatform</varname>, <varname>hostPlatform,</varname> and <varname>targetPlatform</varname>; see <varname>stage.nix</varname> or the manual). Actually, those identifiers are purposefully not used here to draw a subtle but important distinction: While the granularity of having 3 platforms is necessary to properly *build* packages, it is overkill for specifying the user's *intent* when making a build plan or package set. A simple "build vs deploy" dichotomy is adequate: the sliding window principle described in the previous section shows how to interpolate between the these two "end points" to get the 3 platform triple for each bootstrapping stage. That means for any package a given package set, even those not bound on the top level but only reachable via dependencies or <varname>buildPackages</varname>, the three platforms will be defined as one of <varname>localSystem</varname> or <varname>crossSystem</varname>, with the former replacing the latter as one traverses build-time dependencies. A last simple difference is that <varname>crossSystem</varname> should be null when one doesn't want to cross-compile, while the <varname>*Platform</varname>s are always non-null. <varname>localSystem</varname> is always non-null.
</para>
</section>
<!--============================================================-->
<section xml:id="sec-cross-infra">
<title>Cross-compilation infrastructure</title>
<section xml:id="ssec-cross-dependency-implementation">
<title>Implementation of dependencies</title>
<para>
The categorizes of dependencies developed in <xref
linkend="ssec-cross-dependency-categorization"/> are specified as lists of derivations given to <varname>mkDerivation</varname>, as documented in <xref linkend="ssec-stdenv-dependencies"/>. In short, each list of dependencies for "host → target" of "foo → bar" is called <varname>depsFooBar</varname>, with exceptions for backwards compatibility that <varname>depsBuildHost</varname> is instead called <varname>nativeBuildInputs</varname> and <varname>depsHostTarget</varname> is instead called <varname>buildInputs</varname>. Nixpkgs is now structured so that each <varname>depsFooBar</varname> is automatically taken from <varname>pkgsFooBar</varname>. (These <varname>pkgsFooBar</varname>s are quite new, so there is no special case for <varname>nativeBuildInputs</varname> and <varname>buildInputs</varname>.) For example, <varname>pkgsBuildHost.gcc</varname> should be used at build-time, while <varname>pkgsHostTarget.gcc</varname> should be used at run-time.
</para>
<para>
Now, for most of Nixpkgs's history, there were no <varname>pkgsFooBar</varname> attributes, and most packages have not been refactored to use it explicitly. Prior to those, there were just <varname>buildPackages</varname>, <varname>pkgs</varname>, and <varname>targetPackages</varname>. Those are now redefined as aliases to <varname>pkgsBuildHost</varname>, <varname>pkgsHostTarget</varname>, and <varname>pkgsTargetTarget</varname>. It is acceptable, even recommended, to use them for libraries to show that the host platform is irrelevant.
</para>
<para>
But before that, there was just <varname>pkgs</varname>, even though both <varname>buildInputs</varname> and <varname>nativeBuildInputs</varname> existed. [Cross barely worked, and those were implemented with some hacks on <varname>mkDerivation</varname> to override dependencies.] What this means is the vast majority of packages do not use any explicit package set to populate their dependencies, just using whatever <varname>callPackage</varname> gives them even if they do correctly sort their dependencies into the multiple lists described above. And indeed, asking that users both sort their dependencies, <emphasis>and</emphasis> take them from the right attribute set, is both too onerous and redundant, so the recommended approach (for now) is to continue just categorizing by list and not using an explicit package set.
</para>
<para>
To make this work, we "splice" together the six <varname>pkgsFooBar</varname> package sets and have <varname>callPackage</varname> actually take its arguments from that. This is currently implemented in <filename>pkgs/top-level/splice.nix</filename>. <varname>mkDerivation</varname> then, for each dependency attribute, pulls the right derivation out from the splice. This splicing can be skipped when not cross-compiling as the package sets are the same, but still is a bit slow for cross-compiling. We'd like to do something better, but haven't come up with anything yet.
</para>
</section>
<section xml:id="ssec-bootstrapping">
<title>Bootstrapping</title>
<para>
Each of the package sets described above come from a single bootstrapping stage. While <filename>pkgs/top-level/default.nix</filename>, coordinates the composition of stages at a high level, <filename>pkgs/top-level/stage.nix</filename> "ties the knot" (creates the fixed point) of each stage. The package sets are defined per-stage however, so they can be thought of as edges between stages (the nodes) in a graph. Compositions like <literal>pkgsBuildTarget.targetPackages</literal> can be thought of as paths to this graph.
</para>
<para>
While there are many package sets, and thus many edges, the stages can also be arranged in a linear chain. In other words, many of the edges are redundant as far as connectivity is concerned. This hinges on the type of bootstrapping we do. Currently for cross it is:
<orderedlist>
<listitem>
<para>
<literal>(native, native, native)</literal>
</para>
</listitem>
<listitem>
<para>
<literal>(native, native, foreign)</literal>
</para>
</listitem>
<listitem>
<para>
<literal>(native, foreign, foreign)</literal>
</para>
</listitem>
</orderedlist>
In each stage, <varname>pkgsBuildHost</varname> refers to the previous stage, <varname>pkgsBuildBuild</varname> refers to the one before that, and <varname>pkgsHostTarget</varname> refers to the current one, and <varname>pkgsTargetTarget</varname> refers to the next one. When there is no previous or next stage, they instead refer to the current stage. Note how all the invariants regarding the mapping between dependency and depending packages' build host and target platforms are preserved. <varname>pkgsBuildTarget</varname> and <varname>pkgsHostHost</varname> are more complex in that the stage fitting the requirements isn't always a fixed chain of "prevs" and "nexts" away (modulo the "saturating" self-references at the ends). We just special case each instead. All the primary edges are implemented is in <filename>pkgs/stdenv/booter.nix</filename>, and secondarily aliases in <filename>pkgs/top-level/stage.nix</filename>.
</para>
<note>
<para>
Note the native stages are bootstrapped in legacy ways that predate the current cross implementation. This is why the bootstrapping stages leading up to the final stages are ignored inthe previous paragraph.
</para>
</note>
<para>
If one looks at the 3 platform triples, one can see that they overlap such that one could put them together into a chain like:
<programlisting>
(native, native, native, foreign, foreign)
</programlisting>
If one imagines the saturating self references at the end being replaced with infinite stages, and then overlays those platform triples, one ends up with the infinite tuple:
<programlisting>
(native..., native, native, native, foreign, foreign, foreign...)
</programlisting>
On can then imagine any sequence of platforms such that there are bootstrap stages with their 3 platforms determined by "sliding a window" that is the 3 tuple through the sequence. This was the original model for bootstrapping. Without a target platform (assume a better world where all compilers are multi-target and all standard libraries are built in their own derivation), this is sufficient. Conversely if one wishes to cross compile "faster", with a "Canadian Cross" bootstraping stage where <literal>build != host != target</literal>, more bootstrapping stages are needed since no sliding window providess the pesky <varname>pkgsBuildTarget</varname> package set since it skips the Canadian cross stage's "host".
</para>
<note>
<para>
It is much better to refer to <varname>buildPackages</varname> than <varname>targetPackages</varname>, or more broadly package sets that do not mention "target". There are three reasons for this.
</para>
<para>
First, it is because bootstrapping stages do not have a unique <varname>targetPackages</varname>. For example a <literal>(x86-linux, x86-linux, arm-linux)</literal> and <literal>(x86-linux, x86-linux, x86-windows)</literal> package set both have a <literal>(x86-linux, x86-linux, x86-linux)</literal> package set. Because there is no canonical <varname>targetPackages</varname> for such a native (<literal>build == host == target</literal>) package set, we set their <varname>targetPackages</varname>
</para>
<para>
Second, it is because this is a frequent source of hard-to-follow "infinite recursions" / cycles. When only package sets that don't mention target are used, the package set forms a directed acyclic graph. This means that all cycles that exist are confined to one stage. This means they are a lot smaller, and easier to follow in the code or a backtrace. It also means they are present in native and cross builds alike, and so more likely to be caught by CI and other users.
</para>
<para>
Thirdly, it is because everything target-mentioning only exists to accommodate compilers with lousy build systems that insist on the compiler itself and standard library being built together. Of course that is bad because bigger derivations means longer rebuilds. It is also problematic because it tends to make the standard libraries less like other libraries than they could be, complicating code and build systems alike. Because of the other problems, and because of these innate disadvantages, compilers ought to be packaged another way where possible.
</para>
</note>
<note>
<para>
If one explores Nixpkgs, they will see derivations with names like <literal>gccCross</literal>. Such <literal>*Cross</literal> derivations is a holdover from before we properly distinguished between the host and target platforms—the derivation with "Cross" in the name covered the <literal>build = host != target</literal> case, while the other covered the <literal>host = target</literal>, with build platform the same or not based on whether one was using its <literal>.nativeDrv</literal> or <literal>.crossDrv</literal>. This ugliness will disappear soon.
</para>
</note>
</section>
</section>
</chapter>

View file

@ -623,6 +623,12 @@ lib.mapAttrs (n: v: v // { shortName = n; }) {
fullName = "Open Software License 3.0";
};
parity70 = spdx {
spdxId = "Parity-7.0.0";
fullName = "Parity Public License 7.0.0";
url = "https://paritylicense.com/versions/7.0.0.html";
};
php301 = spdx {
spdxId = "PHP-3.01";
fullName = "PHP License v3.01";

View file

@ -12,6 +12,12 @@ rec {
broadwell = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "fma" ];
skylake = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "fma" ];
skylake-avx512 = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ];
cannonlake = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ];
icelake-client = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ];
icelake-server = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ];
cascadelake = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ];
cooperlake = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ];
tigerlake = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" "avx2" "avx512" "fma" ];
# x86_64 AMD
btver1 = [ "sse3" "ssse3" "sse4_1" "sse4_2" ];
btver2 = [ "sse3" "ssse3" "sse4_1" "sse4_2" "aes" "avx" ];
@ -21,6 +27,7 @@ rec {
bdver4 = [ "sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "avx2" "fma" "fma4" ];
znver1 = [ "sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "avx2" "fma" ];
znver2 = [ "sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "avx2" "fma" ];
znver3 = [ "sse3" "ssse3" "sse4_1" "sse4_2" "sse4a" "aes" "avx" "avx2" "fma" ];
# other
armv5te = [ ];
armv6 = [ ];
@ -41,15 +48,38 @@ rec {
broadwell = [ "haswell" ] ++ inferiors.haswell;
skylake = [ "broadwell" ] ++ inferiors.broadwell;
skylake-avx512 = [ "skylake" ] ++ inferiors.skylake;
# x86_64 AMD
# TODO: fill this (need testing)
btver1 = [ ];
btver2 = [ ]; # TODO: fill this (need testing)
bdver1 = [ ]; # TODO: fill this (need testing)
bdver2 = [ ]; # TODO: fill this (need testing)
bdver3 = [ ]; # TODO: fill this (need testing)
bdver4 = [ ]; # TODO: fill this (need testing)
znver1 = [ ]; # TODO: fill this (need testing)
znver2 = [ ]; # TODO: fill this (need testing)
btver2 = [ ];
bdver1 = [ ];
bdver2 = [ ];
bdver3 = [ ];
bdver4 = [ ];
# Regarding `skylake` as inferior of `znver1`, there are reports of
# successful usage by Gentoo users and Phoronix benchmarking of different
# `-march` targets.
#
# The GCC documentation on extensions used and wikichip documentation
# regarding supperted extensions on znver1 and skylake was used to create
# this partial order.
#
# Note:
#
# - The succesors of `skylake` (`cannonlake`, `icelake`, etc) use `avx512`
# which no current AMD Zen michroarch support.
# - `znver1` uses `ABM`, `CLZERO`, `CX16`, `MWAITX`, and `SSE4A` which no
# current Intel microarch support.
#
# https://www.phoronix.com/scan.php?page=article&item=amd-znver3-gcc11&num=1
# https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
# https://en.wikichip.org/wiki/amd/microarchitectures/zen
# https://en.wikichip.org/wiki/intel/microarchitectures/skylake
znver1 = [ "skylake" ] ++ inferiors.skylake;
znver2 = [ "znver1" ] ++ inferiors.znver1;
znver3 = [ "znver2" ] ++ inferiors.znver2;
# other
armv5te = [ ];
armv6 = [ ];

View file

@ -83,7 +83,7 @@ rec {
if final.isAarch32 then "arm"
else if final.isAarch64 then "arm64"
else if final.isx86_32 then "x86"
else if final.isx86_64 then "ia64"
else if final.isx86_64 then "x86"
else if final.isMips then "mips"
else final.parsed.cpu.name;

View file

@ -100,6 +100,12 @@
githubId = 178750;
name = "Andreas Baldeau";
};
abathur = {
email = "travis.a.everett+nixpkgs@gmail.com";
github = "abathur";
githubId = 2548365;
name = "Travis A. Everett";
};
abbe = {
email = "ashish.is@lostca.se";
github = "wahjava";
@ -183,7 +189,7 @@
name = "Adrien Devresse";
};
adisbladis = {
email = "adis@blad.is";
email = "adisbladis@gmail.com";
github = "adisbladis";
githubId = 63286;
name = "Adam Hose";
@ -574,6 +580,12 @@
githubId = 3808928;
name = "Anders Sildnes";
};
andys8 = {
email = "andys8@users.noreply.github.com";
github = "andys8";
githubId = 13085980;
name = "Andy";
};
aneeshusa = {
email = "aneeshusa@gmail.com";
github = "aneeshusa";
@ -2477,6 +2489,12 @@
githubId = 984691;
name = "Evan Danaher";
};
edbentley = {
email = "hello@edbentley.dev";
github = "edbentley";
githubId = 15923595;
name = "Ed Bentley";
};
edcragg = {
email = "ed.cragg@eipi.xyz";
github = "nuxeh";
@ -2893,6 +2911,16 @@
githubId = 11909469;
name = "Fabian Geiselhart";
};
fab = {
email = "mail@fabian-affolter.ch";
name = "Fabian Affolter";
github = "fabaff";
githubId = 116184;
keys = [{
longkeyid = "dsa1024/0xE23CD2DD36A4397F";
fingerprint = "2F6C 930F D3C4 7E38 6AFA 4EB4 E23C D2DD 36A4 397F";
}];
};
fabianhauser = {
email = "fabian.nixos@fh2.ch";
github = "fabianhauser";
@ -4924,6 +4952,12 @@
githubId = 45168934;
name = "Louis Blin";
};
lucc = {
email = "lucc+nix@posteo.de";
github = "lucc";
githubId = 1104419;
name = "Lucas Hoffmann";
};
ldelelis = {
email = "ldelelis@est.frba.utn.edu.ar";
github = "ldelelis";
@ -5210,6 +5244,10 @@
githubId = 10626;
name = "Andreas Wagner";
};
lrworth = {
email = "luke@worth.id.au";
name = "Luke Worth";
};
lschuermann = {
email = "leon.git@is.currently.online";
github = "lschuermann";
@ -6695,6 +6733,12 @@
githubId = 1449319;
name = "Pacien Tran-Girard";
};
pacman99 = {
email = "pachum99@gmail.com";
github = "Pacman99";
githubId = 16345849;
name = "Parthiv Seetharaman";
};
paddygord = {
email = "pgpatrickgordon@gmail.com";
github = "paddygord";
@ -7325,6 +7369,12 @@
githubId = 1758708;
name = "Răzvan Flavius Panda";
};
rb2k = {
email = "nix@marc-seeger.com";
github = "rb2k";
githubId = 9519;
name = "Marc Seeger";
};
rbasso = {
email = "rbasso@sharpgeeks.net";
github = "rbasso";
@ -7361,6 +7411,12 @@
githubId = 816465;
name = "Redvers Davies";
};
reedrw = {
email = "reedrw5601@gmail.com";
github = "reedrw";
githubId = 21069876;
name = "Reed Williams";
};
refnil = {
email = "broemartino@gmail.com";
github = "refnil";
@ -8475,6 +8531,12 @@
githubId = 638763;
name = "Stuart Moss";
};
stunkymonkey = {
email = "account@buehler.rocks";
github = "Stunkymonkey";
githubId = 1315818;
name = "Felix Bühler";
};
suhr = {
email = "suhr@i2pmail.org";
github = "suhr";
@ -9063,6 +9125,12 @@
githubId = 483735;
name = "Dmitry Geurkov";
};
truh = {
email = "jakob-nixos@truh.in";
github = "truh";
githubId = 1183303;
name = "Jakob Klepp";
};
tscholak = {
email = "torsten.scholak@googlemail.com";
github = "tscholak";
@ -9906,6 +9974,12 @@
githubId = 8100652;
name = "David Mell";
};
ztzg = {
email = "dd@crosstwine.com";
github = "ztzg";
githubId = 393108;
name = "Damien Diederen";
};
zx2c4 = {
email = "Jason@zx2c4.com";
github = "zx2c4";

View file

@ -34,7 +34,7 @@ let
/* Recursively find all packages (derivations) in `pkgs` matching `cond` predicate.
Type: packagesWithPath :: AttrPath (AttrPath derivation bool) (AttrSet | List) List<AttrSet{attrPath :: str; package :: derivation; }>
Type: packagesWithPath :: AttrPath (AttrPath derivation bool) AttrSet List<AttrSet{attrPath :: str; package :: derivation; }>
AttrPath :: [str]
The packages will be returned as a list of named pairs comprising of:
@ -60,8 +60,6 @@ let
if path == rootPath || evaluatedPathContent.recurseForDerivations or false || evaluatedPathContent.recurseForRelease or false then
dedupResults (lib.mapAttrsToList (name: elem: packagesWithPathInner (path ++ [name]) elem) evaluatedPathContent)
else []
else if lib.isList evaluatedPathContent then
dedupResults (lib.imap0 (i: elem: packagesWithPathInner (path ++ [i]) elem) evaluatedPathContent)
else []
else [];
in

View file

@ -83,7 +83,7 @@
VirtualBox settings (Machine / Settings / Shared Folders, then click on the
"Add" icon). Add the following to the
<literal>/etc/nixos/configuration.nix</literal> to auto-mount them. If you do
not add <literal>"nofail"</literal>, the system will no boot properly. The
not add <literal>"nofail"</literal>, the system will not boot properly. The
same goes for disabling <literal>rngd</literal> which is normally used to get
randomness but this does not work in virtual machines.
</para>

View file

@ -650,7 +650,7 @@ See https://github.com/NixOS/nixpkgs/pull/71684 for details.
<listitem>
<para>
<literal>boot.extraTTYs</literal> renamed to
<link linkend="opt-console.extraTTYs">console.extraTTYs</link>
<literal>console.extraTTYs</literal>.
</para>
</listitem>
</itemizedlist>

View file

@ -1344,6 +1344,12 @@ CREATE ROLE postgres LOGIN SUPERUSER;
that makes it unsuitable to be a default app.
</para>
</listitem>
<listitem>
<para>
If you want to manage the configuration of <package>wpa_supplicant</package> outside of NixOS you must ensure that none of <xref linkend="opt-networking.wireless.networks" />, <xref linkend="opt-networking.wireless.extraConfig" /> or <xref linkend="opt-networking.wireless.userControlled.enable" /> is being used or <literal>true</literal>.
Using any of those options will cause <package>wpa_supplicant</package> to be started with a NixOS generated configuration file instead of your own.
</para>
</listitem>
</itemizedlist>
</section>

View file

@ -265,6 +265,36 @@
located in <literal>/run/rspamd</literal> instead of <literal>/run</literal>.
</para>
</listitem>
<listitem>
<para>
Enabling the Tor client no longer silently also enables and
configures Privoxy, and the
<varname>services.tor.client.privoxy.enable</varname> option has
been removed. To enable Privoxy, and to configure it to use
Tor's faster port, use the following configuration:
</para>
<programlisting>
<xref linkend="opt-services.privoxy.enable" /> = true;
<xref linkend="opt-services.privoxy.enableTor" /> = true;
</programlisting>
</listitem>
<listitem>
<para>
The options <literal>services.slurm.dbdserver.storagePass</literal>
and <literal>services.slurm.dbdserver.configFile</literal> have been removed.
Use <literal>services.slurm.dbdserver.storagePassFile</literal> instead to provide the database password.
Extra config options can be given via the option <literal>services.slurm.dbdserver.extraConfig</literal>. The actual configuration file is created on the fly on startup of the service.
This avoids that the password gets exposed in the nix store.
</para>
</listitem>
<listitem>
<para>
Starting with version 1.7.0, the project formerly named <literal>CodiMD</literal>
is now named <literal>HedgeDoc</literal>.
New installations will no longer use the old name for users, state directories and such, this needs to be considered when moving state to a more recent NixOS installation.
Based on <xref linkend="opt-system.stateVersion" />, existing installations will continue to work.
</para>
</listitem>
</itemizedlist>
</section>
@ -276,6 +306,19 @@
<title>Other Notable Changes</title>
<itemizedlist>
<listitem>
<para>
The Mailman NixOS module (<literal>services.mailman</literal>) has a new
option <xref linkend="opt-services.mailman.enablePostfix" />, defaulting
to true, that controls integration with Postfix.
</para>
<para>
If this option is disabled, default MTA config becomes not set and you
should set the options in <literal>services.mailman.settings.mta</literal>
according to the desired configuration as described in
<link xlink:href="https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html">Mailman documentation</link>.
</para>
</listitem>
<listitem>
<para>
The default-version of <literal>nextcloud</literal> is <package>nextcloud20</package>.
@ -357,6 +400,13 @@
<literal>unbound-control</literal> without passing a custom configuration location.
</para>
</listitem>
<listitem>
<para>
The <literal>services.dnscrypt-proxy2</literal> module now takes the upstream's example configuration and updates it with the user's settings.
An option has been added to restore the old behaviour if you prefer to declare the configuration from scratch.
</para>
</listitem>
<listitem>
<para>
NixOS now defaults to the unified cgroup hierarchy (cgroupsv2).
@ -370,6 +420,32 @@
and rebooting.
</para>
</listitem>
<listitem>
<para>
PulseAudio was upgraded to 14.0, with changes to the handling of default sinks.
See its <link xlink:href="https://www.freedesktop.org/wiki/Software/PulseAudio/Notes/14.0/">release notes</link>.
</para>
<para>
GNOME users may wish to delete their <literal>~/.config/pulse</literal> due to the changes to stream routing
logic. See <link xlink:href="https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/issues/832">PulseAudio bug 832</link>
for more information.
</para>
</listitem>
<listitem>
<para>
The <package>zookeeper</package> package does not provide
<literal>zooInspector.sh</literal> anymore, as that "contrib" has
been dropped from upstream releases.
</para>
</listitem>
<listitem>
<para>
<xref linkend="opt-users.users._name_.createHome" /> now always ensures home directory permissions to be <literal>0700</literal>.
Permissions had previously been ignored for already existing home directories, possibly leaving them readable by others.
The option's description was incorrect regarding ownership management and has been simplified greatly.
</para>
</listitem>
</itemizedlist>
</section>
</section>

View file

@ -18,9 +18,13 @@
bootSize ? "256M"
, # The files and directories to be placed in the target file system.
# This is a list of attribute sets {source, target} where `source'
# is the file system object (regular file or directory) to be
# grafted in the file system at path `target'.
# This is a list of attribute sets {source, target, mode, user, group} where
# `source' is the file system object (regular file or directory) to be
# grafted in the file system at path `target', `mode' is a string containing
# the permissions that will be set (ex. "755"), `user' and `group' are the
# user and group name that will be set as owner of the files.
# `mode', `user', and `group' are optional.
# When setting one of `user' or `group', the other needs to be set too.
contents ? []
, # Type of partition table to use; either "legacy", "efi", or "none".
@ -60,6 +64,11 @@
assert partitionTableType == "legacy" || partitionTableType == "legacy+gpt" || partitionTableType == "efi" || partitionTableType == "hybrid" || partitionTableType == "none";
# We use -E offset=X below, which is only supported by e2fsprogs
assert partitionTableType != "none" -> fsType == "ext4";
# Either both or none of {user,group} need to be set
assert lib.all
(attrs: ((attrs.user or null) == null)
== ((attrs.group or null) == null))
contents;
with lib;
@ -148,6 +157,9 @@ let format' = format; in let
# !!! should use XML.
sources = map (x: x.source) contents;
targets = map (x: x.target) contents;
modes = map (x: x.mode or "''") contents;
users = map (x: x.user or "''") contents;
groups = map (x: x.group or "''") contents;
closureInfo = pkgs.closureInfo { rootPaths = [ config.system.build.toplevel channelSources ]; };
@ -174,22 +186,33 @@ let format' = format; in let
set -f
sources_=(${concatStringsSep " " sources})
targets_=(${concatStringsSep " " targets})
modes_=(${concatStringsSep " " modes})
set +f
for ((i = 0; i < ''${#targets_[@]}; i++)); do
source="''${sources_[$i]}"
target="''${targets_[$i]}"
mode="''${modes_[$i]}"
if [ -n "$mode" ]; then
rsync_chmod_flags="--chmod=$mode"
else
rsync_chmod_flags=""
fi
# Unfortunately cptofs only supports modes, not ownership, so we can't use
# rsync's --chown option. Instead, we change the ownerships in the
# VM script with chown.
rsync_flags="-a --no-o --no-g $rsync_chmod_flags"
if [[ "$source" =~ '*' ]]; then
# If the source name contains '*', perform globbing.
mkdir -p $root/$target
for fn in $source; do
rsync -a --no-o --no-g "$fn" $root/$target/
rsync $rsync_flags "$fn" $root/$target/
done
else
mkdir -p $root/$(dirname $target)
if ! [ -e $root/$target ]; then
rsync -a --no-o --no-g $source $root/$target
rsync $rsync_flags $source $root/$target
else
echo "duplicate entry $target -> $source"
exit 1
@ -284,6 +307,21 @@ in pkgs.vmTools.runInLinuxVM (
# The above scripts will generate a random machine-id and we don't want to bake a single ID into all our images
rm -f $mountPoint/etc/machine-id
# Set the ownerships of the contents. The modes are set in preVM.
# No globbing on targets, so no need to set -f
targets_=(${concatStringsSep " " targets})
users_=(${concatStringsSep " " users})
groups_=(${concatStringsSep " " groups})
for ((i = 0; i < ''${#targets_[@]}; i++)); do
target="''${targets_[$i]}"
user="''${users_[$i]}"
group="''${groups_[$i]}"
if [ -n "$user$group" ]; then
# We have to nixos-enter since we need to use the user and group of the VM
nixos-enter --root $mountPoint -- chown -R "$user:$group" "$target"
fi
done
umount -R /mnt
# Make sure resize2fs works. Note that resize2fs has stricter criteria for resizing than a normal

View file

@ -67,6 +67,8 @@ rec {
LOGFILE=/dev/null tests='exec(os.environ["testScript"])' ${driver}/bin/nixos-test-driver
'';
passthru = driver.passthru;
};
@ -76,6 +78,7 @@ rec {
, name ? "unnamed"
# Skip linting (mainly intended for faster dev cycles)
, skipLint ? false
, passthru ? {}
, ...
} @ t:
let
@ -137,7 +140,7 @@ rec {
testScript = testScript';
preferLocalBuild = true;
testName = name;
passthru = {
passthru = passthru // {
inherit nodes;
};
}

View file

@ -90,20 +90,6 @@ in
'';
};
extraTTYs = mkOption {
default = [];
type = types.listOf types.str;
example = ["tty8" "tty9"];
description = ''
TTY (virtual console) devices, in addition to the consoles on
which mingetty and syslogd run, that must be initialised.
Only useful if you have some program that you want to run on
some fixed console. For example, the NixOS installation CD
opens the manual in a web browser on console 7, so it sets
<option>console.extraTTYs</option> to <literal>["tty7"]</literal>.
'';
};
useXkbConfig = mkOption {
type = types.bool;
default = false;
@ -199,5 +185,9 @@ in
(mkRenamedOptionModule [ "i18n" "consoleUseXkbConfig" ] [ "console" "useXkbConfig" ])
(mkRenamedOptionModule [ "boot" "earlyVconsoleSetup" ] [ "console" "earlySetup" ])
(mkRenamedOptionModule [ "boot" "extraTTYs" ] [ "console" "extraTTYs" ])
(mkRemovedOptionModule [ "console" "extraTTYs" ] ''
Since NixOS switched to systemd (circa 2012), TTYs have been spawned on
demand, so there is no need to configure them manually.
'')
];
}

View file

@ -59,30 +59,28 @@ in
users.ldap = {
enable = mkOption {
type = types.bool;
default = false;
description = "Whether to enable authentication against an LDAP server.";
};
enable = mkEnableOption "authentication against an LDAP server";
loginPam = mkOption {
type = types.bool;
default = true;
description = "Whether to include authentication against LDAP in login PAM";
description = "Whether to include authentication against LDAP in login PAM.";
};
nsswitch = mkOption {
type = types.bool;
default = true;
description = "Whether to include lookup against LDAP in NSS";
description = "Whether to include lookup against LDAP in NSS.";
};
server = mkOption {
type = types.str;
example = "ldap://ldap.example.org/";
description = "The URL of the LDAP server.";
};
base = mkOption {
type = types.str;
example = "dc=example,dc=org";
description = "The distinguished name of the search base.";
};
@ -129,7 +127,7 @@ in
type = types.lines;
description = ''
Extra configuration options that will be added verbatim at
the end of the nslcd configuration file (nslcd.conf).
the end of the nslcd configuration file (<literal>nslcd.conf(5)</literal>).
'' ;
} ;
@ -180,7 +178,7 @@ in
description = ''
Specifies the time limit (in seconds) to use when connecting
to the directory server. This is distinct from the time limit
specified in <literal>users.ldap.timeLimit</literal> and affects
specified in <option>users.ldap.timeLimit</option> and affects
the initial server connection only.
'';
};
@ -197,7 +195,7 @@ in
actually contact the directory server, and it is possible that
a malformed configuration file will trigger reconnection. If
<literal>soft</literal> is specified, then
<literal>nss_ldap</literal> will return immediately on server
<package>nss_ldap</package> will return immediately on server
failure. All hard reconnect policies block with exponential
backoff before retrying.
'';
@ -209,10 +207,10 @@ in
type = types.lines;
description = ''
Extra configuration options that will be added verbatim at
the end of the ldap configuration file (ldap.conf).
If <literal>users.ldap.daemon</literal> is enabled, this
the end of the ldap configuration file (<literal>ldap.conf(5)</literal>).
If <option>users.ldap.daemon</option> is enabled, this
configuration will not be used. In that case, use
<literal>users.ldap.daemon.extraConfig</literal> instead.
<option>users.ldap.daemon.extraConfig</option> instead.
'' ;
};
@ -240,9 +238,9 @@ in
'';
};
system.nssModules = singleton (
system.nssModules = mkIf cfg.nsswitch (singleton (
if cfg.daemon.enable then nss_pam_ldapd else nss_ldap
);
));
system.nssDatabases.group = optional cfg.nsswitch "ldap";
system.nssDatabases.passwd = optional cfg.nsswitch "ldap";
@ -276,7 +274,12 @@ in
} >"$conf"
mv -fT "$conf" /run/nslcd/nslcd.conf
'';
restartTriggers = [ "/run/nslcd/nslcd.conf" ];
restartTriggers = [
nslcdConfig
cfg.bind.passwordFile
cfg.daemon.rootpwmodpwFile
];
serviceConfig = {
ExecStart = "${nslcdWrapped}/bin/nslcd";

View file

@ -209,10 +209,11 @@ foreach my $u (@{$spec->{users}}) {
}
}
# Create a home directory.
# Ensure home directory incl. ownership and permissions.
if ($u->{createHome}) {
make_path($u->{home}, { mode => 0700 }) if ! -e $u->{home};
chown $u->{uid}, $u->{gid}, $u->{home};
chmod 0700, $u->{home};
}
if (defined $u->{passwordFile}) {

View file

@ -198,10 +198,8 @@ let
type = types.bool;
default = false;
description = ''
If true, the home directory will be created automatically. If this
option is true and the home directory already exists but is not
owned by the user, directory owner and group will be changed to
match the user.
Whether to create the home directory and ensure ownership as well as
permissions to match the user.
'';
};

View file

@ -48,6 +48,7 @@ in {
rtl8192su-firmware
rt5677-firmware
rtl8723bs-firmware
rtl8761b-firmware
rtlwifi_new-firmware
zd1211fw
alsa-firmware

View file

@ -143,6 +143,13 @@ let
LINUX /boot/${config.system.boot.loader.kernelFile}
APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} loglevel=7
INITRD /boot/${config.system.boot.loader.initrdFile}
# A variant to boot with a serial console enabled
LABEL boot-serial
MENU LABEL NixOS ${config.system.nixos.label}${config.isoImage.appendToMenuLabel} (serial console=ttyS0,115200n8)
LINUX /boot/${config.system.boot.loader.kernelFile}
APPEND init=${config.system.build.toplevel}/init ${toString config.boot.kernelParams} console=ttyS0,115200n8
INITRD /boot/${config.system.boot.loader.initrdFile}
'';
isolinuxMemtest86Entry = ''

View file

@ -33,7 +33,7 @@
kernel=u-boot-rpi3.bin
# Boot in 64-bit mode.
arm_control=0x200
arm_64bit=1
# U-Boot used to need this to work, regardless of whether UART is actually used or not.
# TODO: check when/if this can be removed.

View file

@ -223,7 +223,7 @@ in
# Figure out device names for the boot device and root filesystem.
rootPart=$(${pkgs.util-linux}/bin/findmnt -n -o SOURCE /)
bootDevice=$(lsblk -npo PKNAME $rootPart)
partNum=$(lsblk -npo MAJ:MIN $rootPart | awk -F: '{print $2}')
partNum=$(lsblk -npo MAJ:MIN $rootPart | ${pkgs.gawk}/bin/awk -F: '{print $2}')
# Resize the root partition and the filesystem to fit the disk
echo ",+," | sfdisk -N$partNum --no-reread $bootDevice

View file

@ -1,6 +1,6 @@
{
x86_64-linux = "/nix/store/fwak7l5jjl0py4wldsqjbv7p7rdzql0b-nix-2.3.9";
i686-linux = "/nix/store/jlqrx9zw3vkwcczndaar5ban1j8g519z-nix-2.3.9";
aarch64-linux = "/nix/store/kzvpzlm12185hw27l5znrprgvcja54d0-nix-2.3.9";
x86_64-darwin = "/nix/store/kanh3awpf370pxfnjfvkh2m343wr3hj0-nix-2.3.9";
x86_64-linux = "/nix/store/iwfs2bfcy7lqwhri94p2i6jc87ih55zk-nix-2.3.10";
i686-linux = "/nix/store/a3ccfvy9i5n418d5v0bir330kbcz3vj8-nix-2.3.10";
aarch64-linux = "/nix/store/bh5g6cv7bv35iz853d3xv2sphn51ybmb-nix-2.3.10";
x86_64-darwin = "/nix/store/8c98r6zlwn2d40qm7jnnrr2rdlqviszr-nix-2.3.10";
}

View file

@ -73,7 +73,72 @@ in {
pruneFS = mkOption {
type = listOf str;
default = ["afs" "anon_inodefs" "auto" "autofs" "bdev" "binfmt" "binfmt_misc" "cgroup" "cifs" "coda" "configfs" "cramfs" "cpuset" "debugfs" "devfs" "devpts" "devtmpfs" "ecryptfs" "eventpollfs" "exofs" "futexfs" "ftpfs" "fuse" "fusectl" "gfs" "gfs2" "hostfs" "hugetlbfs" "inotifyfs" "iso9660" "jffs2" "lustre" "misc" "mqueue" "ncpfs" "nnpfs" "ocfs" "ocfs2" "pipefs" "proc" "ramfs" "rpc_pipefs" "securityfs" "selinuxfs" "sfs" "shfs" "smbfs" "sockfs" "spufs" "nfs" "NFS" "nfs4" "nfsd" "sshfs" "subfs" "supermount" "sysfs" "tmpfs" "ubifs" "udf" "usbfs" "vboxsf" "vperfctrfs" ];
default = [
"afs"
"anon_inodefs"
"auto"
"autofs"
"bdev"
"binfmt"
"binfmt_misc"
"cgroup"
"cifs"
"coda"
"configfs"
"cramfs"
"cpuset"
"debugfs"
"devfs"
"devpts"
"devtmpfs"
"ecryptfs"
"eventpollfs"
"exofs"
"futexfs"
"ftpfs"
"fuse"
"fusectl"
"fuse.sshfs"
"gfs"
"gfs2"
"hostfs"
"hugetlbfs"
"inotifyfs"
"iso9660"
"jffs2"
"lustre"
"misc"
"mqueue"
"ncpfs"
"nnpfs"
"ocfs"
"ocfs2"
"pipefs"
"proc"
"ramfs"
"rpc_pipefs"
"securityfs"
"selinuxfs"
"sfs"
"shfs"
"smbfs"
"sockfs"
"spufs"
"nfs"
"NFS"
"nfs4"
"nfsd"
"sshfs"
"subfs"
"supermount"
"sysfs"
"tmpfs"
"ubifs"
"udf"
"usbfs"
"vboxsf"
"vperfctrfs"
];
description = ''
Which filesystem types to exclude from indexing
'';

View file

@ -654,6 +654,8 @@
./services/networking/hylafax/default.nix
./services/networking/i2pd.nix
./services/networking/i2p.nix
./services/networking/icecream/scheduler.nix
./services/networking/icecream/daemon.nix
./services/networking/iodine.nix
./services/networking/iperf3.nix
./services/networking/ircd-hybrid/default.nix
@ -854,16 +856,15 @@
./services/web-apps/atlassian/confluence.nix
./services/web-apps/atlassian/crowd.nix
./services/web-apps/atlassian/jira.nix
./services/web-apps/codimd.nix
./services/web-apps/convos.nix
./services/web-apps/cryptpad.nix
./services/web-apps/documize.nix
./services/web-apps/dokuwiki.nix
./services/web-apps/engelsystem.nix
./services/web-apps/frab.nix
./services/web-apps/gerrit.nix
./services/web-apps/gotify-server.nix
./services/web-apps/grocy.nix
./services/web-apps/hedgedoc.nix
./services/web-apps/icingaweb2/icingaweb2.nix
./services/web-apps/icingaweb2/module-monitoring.nix
./services/web-apps/ihatemoney
@ -877,6 +878,7 @@
./services/web-apps/moodle.nix
./services/web-apps/nextcloud.nix
./services/web-apps/nexus.nix
./services/web-apps/plantuml-server.nix
./services/web-apps/pgpkeyserver-lite.nix
./services/web-apps/matomo.nix
./services/web-apps/moinmoin.nix

View file

@ -32,6 +32,7 @@ with lib;
(mkRemovedOptionModule ["services" "cgmanager" "enable"] "cgmanager was deprecated by lxc and therefore removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "osquery" ] "The osquery module has been removed")
(mkRemovedOptionModule [ "services" "fourStore" ] "The fourStore module has been removed")
(mkRemovedOptionModule [ "services" "frab" ] "The frab module has been removed")
(mkRemovedOptionModule [ "services" "fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed")
(mkRemovedOptionModule [ "services" "mathics" ] "The Mathics module has been removed")
(mkRemovedOptionModule [ "programs" "way-cooler" ] ("way-cooler is abandoned by its author: " +

View file

@ -104,7 +104,7 @@ let
mkHash = with builtins; val: substring 0 20 (hashString "sha256" val);
certDir = mkHash hashData;
domainHash = mkHash "${concatStringsSep " " extraDomains} ${data.domain}";
othersHash = mkHash "${toString acmeServer} ${data.keyType}";
othersHash = mkHash "${toString acmeServer} ${data.keyType} ${data.email}";
accountDir = "/var/lib/acme/.lego/accounts/" + othersHash;
protocolOpts = if useDns then (
@ -253,7 +253,8 @@ let
echo '${domainHash}' > domainhash.txt
# Check if we can renew
if [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' ]; then
# Certificates and account credentials must exist
if [ -e 'certificates/${keyName}.key' -a -e 'certificates/${keyName}.crt' -a "$(ls -1 accounts)" ]; then
# When domains are updated, there's no need to do a full
# Lego run, but it's likely renew won't work if days is too low.

View file

@ -263,4 +263,28 @@ chmod 400 /var/lib/secrets/certs.secret
ones.
</para>
</section>
<section xml:id="module-security-acme-fix-jws">
<title>Fixing JWS Verification error</title>
<para>
It is possible that your account credentials file may become corrupt and need
to be regnerated. In this scenario lego will produce the error <literal>JWS verification error</literal>.
The solution is to simply delete the associated accounts file and
re-run the affected service(s).
</para>
<programlisting>
# Find the accounts folder for the certificate
systemctl cat acme-example.com.service | grep -Po 'accounts/[^:]*'
export accountdir="$(!!)"
# Move this folder to some place else
mv /var/lib/acme/.lego/$accountdir{,.bak}
# Recreate the folder using systemd-tmpfiles
systemd-tmpfiles --create
# Get a new account and reissue certificates
# Note: Do this for all certs that share the same account email address
systemctl start acme-example.com.service
</programlisting>
</section>
</chapter>

View file

@ -66,7 +66,10 @@ in {
default = "${cfg.dataDir}/music";
defaultText = ''''${dataDir}/music'';
description = ''
The directory or NFS/SMB network share where mpd reads music from.
The directory or NFS/SMB network share where MPD reads music from. If left
as the default value this directory will automatically be created before
the MPD server starts, otherwise the sysadmin is responsible for ensuring
the directory exists with appropriate ownership and permissions.
'';
};
@ -75,7 +78,10 @@ in {
default = "${cfg.dataDir}/playlists";
defaultText = ''''${dataDir}/playlists'';
description = ''
The directory where mpd stores playlists.
The directory where MPD stores playlists. If left as the default value
this directory will automatically be created before the MPD server starts,
otherwise the sysadmin is responsible for ensuring the directory exists
with appropriate ownership and permissions.
'';
};
@ -94,8 +100,10 @@ in {
type = types.path;
default = "/var/lib/${name}";
description = ''
The directory where MPD stores its state, tag cache,
playlists etc.
The directory where MPD stores its state, tag cache, playlists etc. If
left as the default value this directory will automatically be created
before the MPD server starts, otherwise the sysadmin is responsible for
ensuring the directory exists with appropriate ownership and permissions.
'';
};
@ -185,36 +193,42 @@ in {
};
};
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' - ${cfg.user} ${cfg.group} - -"
"d '${cfg.playlistDirectory}' - ${cfg.user} ${cfg.group} - -"
];
systemd.services.mpd = {
after = [ "network.target" "sound.target" ];
description = "Music Player Daemon";
wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target";
serviceConfig = {
User = "${cfg.user}";
ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon /etc/mpd.conf";
ExecStartPre = pkgs.writeScript "mpd-start-pre" ''
#!${pkgs.runtimeShell}
set -euo pipefail
cat ${mpdConf} ${cfg.credentialsFile} > /etc/mpd.conf
'';
Type = "notify";
LimitRTPRIO = 50;
LimitRTTIME = "infinity";
ProtectSystem = true;
NoNewPrivileges = true;
ProtectKernelTunables = true;
ProtectControlGroups = true;
ProtectKernelModules = true;
RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_NETLINK";
RestrictNamespaces = true;
Restart = "always";
};
serviceConfig = mkMerge [
{
User = "${cfg.user}";
ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon /etc/mpd.conf";
ExecStartPre = pkgs.writeScript "mpd-start-pre" ''
#!${pkgs.runtimeShell}
set -euo pipefail
cat ${mpdConf} ${cfg.credentialsFile} > /etc/mpd.conf
'';
Type = "notify";
LimitRTPRIO = 50;
LimitRTTIME = "infinity";
ProtectSystem = true;
NoNewPrivileges = true;
ProtectKernelTunables = true;
ProtectControlGroups = true;
ProtectKernelModules = true;
RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_NETLINK";
RestrictNamespaces = true;
Restart = "always";
}
(mkIf (cfg.dataDir == "/var/lib/${name}") {
StateDirectory = [ name ];
})
(mkIf (cfg.playlistDirectory == "/var/lib/${name}/playlists") {
StateDirectory = [ name "${name}/playlists" ];
})
(mkIf (cfg.musicDirectory == "/var/lib/${name}/music") {
StateDirectory = [ name "${name}/music" ];
})
];
};
environment.etc."mpd.conf" = {
mode = "0640";

View file

@ -34,13 +34,12 @@ let
${cfg.extraCgroupConfig}
'';
slurmdbdConf = pkgs.writeTextDir "slurmdbd.conf"
slurmdbdConf = pkgs.writeText "slurmdbd.conf"
''
DbdHost=${cfg.dbdserver.dbdHost}
SlurmUser=${cfg.user}
StorageType=accounting_storage/mysql
StorageUser=${cfg.dbdserver.storageUser}
${optionalString (cfg.dbdserver.storagePass != null) "StoragePass=${cfg.dbdserver.storagePass}"}
${cfg.dbdserver.extraConfig}
'';
@ -95,26 +94,12 @@ in
'';
};
storagePass = mkOption {
type = types.nullOr types.str;
storagePassFile = mkOption {
type = with types; nullOr str;
default = null;
description = ''
Database password. Note that this password will be publicable
readable in the nix store. Use <option>configFile</option>
to store the and config file and password outside the nix store.
'';
};
configFile = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Path to <literal>slurmdbd.conf</literal>. The password for the database connection
is stored in the config file. Use this option to specfify a path
outside the nix store. If this option is unset a configuration file
will be generated. See also:
<citerefentry><refentrytitle>slurmdbd.conf</refentrytitle>
<manvolnum>8</manvolnum></citerefentry>.
Path to file with database password. The content of this will be used to
create the password for the <literal>StoragePass</literal> option.
'';
};
@ -122,7 +107,9 @@ in
type = types.lines;
default = "";
description = ''
Extra configuration for <literal>slurmdbd.conf</literal>
Extra configuration for <literal>slurmdbd.conf</literal> See also:
<citerefentry><refentrytitle>slurmdbd.conf</refentrytitle>
<manvolnum>8</manvolnum></citerefentry>.
'';
};
};
@ -292,6 +279,16 @@ in
};
imports = [
(mkRemovedOptionModule [ "services" "slurm" "dbdserver" "storagePass" ] ''
This option has been removed so that the database password is not exposed via the nix store.
Use services.slurm.dbdserver.storagePassFile to provide the database password.
'')
(mkRemovedOptionModule [ "services" "slurm" "dbdserver" "configFile" ] ''
This option has been removed. Use services.slurm.dbdserver.storagePassFile
and services.slurm.dbdserver.extraConfig instead.
'')
];
###### implementation
@ -386,23 +383,34 @@ in
'';
};
systemd.services.slurmdbd = mkIf (cfg.dbdserver.enable) {
systemd.services.slurmdbd = let
# slurm strips the last component off the path
configPath = "$RUNTIME_DIRECTORY/slurmdbd.conf";
in mkIf (cfg.dbdserver.enable) {
path = with pkgs; [ wrappedSlurm munge coreutils ];
wantedBy = [ "multi-user.target" ];
after = [ "network.target" "munged.service" "mysql.service" ];
requires = [ "munged.service" "mysql.service" ];
# slurm strips the last component off the path
environment.SLURM_CONF =
if (cfg.dbdserver.configFile == null) then
"${slurmdbdConf}/slurm.conf"
else
cfg.dbdserver.configFile;
preStart = ''
cp ${slurmdbdConf} ${configPath}
chmod 600 ${configPath}
chown ${cfg.user} ${configPath}
${optionalString (cfg.dbdserver.storagePassFile != null) ''
echo "StoragePass=$(cat ${cfg.dbdserver.storagePassFile})" \
>> ${configPath}
''}
'';
script = ''
export SLURM_CONF=${configPath}
exec ${cfg.package}/bin/slurmdbd -D
'';
serviceConfig = {
Type = "forking";
ExecStart = "${cfg.package}/bin/slurmdbd";
RuntimeDirectory = "slurmdbd";
Type = "simple";
PIDFile = "/run/slurmdbd.pid";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
};

View file

@ -176,7 +176,7 @@ in
postStart = ''
if test -e "${cfg.dbpath}/.first_startup"; then
${optionalString (cfg.initialScript != null) ''
${mongodb}/bin/mongo -u root -p ${cfg.initialRootPassword} admin "${cfg.initialScript}"
${mongodb}/bin/mongo ${optionalString (cfg.enableAuth) "-u root -p ${cfg.initialRootPassword}"} admin "${cfg.initialScript}"
''}
rm -f "${cfg.dbpath}/.first_startup"
fi

View file

@ -23,19 +23,26 @@ in {
default = null;
description = "the thermald manual configuration file.";
};
package = mkOption {
type = types.package;
default = pkgs.thermald;
defaultText = "pkgs.thermald";
description = "Which thermald package to use.";
};
};
};
###### implementation
config = mkIf cfg.enable {
services.dbus.packages = [ pkgs.thermald ];
services.dbus.packages = [ cfg.package ];
systemd.services.thermald = {
description = "Thermal Daemon Service";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = ''
${pkgs.thermald}/sbin/thermald \
${cfg.package}/sbin/thermald \
--no-daemon \
${optionalString cfg.debug "--loglevel=debug"} \
${optionalString (cfg.configFile != null) "--config-file ${cfg.configFile}"} \

View file

@ -205,7 +205,7 @@ in
extraRules = mkOption {
default = "";
example = ''
KERNEL=="eth*", ATTR{address}=="00:1D:60:B9:6D:4F", NAME="my_fast_network_card"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:1D:60:B9:6D:4F", KERNEL=="eth*", NAME="my_fast_network_card"
'';
type = types.lines;
description = ''

View file

@ -38,7 +38,7 @@ let
webSettingsJSON = pkgs.writeText "settings.json" (builtins.toJSON webSettings);
# TODO: Should this be RFC42-ised so that users can set additional options without modifying the module?
mtaConfig = pkgs.writeText "mailman-postfix.cfg" ''
postfixMtaConfig = pkgs.writeText "mailman-postfix.cfg" ''
[postfix]
postmap_command: ${pkgs.postfix}/bin/postmap
transport_file_type: hash
@ -81,7 +81,7 @@ in {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable Mailman on this host. Requires an active Postfix installation.";
description = "Enable Mailman on this host. Requires an active MTA on the host (e.g. Postfix).";
};
package = mkOption {
@ -92,6 +92,20 @@ in {
description = "Mailman package to use";
};
enablePostfix = mkOption {
type = types.bool;
default = true;
example = false;
description = ''
Enable Postfix integration. Requires an active Postfix installation.
If you want to use another MTA, set this option to false and configure
settings in services.mailman.settings.mta.
Refer to the Mailman manual for more info.
'';
};
siteOwner = mkOption {
type = types.str;
example = "postmaster@example.org";
@ -182,7 +196,7 @@ in {
pid_file = "/run/mailman/master.pid";
};
mta.configuration = lib.mkDefault "${mtaConfig}";
mta.configuration = lib.mkDefault (if cfg.enablePostfix then "${postfixMtaConfig}" else throw "When Mailman Postfix integration is disabled, set `services.mailman.settings.mta.configuration` to the path of the config file required to integrate with your MTA.");
"archiver.hyperkitty" = lib.mkIf cfg.hyperkitty.enable {
class = "mailman_hyperkitty.Archiver";
@ -211,14 +225,22 @@ in {
See <https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html>.
'';
};
in [
in (lib.optionals cfg.enablePostfix [
{ assertion = postfix.enable;
message = "Mailman requires Postfix";
message = ''
Mailman's default NixOS configuration requires Postfix to be enabled.
If you want to use another MTA, set services.mailman.enablePostfix
to false and configure settings in services.mailman.settings.mta.
Refer to <https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html>
for more info.
'';
}
(requirePostfixHash [ "relayDomains" ] "postfix_domains")
(requirePostfixHash [ "config" "transport_maps" ] "postfix_lmtp")
(requirePostfixHash [ "config" "local_recipient_maps" ] "postfix_lmtp")
];
]);
users.users.mailman = {
description = "GNU Mailman";
@ -275,7 +297,7 @@ in {
'';
}) ];
services.postfix = {
services.postfix = lib.mkIf cfg.enablePostfix {
recipientDelimiter = "+"; # bake recipient addresses in mail envelopes via VERP
config = {
owner_request_special = "no"; # Mailman handles -owner addresses on its own
@ -421,7 +443,7 @@ in {
inherit startAt;
restartTriggers = [ config.environment.etc."mailman3/settings.py".source ];
serviceConfig = {
ExecStart = "${pythonEnv}/bin/mailman-web runjobs minutely";
ExecStart = "${pythonEnv}/bin/mailman-web runjobs ${name}";
User = cfg.webUser;
Group = "mailman";
WorkingDirectory = "/var/lib/mailman-web";

View file

@ -13,9 +13,9 @@
</para>
<section xml:id="module-services-mailman-basic-usage">
<title>Basic usage</title>
<title>Basic usage with Postfix</title>
<para>
For a basic configuration, the following settings are suggested:
For a basic configuration with Postfix as the MTA, the following settings are suggested:
<programlisting>{ config, ... }: {
services.postfix = {
enable = true;
@ -56,4 +56,39 @@
necessary, but outside the scope of the Mailman module.
</para>
</section>
<section xml:id="module-services-mailman-other-mtas">
<title>Using with other MTAs</title>
<para>
Mailman also supports other MTA, though with a little bit more configuration. For example, to use Mailman with Exim, you can use the following settings:
<programlisting>{ config, ... }: {
services = {
mailman = {
enable = true;
siteOwner = "mailman@example.org";
<link linkend="opt-services.mailman.enablePostfix">enablePostfix</link> = false;
settings.mta = {
incoming = "mailman.mta.exim4.LMTP";
outgoing = "mailman.mta.deliver.deliver";
lmtp_host = "localhost";
lmtp_port = "8024";
smtp_host = "localhost";
smtp_port = "25";
configuration = "python:mailman.config.exim4";
};
};
exim = {
enable = true;
# You can configure Exim in a separate file to reduce configuration.nix clutter
config = builtins.readFile ./exim.conf;
};
};
}</programlisting>
</para>
<para>
The exim config needs some special additions to work with Mailman. Currently
NixOS can't manage Exim config with such granularity. Please refer to
<link xlink:href="https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html">Mailman documentation</link>
for more info on configuring Mailman for working with Exim.
</para>
</section>
</chapter>

View file

@ -52,7 +52,7 @@ let
};
type = mkOption {
type = types.enum [ "inet" "unix" "fifo" "pass" ];
type = types.enum [ "inet" "unix" "unix-dgram" "fifo" "pass" ];
default = "unix";
example = "inet";
description = "The type of the service";

View file

@ -76,6 +76,7 @@ in {
default = ''
zookeeper.root.logger=INFO, CONSOLE
log4j.rootLogger=INFO, CONSOLE
log4j.logger.org.apache.zookeeper.audit.Log4jAuditLogger=INFO, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[myid:%X{myid}] - %-5p [%t:%C{1}@%L] - %m%n
@ -128,11 +129,10 @@ in {
description = "Zookeeper Daemon";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment = { ZOOCFGDIR = configDir; };
serviceConfig = {
ExecStart = ''
${pkgs.jre}/bin/java \
-cp "${cfg.package}/lib/*:${cfg.package}/${cfg.package.name}.jar:${configDir}" \
-cp "${cfg.package}/lib/*:${configDir}" \
${escapeShellArgs cfg.extraCmdLineOptions} \
-Dzookeeper.datadir.autocreate=false \
${optionalString cfg.preferIPv4 "-Djava.net.preferIPv4Stack=true"} \
@ -143,6 +143,7 @@ in {
};
preStart = ''
echo "${toString cfg.id}" > ${cfg.dataDir}/myid
mkdir -p ${cfg.dataDir}/version-2
'';
};

View file

@ -37,10 +37,12 @@ let
"modemmanager"
"nextcloud"
"nginx"
"nginxlog"
"node"
"openvpn"
"postfix"
"postgres"
"py-air-control"
"redis"
"rspamd"
"rtl_433"

View file

@ -0,0 +1,51 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.nginxlog;
in {
port = 9117;
extraOpts = {
settings = mkOption {
type = types.attrs;
default = {};
description = ''
All settings of nginxlog expressed as an Nix attrset.
Check the official documentation for the corresponding YAML
settings that can all be used here: https://github.com/martin-helmich/prometheus-nginxlog-exporter
The `listen` object is already generated by `port`, `listenAddress` and `metricsEndpoint` and
will be merged with the value of `settings` before writting it as JSON.
'';
};
metricsEndpoint = mkOption {
type = types.str;
default = "/metrics";
description = ''
Path under which to expose metrics.
'';
};
};
serviceOpts = let
listenConfig = {
listen = {
port = cfg.port;
address = cfg.listenAddress;
metrics_endpoint = cfg.metricsEndpoint;
};
};
completeConfig = pkgs.writeText "nginxlog-exporter.yaml" (builtins.toJSON (lib.recursiveUpdate listenConfig cfg.settings));
in {
serviceConfig = {
ExecStart = ''
${pkgs.prometheus-nginxlog-exporter}/bin/prometheus-nginxlog-exporter -config-file ${completeConfig}
'';
Restart="always";
ProtectSystem="full";
};
};
}

View file

@ -0,0 +1,53 @@
{ config, lib, pkgs, options }:
with lib;
let
cfg = config.services.prometheus.exporters.py-air-control;
workingDir = "/var/lib/${cfg.stateDir}";
in
{
port = 9896;
extraOpts = {
deviceHostname = mkOption {
type = types.str;
example = "192.168.1.123";
description = ''
The hostname of the air purification device from which to scrape the metrics.
'';
};
protocol = mkOption {
type = types.str;
default = "http";
description = ''
The protocol to use when communicating with the air purification device.
Available: [http, coap, plain_coap]
'';
};
stateDir = mkOption {
type = types.str;
default = "prometheus-py-air-control-exporter";
description = ''
Directory below <literal>/var/lib</literal> to store runtime data.
This directory will be created automatically using systemd's StateDirectory mechanism.
'';
};
};
serviceOpts = {
serviceConfig = {
DynamicUser = false;
StateDirectory = cfg.stateDir;
WorkingDirectory = workingDir;
ExecStart = ''
${pkgs.python3Packages.py-air-control-exporter}/bin/py-air-control-exporter \
--host ${cfg.deviceHostname} \
--protocol ${cfg.protocol} \
--listen-port ${toString cfg.port} \
--listen-address ${cfg.listenAddress}
'';
Environment = [ "HOME=${workingDir}" ];
};
};
}

View file

@ -108,7 +108,7 @@ in {
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ];
RestrictNamespaces = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;

View file

@ -27,6 +27,16 @@ in
default = {};
};
upstreamDefaults = mkOption {
description = ''
Whether to base the config declared in <literal>services.dnscrypt-proxy2.settings</literal> on the upstream example config (<link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>)
Disable this if you want to declare your dnscrypt config from scratch.
'';
type = types.bool;
default = true;
};
configFile = mkOption {
description = ''
Path to TOML config file. See: <link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>
@ -38,7 +48,13 @@ in
json = builtins.toJSON cfg.settings;
passAsFile = [ "json" ];
} ''
${pkgs.remarshal}/bin/json2toml < $jsonPath > $out
${if cfg.upstreamDefaults then ''
${pkgs.remarshal}/bin/toml2json ${pkgs.dnscrypt-proxy2.src}/dnscrypt-proxy/example-dnscrypt-proxy.toml > example.json
${pkgs.jq}/bin/jq --slurp add example.json $jsonPath > config.json # merges the two
'' else ''
cp $jsonPath config.json
''}
${pkgs.remarshal}/bin/json2toml < config.json > $out
'';
defaultText = literalExample "TOML file generated from services.dnscrypt-proxy2.settings";
};

View file

@ -0,0 +1,155 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.icecream.daemon;
in {
###### interface
options = {
services.icecream.daemon = {
enable = mkEnableOption "Icecream Daemon";
openFirewall = mkOption {
type = types.bool;
description = ''
Whether to automatically open receive port in the firewall.
'';
};
openBroadcast = mkOption {
type = types.bool;
description = ''
Whether to automatically open the firewall for scheduler discovery.
'';
};
cacheLimit = mkOption {
type = types.ints.u16;
default = 256;
description = ''
Maximum size in Megabytes of cache used to store compile environments of compile clients.
'';
};
netName = mkOption {
type = types.str;
default = "ICECREAM";
description = ''
Network name to connect to. A scheduler with the same name needs to be running.
'';
};
noRemote = mkOption {
type = types.bool;
default = false;
description = ''
Prevent jobs from other nodes being scheduled on this daemon.
'';
};
schedulerHost = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Explicit scheduler hostname, useful in firewalled environments.
Uses scheduler autodiscovery via broadcast if set to null.
'';
};
maxProcesses = mkOption {
type = types.nullOr types.ints.u16;
default = null;
description = ''
Maximum number of compile jobs started in parallel for this daemon.
Uses the number of CPUs if set to null.
'';
};
nice = mkOption {
type = types.int;
default = 5;
description = ''
The level of niceness to use.
'';
};
hostname = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Hostname of the daemon in the icecream infrastructure.
Uses the hostname retrieved via uname if set to null.
'';
};
user = mkOption {
type = types.str;
default = "icecc";
description = ''
User to run the icecream daemon as. Set to root to enable receive of
remote compile environments.
'';
};
package = mkOption {
default = pkgs.icecream;
defaultText = "pkgs.icecream";
type = types.package;
description = "Icecream package to use.";
};
extraArgs = mkOption {
type = types.listOf types.str;
default = [];
description = "Additional command line parameters.";
example = [ "-v" ];
};
};
};
###### implementation
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ 10245 ];
networking.firewall.allowedUDPPorts = mkIf cfg.openBroadcast [ 8765 ];
systemd.services.icecc-daemon = {
description = "Icecream compile daemon";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = escapeShellArgs ([
"${getBin cfg.package}/bin/iceccd"
"-b" "$STATE_DIRECTORY"
"-u" "icecc"
(toString cfg.nice)
]
++ optionals (cfg.schedulerHost != null) ["-s" cfg.schedulerHost]
++ optionals (cfg.netName != null) [ "-n" cfg.netName ]
++ optionals (cfg.cacheLimit != null) [ "--cache-limit" (toString cfg.cacheLimit) ]
++ optionals (cfg.maxProcesses != null) [ "-m" (toString cfg.maxProcesses) ]
++ optionals (cfg.hostname != null) [ "-N" (cfg.hostname) ]
++ optional cfg.noRemote "--no-remote"
++ cfg.extraArgs);
DynamicUser = true;
User = "icecc";
Group = "icecc";
StateDirectory = "icecc";
RuntimeDirectory = "icecc";
AmbientCapabilities = "CAP_SYS_CHROOT";
CapabilityBoundingSet = "CAP_SYS_CHROOT";
};
};
};
meta.maintainers = with lib.maintainers; [ emantor ];
}

View file

@ -0,0 +1,101 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.icecream.scheduler;
in {
###### interface
options = {
services.icecream.scheduler = {
enable = mkEnableOption "Icecream Scheduler";
netName = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Network name for the icecream scheduler.
Uses the default ICECREAM if null.
'';
};
port = mkOption {
type = types.port;
default = 8765;
description = ''
Server port to listen for icecream daemon requests.
'';
};
openFirewall = mkOption {
type = types.bool;
description = ''
Whether to automatically open the daemon port in the firewall.
'';
};
openTelnet = mkOption {
type = types.bool;
default = false;
description = ''
Whether to open the telnet TCP port on 8766.
'';
};
persistentClientConnection = mkOption {
type = types.bool;
default = false;
description = ''
Whether to prevent clients from connecting to a better scheduler.
'';
};
package = mkOption {
default = pkgs.icecream;
defaultText = "pkgs.icecream";
type = types.package;
description = "Icecream package to use.";
};
extraArgs = mkOption {
type = types.listOf types.str;
default = [];
description = "Additional command line parameters";
example = [ "-v" ];
};
};
};
###### implementation
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = mkMerge [
(mkIf cfg.openFirewall [ cfg.port ])
(mkIf cfg.openTelnet [ 8766 ])
];
systemd.services.icecc-scheduler = {
description = "Icecream scheduling server";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = escapeShellArgs ([
"${getBin cfg.package}/bin/icecc-scheduler"
"-p" (toString cfg.port)
]
++ optionals (cfg.netName != null) [ "-n" (toString cfg.netName) ]
++ optional cfg.persistentClientConnection "-r"
++ cfg.extraArgs);
DynamicUser = true;
};
};
};
meta.maintainers = with lib.maintainers; [ emantor ];
}

View file

@ -135,6 +135,8 @@ in {
CacheDirectory = "knot-resolver";
CacheDirectoryMode = "0770";
};
# We don't mind running stop phase from wrong version. It seems less racy.
systemd.services."kresd@".stopIfChanged = false;
# Try cleaning up the previously default location of cache file.
# Note that /var/cache/* should always be safe to remove.

View file

@ -8,15 +8,22 @@ let
cfg = config.services.privoxy;
confFile = pkgs.writeText "privoxy.conf" ''
confFile = pkgs.writeText "privoxy.conf" (''
user-manual ${privoxy}/share/doc/privoxy/user-manual
confdir ${privoxy}/etc/
listen-address ${cfg.listenAddress}
enable-edit-actions ${if (cfg.enableEditActions == true) then "1" else "0"}
${concatMapStrings (f: "actionsfile ${f}\n") cfg.actionsFiles}
${concatMapStrings (f: "filterfile ${f}\n") cfg.filterFiles}
'' + optionalString cfg.enableTor ''
forward-socks4a / ${config.services.tor.client.socksListenAddressFaster} .
toggle 1
enable-remote-toggle 0
enable-edit-actions 0
enable-remote-http-toggle 0
'' + ''
${cfg.extraConfig}
'';
'');
in
@ -72,6 +79,15 @@ in
'';
};
enableTor = mkOption {
type = types.bool;
default = false;
description = ''
Whether to configure Privoxy to use Tor's faster SOCKS port,
suitable for HTTP.
'';
};
extraConfig = mkOption {
type = types.lines;
default = "" ;

View file

@ -1,13 +1,156 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.tinc;
in
mkValueString = value:
if value == true then "yes"
else if value == false then "no"
else generators.mkValueStringDefault { } value;
toTincConf = generators.toKeyValue {
listsAsDuplicateKeys = true;
mkKeyValue = generators.mkKeyValueDefault { inherit mkValueString; } "=";
};
tincConfType = with types;
let
valueType = oneOf [ bool str int ];
in
attrsOf (either valueType (listOf valueType));
addressSubmodule = {
options = {
address = mkOption {
type = types.str;
description = "The external IP address or hostname where the host can be reached.";
};
port = mkOption {
type = types.nullOr types.port;
default = null;
description = ''
The port where the host can be reached.
If no port is specified, the default Port is used.
'';
};
};
};
subnetSubmodule = {
options = {
address = mkOption {
type = types.str;
description = ''
The subnet of this host.
Subnets can either be single MAC, IPv4 or IPv6 addresses, in which case
a subnet consisting of only that single address is assumed, or they can
be a IPv4 or IPv6 network address with a prefix length.
IPv4 subnets are notated like 192.168.1.0/24, IPv6 subnets are notated
like fec0:0:0:1::/64. MAC addresses are notated like 0:1a:2b:3c:4d:5e.
Note that subnets like 192.168.1.1/24 are invalid.
'';
};
prefixLength = mkOption {
type = with types; nullOr (addCheck int (n: n >= 0 && n <= 128));
default = null;
description = ''
The prefix length of the subnet.
If null, a subnet consisting of only that single address is assumed.
This conforms to standard CIDR notation as described in RFC1519.
'';
};
weight = mkOption {
type = types.ints.unsigned;
default = 10;
description = ''
Indicates the priority over identical Subnets owned by different nodes.
Lower values indicate higher priority. Packets will be sent to the
node with the highest priority, unless that node is not reachable, in
which case the node with the next highest priority will be tried, and
so on.
'';
};
};
};
hostSubmodule = { config, ... }: {
options = {
addresses = mkOption {
type = types.listOf (types.submodule addressSubmodule);
default = [ ];
description = ''
The external address where the host can be reached. This will set this
host's <option>settings.Address</option> option.
This variable is only required if you want to connect to this host.
'';
};
subnets = mkOption {
type = types.listOf (types.submodule subnetSubmodule);
default = [ ];
description = ''
The subnets which this tinc daemon will serve. This will set this
host's <option>settings.Subnet</option> option.
Tinc tries to look up which other daemon it should send a packet to by
searching the appropriate subnet. If the packet matches a subnet, it
will be sent to the daemon who has this subnet in his host
configuration file.
'';
};
rsaPublicKey = mkOption {
type = types.str;
default = "";
description = ''
Legacy RSA public key of the host in PEM format, including start and
end markers.
This will be appended as-is in the host's configuration file.
The ed25519 public key can be specified using the
<option>settings.Ed25519PublicKey</option> option instead.
'';
};
settings = mkOption {
default = { };
type = types.submodule { freeformType = tincConfType; };
description = ''
Configuration for this host.
See <link xlink:href="https://tinc-vpn.org/documentation-1.1/Host-configuration-variables.html"/>
for supported values.
'';
};
};
config.settings = {
Address = mkDefault (map
(address: "${address.address} ${toString address.port}")
config.addresses);
Subnet = mkDefault (map
(subnet:
if subnet.prefixLength == null then "${subnet.address}#${toString subnet.weight}"
else "${subnet.address}/${toString subnet.prefixLength}#${toString subnet.weight}")
config.subnets);
};
};
in
{
###### interface
@ -18,7 +161,7 @@ in
networks = mkOption {
default = { };
type = with types; attrsOf (submodule {
type = with types; attrsOf (submodule ({ config, ... }: {
options = {
extraConfig = mkOption {
@ -26,6 +169,9 @@ in
type = types.lines;
description = ''
Extra lines to add to the tinc service configuration file.
Note that using the declarative <option>service.tinc.networks.&lt;name&gt;.settings</option>
option is preferred.
'';
};
@ -69,6 +215,40 @@ in
hosts = mkOption {
default = { };
type = types.attrsOf types.lines;
description = ''
The name of the host in the network as well as the configuration for that host.
This name should only contain alphanumerics and underscores.
Note that using the declarative <option>service.tinc.networks.&lt;name&gt;.hostSettings</option>
option is preferred.
'';
};
hostSettings = mkOption {
default = { };
example = literalExample ''
{
host1 = {
addresses = [
{ address = "192.168.1.42"; }
{ address = "192.168.1.42"; port = 1655; }
];
subnets = [ { address = "10.0.0.42"; } ];
rsaPublicKey = "...";
settings = {
Ed25519PublicKey = "...";
};
};
host2 = {
subnets = [ { address = "10.0.1.0"; prefixLength = 24; weight = 2; } ];
rsaPublicKey = "...";
settings = {
Compression = 10;
};
};
}
'';
type = types.attrsOf (types.submodule hostSubmodule);
description = ''
The name of the host in the network as well as the configuration for that host.
This name should only contain alphanumerics and underscores.
@ -79,7 +259,7 @@ in
default = "tun";
type = types.enum [ "tun" "tap" ];
description = ''
The type of virtual interface used for the network connection
The type of virtual interface used for the network connection.
'';
};
@ -118,8 +298,44 @@ in
Note that tinc can't run scripts anymore (such as tinc-down or host-up), unless it is setup to be runnable inside chroot environment.
'';
};
settings = mkOption {
default = { };
type = types.submodule { freeformType = tincConfType; };
example = literalExample ''
{
Interface = "custom.interface";
DirectOnly = true;
Mode = "switch";
}
'';
description = ''
Configuration of the Tinc daemon for this network.
See <link xlink:href="https://tinc-vpn.org/documentation-1.1/Main-configuration-variables.html"/>
for supported values.
'';
};
};
});
config = {
hosts = mapAttrs
(hostname: host: ''
${toTincConf host.settings}
${host.rsaPublicKey}
'')
config.hostSettings;
settings = {
DeviceType = mkDefault config.interfaceType;
Name = mkDefault (if config.name == null then "$HOST" else config.name);
Ed25519PrivateKeyFile = mkIf (config.ed25519PrivateKeyFile != null) (mkDefault config.ed25519PrivateKeyFile);
PrivateKeyFile = mkIf (config.rsaPrivateKeyFile != null) (mkDefault config.rsaPrivateKeyFile);
ListenAddress = mkIf (config.listenAddress != null) (mkDefault config.listenAddress);
BindToAddress = mkIf (config.bindToAddress != null) (mkDefault config.bindToAddress);
};
};
}));
description = ''
Defines the tinc networks which will be started.
@ -144,13 +360,7 @@ in
"tinc/${network}/tinc.conf" = {
mode = "0444";
text = ''
Name = ${if data.name == null then "$HOST" else data.name}
DeviceType = ${data.interfaceType}
${optionalString (data.ed25519PrivateKeyFile != null) "Ed25519PrivateKeyFile = ${data.ed25519PrivateKeyFile}"}
${optionalString (data.rsaPrivateKeyFile != null) "PrivateKeyFile = ${data.rsaPrivateKeyFile}"}
${optionalString (data.listenAddress != null) "ListenAddress = ${data.listenAddress}"}
${optionalString (data.bindToAddress != null) "BindToAddress = ${data.bindToAddress}"}
Interface = tinc.${network}
${toTincConf ({ Interface = "tinc.${network}"; } // data.settings)}
${data.extraConfig}
'';
};
@ -168,6 +378,7 @@ in
Type = "simple";
Restart = "always";
RestartSec = "3";
ExecReload = mkIf (versionAtLeast (getVersion data.package) "1.1pre") "${data.package}/bin/tinc -n ${network} reload";
ExecStart = "${data.package}/bin/tincd -D -U tinc.${network} -n ${network} ${optionalString (data.chroot) "-R"} --pidfile /run/tinc.${network}.pid -d ${toString data.debugLevel}";
};
preStart = ''
@ -221,4 +432,5 @@ in
};
meta.maintainers = with maintainers; [ minijackson ];
}

View file

@ -51,6 +51,6 @@ in
###### implementation
config.powerManagement.powerDownCommands = lines;
config.powerManagement.powerUpCommands = lines;
}

View file

@ -119,15 +119,17 @@ in {
# firewall rules before sshguard starts.
preStart = optionalString config.networking.firewall.enable ''
${pkgs.ipset}/bin/ipset -quiet create -exist sshguard4 hash:net family inet
${pkgs.ipset}/bin/ipset -quiet create -exist sshguard6 hash:net family inet6
${pkgs.iptables}/bin/iptables -I INPUT -m set --match-set sshguard4 src -j DROP
'' + optionalString (config.networking.firewall.enable && config.networking.enableIPv6) ''
${pkgs.ipset}/bin/ipset -quiet create -exist sshguard6 hash:net family inet6
${pkgs.iptables}/bin/ip6tables -I INPUT -m set --match-set sshguard6 src -j DROP
'';
postStop = optionalString config.networking.firewall.enable ''
${pkgs.iptables}/bin/iptables -D INPUT -m set --match-set sshguard4 src -j DROP
${pkgs.iptables}/bin/ip6tables -D INPUT -m set --match-set sshguard6 src -j DROP
${pkgs.ipset}/bin/ipset -quiet destroy sshguard4
'' + optionalString (config.networking.firewall.enable && config.networking.enableIPv6) ''
${pkgs.iptables}/bin/ip6tables -D INPUT -m set --match-set sshguard6 src -j DROP
${pkgs.ipset}/bin/ipset -quiet destroy sshguard6
'';

View file

@ -107,6 +107,9 @@ let
in
{
imports = [
(mkRemovedOptionModule [ "services" "tor" "client" "privoxy" "enable" ] ''
Use services.privoxy.enable and services.privoxy.enableTor instead.
'')
(mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "relay" "port" ])
(mkRemovedOptionModule [ "services" "tor" "relay" "isBridge" ] "Use services.tor.relay.role instead.")
(mkRemovedOptionModule [ "services" "tor" "relay" "isExit" ] "Use services.tor.relay.role instead.")
@ -270,23 +273,6 @@ in
description = "List of suffixes to use with automapHostsOnResolve";
};
};
privoxy.enable = mkOption {
type = types.bool;
default = true;
description = ''
Whether to enable and configure the system Privoxy to use Tor's
faster port, suitable for HTTP.
To have anonymity, protocols need to be scrubbed of identifying
information, and this can be accomplished for HTTP by Privoxy.
Privoxy can also be useful for KDE torification. A good setup would be:
setting SOCKS proxy to the default Tor port, providing maximum
circuit isolation where possible; and setting HTTP proxy to Privoxy
to route HTTP traffic over faster, but less isolated port.
'';
};
};
relay = {
@ -784,16 +770,5 @@ in
};
environment.systemPackages = [ cfg.package ];
services.privoxy = mkIf (cfg.client.enable && cfg.client.privoxy.enable) {
enable = true;
extraConfig = ''
forward-socks4a / ${cfg.client.socksListenAddressFaster} .
toggle 1
enable-remote-toggle 0
enable-edit-actions 0
enable-remote-http-toggle 0
'';
};
};
}

View file

@ -1,222 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.frab;
package = pkgs.frab;
databaseConfig = builtins.toJSON { production = cfg.database; };
frabEnv = {
RAILS_ENV = "production";
RACK_ENV = "production";
SECRET_KEY_BASE = cfg.secretKeyBase;
FRAB_HOST = cfg.host;
FRAB_PROTOCOL = cfg.protocol;
FROM_EMAIL = cfg.fromEmail;
RAILS_SERVE_STATIC_FILES = "1";
} // cfg.extraEnvironment;
frab-rake = pkgs.stdenv.mkDerivation {
name = "frab-rake";
buildInputs = [ package.env pkgs.makeWrapper ];
phases = "installPhase fixupPhase";
installPhase = ''
mkdir -p $out/bin
makeWrapper ${package.env}/bin/bundle $out/bin/frab-bundle \
${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") frabEnv)} \
--set PATH '${lib.makeBinPath (with pkgs; [ nodejs file imagemagick ])}:$PATH' \
--set RAKEOPT '-f ${package}/share/frab/Rakefile' \
--run 'cd ${package}/share/frab'
makeWrapper $out/bin/frab-bundle $out/bin/frab-rake \
--add-flags "exec rake"
'';
};
in
{
options = {
services.frab = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Enable the frab service.
'';
};
host = mkOption {
type = types.str;
example = "frab.example.com";
description = ''
Hostname under which this frab instance can be reached.
'';
};
protocol = mkOption {
type = types.str;
default = "https";
example = "http";
description = ''
Either http or https, depending on how your Frab instance
will be exposed to the public.
'';
};
fromEmail = mkOption {
type = types.str;
default = "frab@localhost";
description = ''
Email address used by frab.
'';
};
listenAddress = mkOption {
type = types.str;
default = "localhost";
description = ''
Address or hostname frab should listen on.
'';
};
listenPort = mkOption {
type = types.int;
default = 3000;
description = ''
Port frab should listen on.
'';
};
statePath = mkOption {
type = types.str;
default = "/var/lib/frab";
description = ''
Directory where frab keeps its state.
'';
};
user = mkOption {
type = types.str;
default = "frab";
description = ''
User to run frab.
'';
};
group = mkOption {
type = types.str;
default = "frab";
description = ''
Group to run frab.
'';
};
secretKeyBase = mkOption {
type = types.str;
description = ''
Your secret key is used for verifying the integrity of signed cookies.
If you change this key, all old signed cookies will become invalid!
Make sure the secret is at least 30 characters and all random,
no regular words or you'll be exposed to dictionary attacks.
'';
};
database = mkOption {
type = types.attrs;
default = {
adapter = "sqlite3";
database = "/var/lib/frab/db.sqlite3";
pool = 5;
timeout = 5000;
};
example = {
adapter = "postgresql";
database = "frab";
host = "localhost";
username = "frabuser";
password = "supersecret";
encoding = "utf8";
pool = 5;
};
description = ''
Rails database configuration for Frab as Nix attribute set.
'';
};
extraEnvironment = mkOption {
type = types.attrs;
default = {};
example = {
FRAB_CURRENCY_UNIT = "";
FRAB_CURRENCY_FORMAT = "%n%u";
EXCEPTION_EMAIL = "frab-owner@example.com";
SMTP_ADDRESS = "localhost";
SMTP_PORT = "587";
SMTP_DOMAIN = "localdomain";
SMTP_USER_NAME = "root";
SMTP_PASSWORD = "toor";
SMTP_AUTHENTICATION = "1";
SMTP_NOTLS = "1";
};
description = ''
Additional environment variables to set for frab for further
configuration. See the frab documentation for more information.
'';
};
};
};
config = mkIf cfg.enable {
environment.systemPackages = [ frab-rake ];
users.users.${cfg.user} =
{ group = cfg.group;
home = "${cfg.statePath}";
isSystemUser = true;
};
users.groups.${cfg.group} = { };
systemd.tmpfiles.rules = [
"d '${cfg.statePath}/system/attachments' - ${cfg.user} ${cfg.group} - -"
];
systemd.services.frab = {
after = [ "network.target" "gitlab.service" ];
wantedBy = [ "multi-user.target" ];
environment = frabEnv;
preStart = ''
ln -sf ${pkgs.writeText "frab-database.yml" databaseConfig} /run/frab/database.yml
ln -sf ${cfg.statePath}/system /run/frab/system
if ! test -e "${cfg.statePath}/db-setup-done"; then
${frab-rake}/bin/frab-rake db:setup
touch ${cfg.statePath}/db-setup-done
else
${frab-rake}/bin/frab-rake db:migrate
fi
'';
serviceConfig = {
PrivateTmp = true;
PrivateDevices = true;
Type = "simple";
User = cfg.user;
Group = cfg.group;
TimeoutSec = "300s";
Restart = "on-failure";
RestartSec = "10s";
RuntimeDirectory = "frab";
WorkingDirectory = "${package}/share/frab";
ExecStart = "${frab-rake}/bin/frab-bundle exec rails server " +
"--binding=${cfg.listenAddress} --port=${toString cfg.listenPort}";
};
};
};
}

View file

@ -115,9 +115,9 @@ in {
user = "grocy";
group = "nginx";
# PHP 7.3 is the only version which is supported/tested by upstream:
# https://github.com/grocy/grocy/blob/v2.6.0/README.md#how-to-install
phpPackage = pkgs.php73;
# PHP 7.4 is the only version which is supported/tested by upstream:
# https://github.com/grocy/grocy/blob/v3.0.0/README.md#how-to-install
phpPackage = pkgs.php74;
inherit (cfg.phpfpm) settings;

View file

@ -3,10 +3,14 @@
with lib;
let
cfg = config.services.codimd;
cfg = config.services.hedgedoc;
name = if versionAtLeast config.system.stateVersion "21.03"
then "hedgedoc"
else "codimd";
prettyJSON = conf:
pkgs.runCommandLocal "codimd-config.json" {
pkgs.runCommandLocal "hedgedoc-config.json" {
nativeBuildInputs = [ pkgs.jq ];
} ''
echo '${builtins.toJSON conf}' | jq \
@ -14,22 +18,26 @@ let
'';
in
{
options.services.codimd = {
enable = mkEnableOption "the CodiMD Markdown Editor";
imports = [
(mkRenamedOptionModule [ "services" "codimd" ] [ "services" "hedgedoc" ])
];
options.services.hedgedoc = {
enable = mkEnableOption "the HedgeDoc Markdown Editor";
groups = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Groups to which the codimd user should be added.
Groups to which the user ${name} should be added.
'';
};
workDir = mkOption {
type = types.path;
default = "/var/lib/codimd";
default = "/var/lib/${name}";
description = ''
Working directory for the CodiMD service.
Working directory for the HedgeDoc service.
'';
};
@ -38,17 +46,17 @@ in
domain = mkOption {
type = types.nullOr types.str;
default = null;
example = "codimd.org";
example = "hedgedoc.org";
description = ''
Domain name for the CodiMD instance.
Domain name for the HedgeDoc instance.
'';
};
urlPath = mkOption {
type = types.nullOr types.str;
default = null;
example = "/url/path/to/codimd";
example = "/url/path/to/hedgedoc";
description = ''
Path under which CodiMD is accessible.
Path under which HedgeDoc is accessible.
'';
};
host = mkOption {
@ -69,7 +77,7 @@ in
path = mkOption {
type = types.nullOr types.str;
default = null;
example = "/run/codimd.sock";
example = "/run/hedgedoc.sock";
description = ''
Specify where a UNIX domain socket should be placed.
'';
@ -77,7 +85,7 @@ in
allowOrigin = mkOption {
type = types.listOf types.str;
default = [];
example = [ "localhost" "codimd.org" ];
example = [ "localhost" "hedgedoc.org" ];
description = ''
List of domains to whitelist.
'';
@ -201,7 +209,7 @@ in
'';
description = ''
Specify which database to use.
CodiMD supports mysql, postgres, sqlite and mssql.
HedgeDoc supports mysql, postgres, sqlite and mssql.
See <link xlink:href="https://sequelize.readthedocs.io/en/v3/">
https://sequelize.readthedocs.io/en/v3/</link> for more information.
Note: This option overrides <option>db</option>.
@ -213,12 +221,12 @@ in
example = literalExample ''
{
dialect = "sqlite";
storage = "/var/lib/codimd/db.codimd.sqlite";
storage = "/var/lib/${name}/db.${name}.sqlite";
}
'';
description = ''
Specify the configuration for sequelize.
CodiMD supports mysql, postgres, sqlite and mssql.
HedgeDoc supports mysql, postgres, sqlite and mssql.
See <link xlink:href="https://sequelize.readthedocs.io/en/v3/">
https://sequelize.readthedocs.io/en/v3/</link> for more information.
Note: This option overrides <option>db</option>.
@ -227,7 +235,7 @@ in
sslKeyPath= mkOption {
type = types.nullOr types.str;
default = null;
example = "/var/lib/codimd/codimd.key";
example = "/var/lib/hedgedoc/hedgedoc.key";
description = ''
Path to the SSL key. Needed when <option>useSSL</option> is enabled.
'';
@ -235,7 +243,7 @@ in
sslCertPath = mkOption {
type = types.nullOr types.str;
default = null;
example = "/var/lib/codimd/codimd.crt";
example = "/var/lib/hedgedoc/hedgedoc.crt";
description = ''
Path to the SSL cert. Needed when <option>useSSL</option> is enabled.
'';
@ -243,7 +251,7 @@ in
sslCAPath = mkOption {
type = types.listOf types.str;
default = [];
example = [ "/var/lib/codimd/ca.crt" ];
example = [ "/var/lib/hedgedoc/ca.crt" ];
description = ''
SSL ca chain. Needed when <option>useSSL</option> is enabled.
'';
@ -251,7 +259,7 @@ in
dhParamPath = mkOption {
type = types.nullOr types.str;
default = null;
example = "/var/lib/codimd/dhparam.pem";
example = "/var/lib/hedgedoc/dhparam.pem";
description = ''
Path to the SSL dh params. Needed when <option>useSSL</option> is enabled.
'';
@ -260,10 +268,10 @@ in
type = types.str;
default = "/tmp";
description = ''
Path to the temp directory CodiMD should use.
Path to the temp directory HedgeDoc should use.
Note that <option>serviceConfig.PrivateTmp</option> is enabled for
the CodiMD systemd service by default.
(Non-canonical paths are relative to CodiMD's base directory)
the HedgeDoc systemd service by default.
(Non-canonical paths are relative to HedgeDoc's base directory)
'';
};
defaultNotePath = mkOption {
@ -271,7 +279,7 @@ in
default = "./public/default.md";
description = ''
Path to the default Note file.
(Non-canonical paths are relative to CodiMD's base directory)
(Non-canonical paths are relative to HedgeDoc's base directory)
'';
};
docsPath = mkOption {
@ -279,7 +287,7 @@ in
default = "./public/docs";
description = ''
Path to the docs directory.
(Non-canonical paths are relative to CodiMD's base directory)
(Non-canonical paths are relative to HedgeDoc's base directory)
'';
};
indexPath = mkOption {
@ -287,7 +295,7 @@ in
default = "./public/views/index.ejs";
description = ''
Path to the index template file.
(Non-canonical paths are relative to CodiMD's base directory)
(Non-canonical paths are relative to HedgeDoc's base directory)
'';
};
hackmdPath = mkOption {
@ -295,7 +303,7 @@ in
default = "./public/views/hackmd.ejs";
description = ''
Path to the hackmd template file.
(Non-canonical paths are relative to CodiMD's base directory)
(Non-canonical paths are relative to HedgeDoc's base directory)
'';
};
errorPath = mkOption {
@ -304,7 +312,7 @@ in
defaultText = "./public/views/error.ejs";
description = ''
Path to the error template file.
(Non-canonical paths are relative to CodiMD's base directory)
(Non-canonical paths are relative to HedgeDoc's base directory)
'';
};
prettyPath = mkOption {
@ -313,7 +321,7 @@ in
defaultText = "./public/views/pretty.ejs";
description = ''
Path to the pretty template file.
(Non-canonical paths are relative to CodiMD's base directory)
(Non-canonical paths are relative to HedgeDoc's base directory)
'';
};
slidePath = mkOption {
@ -322,13 +330,13 @@ in
defaultText = "./public/views/slide.hbs";
description = ''
Path to the slide template file.
(Non-canonical paths are relative to CodiMD's base directory)
(Non-canonical paths are relative to HedgeDoc's base directory)
'';
};
uploadsPath = mkOption {
type = types.str;
default = "${cfg.workDir}/uploads";
defaultText = "/var/lib/codimd/uploads";
defaultText = "/var/lib/${name}/uploads";
description = ''
Path under which uploaded files are saved.
'';
@ -766,7 +774,7 @@ in
type = types.str;
default = "";
description = ''
LDAP field which is used as the username on CodiMD.
LDAP field which is used as the username on HedgeDoc.
By default <option>useridField</option> is used.
'';
};
@ -774,7 +782,7 @@ in
type = types.str;
example = "uid";
description = ''
LDAP field which is a unique identifier for users on CodiMD.
LDAP field which is a unique identifier for users on HedgeDoc.
'';
};
tlsca = mkOption {
@ -840,7 +848,7 @@ in
requiredGroups = mkOption {
type = types.listOf types.str;
default = [];
example = [ "Hackmd-users" "Codimd-users" ];
example = [ "Hedgedoc-Users" ];
description = ''
Required group names.
'';
@ -883,7 +891,7 @@ in
environmentFile = mkOption {
type = with types; nullOr path;
default = null;
example = "/var/lib/codimd/codimd.env";
example = "/var/lib/hedgedoc/hedgedoc.env";
description = ''
Environment file as defined in <citerefentry>
<refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum>
@ -894,9 +902,9 @@ in
setting these variables accordingly in the environment file.
<programlisting>
# snippet of CodiMD-related config
services.codimd.configuration.dbURL = "postgres://codimd:\''${DB_PASSWORD}@db-host:5432/codimddb";
services.codimd.configuration.minio.secretKey = "$MINIO_SECRET_KEY";
# snippet of HedgeDoc-related config
services.hedgedoc.configuration.dbURL = "postgres://hedgedoc:\''${DB_PASSWORD}@db-host:5432/hedgedocdb";
services.hedgedoc.configuration.minio.secretKey = "$MINIO_SECRET_KEY";
</programlisting>
<programlisting>
@ -906,15 +914,15 @@ in
</programlisting>
Note that this file needs to be available on the host on which
<literal>CodiMD</literal> is running.
<literal>HedgeDoc</literal> is running.
'';
};
package = mkOption {
type = types.package;
default = pkgs.codimd;
default = pkgs.hedgedoc;
description = ''
Package that provides CodiMD.
Package that provides HedgeDoc.
'';
};
};
@ -924,20 +932,20 @@ in
{ assertion = cfg.configuration.db == {} -> (
cfg.configuration.dbURL != "" && cfg.configuration.dbURL != null
);
message = "Database configuration for CodiMD missing."; }
message = "Database configuration for HedgeDoc missing."; }
];
users.groups.codimd = {};
users.users.codimd = {
description = "CodiMD service user";
group = "codimd";
users.groups.${name} = {};
users.users.${name} = {
description = "HedgeDoc service user";
group = name;
extraGroups = cfg.groups;
home = cfg.workDir;
createHome = true;
isSystemUser = true;
};
systemd.services.codimd = {
description = "CodiMD Service";
systemd.services.hedgedoc = {
description = "HedgeDoc Service";
wantedBy = [ "multi-user.target" ];
after = [ "networking.target" ];
preStart = ''
@ -947,14 +955,14 @@ in
'';
serviceConfig = {
WorkingDirectory = cfg.workDir;
ExecStart = "${cfg.package}/bin/codimd";
ExecStart = "${cfg.package}/bin/hedgedoc";
EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ];
Environment = [
"CMD_CONFIG_FILE=${cfg.workDir}/config.json"
"NODE_ENV=production"
];
Restart = "always";
User = "codimd";
User = name;
PrivateTmp = true;
};
};

View file

@ -39,7 +39,7 @@ let
export NEXTCLOUD_CONFIG_DIR="${cfg.home}/config"
$sudo \
${phpPackage}/bin/php \
occ $*
occ "$@"
'';
inherit (config.system) stateVersion;
@ -391,7 +391,9 @@ in {
$file = "${c.dbpassFile}";
if (!file_exists($file)) {
throw new \RuntimeException(sprintf(
"Cannot start Nextcloud, dbpass file %s set by NixOS doesn't exist!",
"Cannot start Nextcloud, dbpass file %s set by NixOS doesn't seem to "
. "exist! Please make sure that the file exists and has appropriate "
. "permissions for user & group 'nextcloud'!",
$file
));
}

View file

@ -0,0 +1,123 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.plantuml-server;
in
{
options = {
services.plantuml-server = {
enable = mkEnableOption "PlantUML server";
package = mkOption {
type = types.package;
default = pkgs.plantuml-server;
description = "PlantUML server package to use";
};
user = mkOption {
type = types.str;
default = "plantuml";
description = "User which runs PlantUML server.";
};
group = mkOption {
type = types.str;
default = "plantuml";
description = "Group which runs PlantUML server.";
};
home = mkOption {
type = types.str;
default = "/var/lib/plantuml";
description = "Home directory of the PlantUML server instance.";
};
listenHost = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Host to listen on.";
};
listenPort = mkOption {
type = types.int;
default = 8080;
description = "Port to listen on.";
};
plantumlLimitSize = mkOption {
type = types.int;
default = 4096;
description = "Limits image width and height.";
};
graphvizPackage = mkOption {
type = types.package;
default = pkgs.graphviz_2_32;
description = "Package containing the dot executable.";
};
plantumlStats = mkOption {
type = types.bool;
default = false;
description = "Set it to on to enable statistics report (https://plantuml.com/statistics-report).";
};
httpAuthorization = mkOption {
type = types.nullOr types.str;
default = null;
description = "When calling the proxy endpoint, the value of HTTP_AUTHORIZATION will be used to set the HTTP Authorization header.";
};
allowPlantumlInclude = mkOption {
type = types.bool;
default = false;
description = "Enables !include processing which can read files from the server into diagrams. Files are read relative to the current working directory.";
};
};
};
config = mkIf cfg.enable {
users.users.${cfg.user} = {
isSystemUser = true;
group = cfg.group;
home = cfg.home;
createHome = true;
};
users.groups.${cfg.group} = {};
systemd.services.plantuml-server = {
description = "PlantUML server";
wantedBy = [ "multi-user.target" ];
path = [ cfg.home ];
environment = {
PLANTUML_LIMIT_SIZE = builtins.toString cfg.plantumlLimitSize;
GRAPHVIZ_DOT = "${cfg.graphvizPackage}/bin/dot";
PLANTUML_STATS = if cfg.plantumlStats then "on" else "off";
HTTP_AUTHORIZATION = cfg.httpAuthorization;
ALLOW_PLANTUML_INCLUDE = if cfg.allowPlantumlInclude then "true" else "false";
};
script = ''
${pkgs.jre}/bin/java \
-jar ${pkgs.jetty}/start.jar \
--module=deploy,http,jsp \
jetty.home=${pkgs.jetty} \
jetty.base=${cfg.package} \
jetty.http.host=${cfg.listenHost} \
jetty.http.port=${builtins.toString cfg.listenPort}
'';
serviceConfig = {
User = cfg.user;
Group = cfg.group;
PrivateTmp = true;
};
};
};
meta.maintainers = with lib.maintainers; [ truh ];
}

View file

@ -390,13 +390,24 @@ in
};
config = mkOption {
type = types.str;
default = "";
description = "
Verbatim nginx.conf configuration.
This is mutually exclusive with the structured configuration
via virtualHosts and the recommendedXyzSettings configuration
options. See appendConfig for appending to the generated http block.
";
description = ''
Verbatim <filename>nginx.conf</filename> configuration.
This is mutually exclusive to any other config option for
<filename>nginx.conf</filename> except for
<itemizedlist>
<listitem><para><xref linkend="opt-services.nginx.appendConfig" />
</para></listitem>
<listitem><para><xref linkend="opt-services.nginx.httpConfig" />
</para></listitem>
<listitem><para><xref linkend="opt-services.nginx.logError" />
</para></listitem>
</itemizedlist>
If additional verbatim config in addition to other options is needed,
<xref linkend="opt-services.nginx.appendConfig" /> should be used instead.
'';
};
appendConfig = mkOption {

View file

@ -238,6 +238,7 @@ in
kidletime
kimageformats
kinit
kirigami2 # In system profile for SDDM theme. TODO: wrapper.
kio
kjobwidgets
knewstuff

View file

@ -9,12 +9,7 @@ let
cfg = dmcfg.sddm;
xEnv = config.systemd.services.display-manager.environment;
sddm = if config.services.xserver.desktopManager.lxqt.enable then
# TODO: Move lxqt to libsForQt515
pkgs.libsForQt514.sddm
else
pkgs.libsForQt5.sddm
;
sddm = pkgs.libsForQt5.sddm;
xserverWrapper = pkgs.writeScript "xserver-wrapper" ''
#!/bin/sh

View file

@ -39,6 +39,18 @@ in
displayManager.lightdm.enable = lib.mkForce false;
};
systemd.services.display-manager.enable = false;
# Other displayManagers log to /dev/null because they're services and put
# Xorg's stdout in the journal
#
# To send log to Xorg's default log location ($XDG_DATA_HOME/xorg/), we do
# not specify a log file when running X
services.xserver.logFile = mkDefault null;
# Implement xserverArgs via xinit's system-wide xserverrc
environment.etc."X11/xinit/xserverrc".source = pkgs.writeShellScript "xserverrc" ''
exec ${pkgs.xorg.xorgserver}/bin/X ${toString config.services.xserver.displayManager.xserverArgs} "$@"
'';
environment.systemPackages = with pkgs; [ xorg.xinit ];
};

View file

@ -518,6 +518,19 @@ in
'';
};
logFile = mkOption {
type = types.nullOr types.str;
default = "/dev/null";
example = "/var/log/Xorg.0.log";
description = ''
Controls the file Xorg logs to.
The default of <literal>/dev/null</literal> is set so that systemd services (like <literal>displayManagers</literal>) only log to the journal and don't create their own log files.
Setting this to <literal>null</literal> will not pass the <literal>-logfile</literal> argument to Xorg which allows it to log to its default logfile locations instead (see <literal>man Xorg</literal>). You probably only want this behaviour when running Xorg manually (e.g. via <literal>startx</literal>).
'';
};
verbose = mkOption {
type = types.nullOr types.int;
default = 3;
@ -692,11 +705,10 @@ in
services.xserver.displayManager.xserverArgs =
[ "-config ${configFile}"
"-xkbdir" "${cfg.xkbDir}"
# Log at the default verbosity level to stderr rather than /var/log/X.*.log.
"-logfile" "/dev/null"
] ++ optional (cfg.display != null) ":${toString cfg.display}"
++ optional (cfg.tty != null) "vt${toString cfg.tty}"
++ optional (cfg.dpi != null) "-dpi ${toString cfg.dpi}"
++ optional (cfg.logFile != null) "-logfile ${toString cfg.logFile}"
++ optional (cfg.verbose != null) "-verbose ${toString cfg.verbose}"
++ optional (!cfg.enableTCP) "-nolisten tcp"
++ optional (cfg.autoRepeatDelay != null) "-ardelay ${toString cfg.autoRepeatDelay}"

View file

@ -1,4 +1,4 @@
{ config, lib, ... }:
{ config, pkgs, lib, ... }:
with lib;
let
@ -150,6 +150,9 @@ in
wantedBy = [ "multi-user.target" ];
aliases = [ "dbus-org.freedesktop.resolve1.service" ];
restartTriggers = [ config.environment.etc."systemd/resolved.conf".source ];
# Upstream bug: https://github.com/systemd/systemd/issues/18078
# systemd-resolved without libidn2 is broken
environment.LD_LIBRARY_PATH = "${lib.getLib pkgs.libidn2}/lib";
};
environment.etc = {

View file

@ -308,7 +308,7 @@ let
# the initial RAM disk.
initialRamdisk = pkgs.makeInitrd {
name = "initrd-${kernel-name}";
inherit (config.boot.initrd) compressor prepend;
inherit (config.boot.initrd) compressor compressorArgs prepend;
contents =
[ { object = bootStage1;
@ -334,7 +334,9 @@ let
# Script to add secret files to the initrd at bootloader update time
initialRamdiskSecretAppender =
pkgs.writeScriptBin "append-initrd-secrets"
let
compressorExe = initialRamdisk.compressorExecutableFunction pkgs;
in pkgs.writeScriptBin "append-initrd-secrets"
''
#!${pkgs.bash}/bin/bash -e
function usage {
@ -376,7 +378,7 @@ let
}
(cd "$tmp" && find . -print0 | sort -z | cpio -o -H newc -R +0:+0 --reproducible --null) | \
${config.boot.initrd.compressor} >> "$1"
${compressorExe} ${lib.escapeShellArgs initialRamdisk.compressorArgs} >> "$1"
'';
in
@ -511,13 +513,28 @@ in
};
boot.initrd.compressor = mkOption {
internal = true;
default = "gzip -9n";
type = types.str;
description = "The compressor to use on the initrd image.";
default = "gzip";
type = types.unspecified; # We don't have a function type...
description = ''
The compressor to use on the initrd image. May be any of:
<itemizedlist>
<listitem><para>The name of one of the predefined compressors, see <filename>pkgs/build-support/kernel/initrd-compressor-meta.nix</filename> for the definitions.</para></listitem>
<listitem><para>A function which, given the nixpkgs package set, returns the path to a compressor tool, e.g. <literal>pkgs: "''${pkgs.pigz}/bin/pigz"</literal></para></listitem>
<listitem><para>(not recommended, because it does not work when cross-compiling) the full path to a compressor tool, e.g. <literal>"''${pkgs.pigz}/bin/pigz"</literal></para></listitem>
</itemizedlist>
The given program should read data from stdin and write it to stdout compressed.
'';
example = "xz";
};
boot.initrd.compressorArgs = mkOption {
default = null;
type = types.nullOr (types.listOf types.str);
description = "Arguments to pass to the compressor for the initrd image, or null to use the compressor's defaults.";
};
boot.initrd.secrets = mkOption
{ default = {};
type = types.attrsOf (types.nullOr types.path);

View file

@ -93,7 +93,17 @@ in
(if i.useDHCP != null then i.useDHCP else false));
address = forEach (interfaceIps i)
(ip: "${ip.address}/${toString ip.prefixLength}");
networkConfig.IPv6PrivacyExtensions = "kernel";
# IPv6PrivacyExtensions=kernel seems to be broken with networkd.
# Instead of using IPv6PrivacyExtensions=kernel, configure it according to the value of
# `tempAddress`:
networkConfig.IPv6PrivacyExtensions = {
# generate temporary addresses and use them by default
"default" = true;
# generate temporary addresses but keep using the standard EUI-64 ones by default
"enabled" = "prefer-public";
# completely disable temporary addresses
"disabled" = false;
}.${i.tempAddress};
linkConfig = optionalAttrs (i.macAddress != null) {
MACAddress = i.macAddress;
} // optionalAttrs (i.mtu != null) {

View file

@ -145,6 +145,7 @@ in rec {
(onFullSupported "nixos.tests.printing")
(onFullSupported "nixos.tests.proxy")
(onFullSupported "nixos.tests.sddm.default")
(onFullSupported "nixos.tests.shadow")
(onFullSupported "nixos.tests.simple")
(onFullSupported "nixos.tests.switchTest")
(onFullSupported "nixos.tests.udisks2")

View file

@ -49,7 +49,10 @@ in
cadvisor = handleTestOn ["x86_64-linux"] ./cadvisor.nix {};
cage = handleTest ./cage.nix {};
cagebreak = handleTest ./cagebreak.nix {};
cassandra = handleTest ./cassandra.nix {};
cassandra_2_1 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_2_1; };
cassandra_2_2 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_2_2; };
cassandra_3_0 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_3_0; };
cassandra_3_11 = handleTest ./cassandra.nix { testPackage = pkgs.cassandra_3_11; };
ceph-multi-node = handleTestOn ["x86_64-linux"] ./ceph-multi-node.nix {};
ceph-single-node = handleTestOn ["x86_64-linux"] ./ceph-single-node.nix {};
certmgr = handleTest ./certmgr.nix {};
@ -60,7 +63,6 @@ in
clickhouse = handleTest ./clickhouse.nix {};
cloud-init = handleTest ./cloud-init.nix {};
cockroachdb = handleTestOn ["x86_64-linux"] ./cockroachdb.nix {};
codimd = handleTest ./codimd.nix {};
consul = handleTest ./consul.nix {};
containers-bridge = handleTest ./containers-bridge.nix {};
containers-custom-pkgs.nix = handleTest ./containers-custom-pkgs.nix {};
@ -88,6 +90,7 @@ in
docker-edge = handleTestOn ["x86_64-linux"] ./docker-edge.nix {};
docker-registry = handleTest ./docker-registry.nix {};
docker-tools = handleTestOn ["x86_64-linux"] ./docker-tools.nix {};
docker-tools-cross = handleTestOn ["x86_64-linux" "aarch64-linux"] ./docker-tools-cross.nix {};
docker-tools-overlay = handleTestOn ["x86_64-linux"] ./docker-tools-overlay.nix {};
documize = handleTest ./documize.nix {};
dokuwiki = handleTest ./dokuwiki.nix {};
@ -143,6 +146,7 @@ in
handbrake = handleTestOn ["x86_64-linux"] ./handbrake.nix {};
haproxy = handleTest ./haproxy.nix {};
hardened = handleTest ./hardened.nix {};
hedgedoc = handleTest ./hedgedoc.nix {};
installed-tests = pkgs.recurseIntoAttrs (handleTest ./installed-tests {});
oci-containers = handleTestOn ["x86_64-linux"] ./oci-containers.nix {};
# 9pnet_virtio used to mount /nix partition doesn't support
@ -164,6 +168,7 @@ in
initrd-network-openvpn = handleTest ./initrd-network-openvpn {};
initrd-network-ssh = handleTest ./initrd-network-ssh {};
initrdNetwork = handleTest ./initrd-network.nix {};
initrd-secrets = handleTest ./initrd-secrets.nix {};
installer = handleTest ./installer.nix {};
iodine = handleTest ./iodine.nix {};
ipfs = handleTest ./ipfs.nix {};
@ -195,6 +200,7 @@ in
lidarr = handleTest ./lidarr.nix {};
lightdm = handleTest ./lightdm.nix {};
limesurvey = handleTest ./limesurvey.nix {};
locate = handleTest ./locate.nix {};
login = handleTest ./login.nix {};
loki = handleTest ./loki.nix {};
lsd = handleTest ./lsd.nix {};
@ -205,6 +211,7 @@ in
magic-wormhole-mailbox-server = handleTest ./magic-wormhole-mailbox-server.nix {};
magnetico = handleTest ./magnetico.nix {};
mailcatcher = handleTest ./mailcatcher.nix {};
mailhog = handleTest ./mailhog.nix {};
mariadb-galera-mariabackup = handleTest ./mysql/mariadb-galera-mariabackup.nix {};
mariadb-galera-rsync = handleTest ./mysql/mariadb-galera-rsync.nix {};
matomo = handleTest ./matomo.nix {};
@ -273,6 +280,7 @@ in
openssh = handleTest ./openssh.nix {};
openstack-image-metadata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).metadata or {};
openstack-image-userdata = (handleTestOn ["x86_64-linux"] ./openstack-image.nix {}).userdata or {};
image-contents = handleTest ./image-contents.nix {};
orangefs = handleTest ./orangefs.nix {};
os-prober = handleTestOn ["x86_64-linux"] ./os-prober.nix {};
osrm-backend = handleTest ./osrm-backend.nix {};
@ -316,6 +324,7 @@ in
redis = handleTest ./redis.nix {};
redmine = handleTest ./redmine.nix {};
restic = handleTest ./restic.nix {};
ripgrep = handleTest ./ripgrep.nix {};
robustirc-bridge = handleTest ./robustirc-bridge.nix {};
roundcube = handleTest ./roundcube.nix {};
rspamd = handleTest ./rspamd.nix {};
@ -331,6 +340,7 @@ in
scala = handleTest ./scala.nix {};
sddm = handleTest ./sddm.nix {};
service-runner = handleTest ./service-runner.nix {};
shadow = handleTest ./shadow.nix {};
shadowsocks = handleTest ./shadowsocks {};
shattered-pixel-dungeon = handleTest ./shattered-pixel-dungeon.nix {};
shiori = handleTest ./shiori.nix {};
@ -371,6 +381,7 @@ in
telegraf = handleTest ./telegraf.nix {};
tiddlywiki = handleTest ./tiddlywiki.nix {};
timezone = handleTest ./timezone.nix {};
tinc = handleTest ./tinc {};
tinydns = handleTest ./tinydns.nix {};
tor = handleTest ./tor.nix {};
# traefik test relies on docker-containers
@ -404,6 +415,7 @@ in
xterm = handleTest ./xterm.nix {};
yabar = handleTest ./yabar.nix {};
yggdrasil = handleTest ./yggdrasil.nix {};
yq = handleTest ./yq.nix {};
zfs = handleTest ./zfs.nix {};
zigbee2mqtt = handleTest ./zigbee2mqtt.nix {};
zoneminder = handleTest ./zoneminder.nix {};

View file

@ -1,7 +1,5 @@
import ./make-test-python.nix ({ pkgs, lib, ... }:
import ./make-test-python.nix ({ pkgs, lib, testPackage ? pkgs.cassandra, ... }:
let
# Change this to test a different version of Cassandra:
testPackage = pkgs.cassandra;
clusterName = "NixOS Automated-Test Cluster";
testRemoteAuth = lib.versionAtLeast testPackage.version "3.11";
@ -47,7 +45,7 @@ let
};
in
{
name = "cassandra";
name = "cassandra-${testPackage.version}";
meta = {
maintainers = with lib.maintainers; [ johnazoidberg ];
};
@ -128,4 +126,8 @@ in
"nodetool status -p ${jmxPortStr} --resolve-ip | egrep '^UN[[:space:]]+cass2'"
)
'';
passthru = {
inherit testPackage;
};
})

View file

@ -1,60 +0,0 @@
import ./make-test-python.nix ({ pkgs, lib, ... }:
{
name = "codimd";
meta = with lib.maintainers; {
maintainers = [ willibutz ];
};
nodes = {
codimdSqlite = { ... }: {
services = {
codimd = {
enable = true;
configuration.dbURL = "sqlite:///var/lib/codimd/codimd.db";
};
};
};
codimdPostgres = { ... }: {
systemd.services.codimd.after = [ "postgresql.service" ];
services = {
codimd = {
enable = true;
configuration.dbURL = "postgres://codimd:\${DB_PASSWORD}@localhost:5432/codimddb";
/*
* Do not use pkgs.writeText for secrets as
* they will end up in the world-readable Nix store.
*/
environmentFile = pkgs.writeText "codimd-env" ''
DB_PASSWORD=snakeoilpassword
'';
};
postgresql = {
enable = true;
initialScript = pkgs.writeText "pg-init-script.sql" ''
CREATE ROLE codimd LOGIN PASSWORD 'snakeoilpassword';
CREATE DATABASE codimddb OWNER codimd;
'';
};
};
};
};
testScript = ''
start_all()
with subtest("CodiMD sqlite"):
codimdSqlite.wait_for_unit("codimd.service")
codimdSqlite.wait_for_open_port(3000)
codimdSqlite.wait_until_succeeds("curl -sSf http://localhost:3000/new")
with subtest("CodiMD postgres"):
codimdPostgres.wait_for_unit("postgresql.service")
codimdPostgres.wait_for_unit("codimd.service")
codimdPostgres.wait_for_open_port(5432)
codimdPostgres.wait_for_open_port(3000)
codimdPostgres.wait_until_succeeds("curl -sSf http://localhost:3000/new")
'';
})

View file

@ -0,0 +1,76 @@
# Not everyone has a suitable remote builder set up, so the cross-compilation
# tests that _include_ running the result are separate. That way, most people
# can run the majority of the test suite without the extra setup.
import ./make-test-python.nix ({ pkgs, ... }:
let
remoteSystem =
if pkgs.system == "aarch64-linux"
then "x86_64-linux"
else "aarch64-linux";
remoteCrossPkgs = import ../.. /*nixpkgs*/ {
# NOTE: This is the machine that runs the build - local from the
# 'perspective' of the build script.
localSystem = remoteSystem;
# NOTE: Since this file can't control where the test will be _run_ we don't
# cross-compile _to_ a different system but _from_ a different system
crossSystem = pkgs.system;
};
hello1 = remoteCrossPkgs.dockerTools.buildImage {
name = "hello1";
tag = "latest";
contents = remoteCrossPkgs.hello;
};
hello2 = remoteCrossPkgs.dockerTools.buildLayeredImage {
name = "hello2";
tag = "latest";
contents = remoteCrossPkgs.hello;
};
in {
name = "docker-tools";
meta = with pkgs.stdenv.lib.maintainers; {
maintainers = [ roberth ];
};
nodes = {
docker = { ... }: {
virtualisation = {
diskSize = 2048;
docker.enable = true;
};
};
};
testScript = ''
docker.wait_for_unit("sockets.target")
with subtest("Ensure cross compiled buildImage image can run."):
docker.succeed(
"docker load --input='${hello1}'"
)
assert "Hello, world!" in docker.succeed(
"docker run --rm ${hello1.imageName} hello",
)
docker.succeed(
"docker rmi ${hello1.imageName}",
)
with subtest("Ensure cross compiled buildLayeredImage image can run."):
docker.succeed(
"docker load --input='${hello2}'"
)
assert "Hello, world!" in docker.succeed(
"docker run --rm ${hello2.imageName} hello",
)
docker.succeed(
"docker rmi ${hello2.imageName}",
)
'';
})

View file

@ -245,7 +245,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
"docker inspect ${pkgs.dockerTools.examples.cross.imageName} "
+ "| ${pkgs.jq}/bin/jq -r .[].Architecture"
).strip()
== "${if pkgs.system == "aarch64-linux" then "amd64" else "arm64v8"}"
== "${if pkgs.system == "aarch64-linux" then "amd64" else "arm64"}"
)
'';
})

View file

@ -0,0 +1,60 @@
import ./make-test-python.nix ({ pkgs, lib, ... }:
{
name = "hedgedoc";
meta = with lib.maintainers; {
maintainers = [ willibutz ];
};
nodes = {
hedgedocSqlite = { ... }: {
services = {
hedgedoc = {
enable = true;
configuration.dbURL = "sqlite:///var/lib/hedgedoc/hedgedoc.db";
};
};
};
hedgedocPostgres = { ... }: {
systemd.services.hedgedoc.after = [ "postgresql.service" ];
services = {
hedgedoc = {
enable = true;
configuration.dbURL = "postgres://hedgedoc:\${DB_PASSWORD}@localhost:5432/hedgedocdb";
/*
* Do not use pkgs.writeText for secrets as
* they will end up in the world-readable Nix store.
*/
environmentFile = pkgs.writeText "hedgedoc-env" ''
DB_PASSWORD=snakeoilpassword
'';
};
postgresql = {
enable = true;
initialScript = pkgs.writeText "pg-init-script.sql" ''
CREATE ROLE hedgedoc LOGIN PASSWORD 'snakeoilpassword';
CREATE DATABASE hedgedocdb OWNER hedgedoc;
'';
};
};
};
};
testScript = ''
start_all()
with subtest("HedgeDoc sqlite"):
hedgedocSqlite.wait_for_unit("hedgedoc.service")
hedgedocSqlite.wait_for_open_port(3000)
hedgedocSqlite.wait_until_succeeds("curl -sSf http://localhost:3000/new")
with subtest("HedgeDoc postgres"):
hedgedocPostgres.wait_for_unit("postgresql.service")
hedgedocPostgres.wait_for_unit("hedgedoc.service")
hedgedocPostgres.wait_for_open_port(5432)
hedgedocPostgres.wait_for_open_port(3000)
hedgedocPostgres.wait_until_succeeds("curl -sSf http://localhost:3000/new")
'';
})

View file

@ -0,0 +1,51 @@
# Tests the contents attribute of nixos/lib/make-disk-image.nix
# including its user, group, and mode attributes.
{ system ? builtins.currentSystem,
config ? {},
pkgs ? import ../.. { inherit system config; }
}:
with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
with import common/ec2.nix { inherit makeTest pkgs; };
let
config = (import ../lib/eval-config.nix {
inherit system;
modules = [
../modules/testing/test-instrumentation.nix
../modules/profiles/qemu-guest.nix
{
fileSystems."/".device = "/dev/disk/by-label/nixos";
boot.loader.grub.device = "/dev/vda";
boot.loader.timeout = 0;
}
];
}).config;
image = (import ../lib/make-disk-image.nix {
inherit pkgs config;
lib = pkgs.lib;
format = "qcow2";
contents = [{
source = pkgs.writeText "testFile" "contents";
target = "/testFile";
user = "1234";
group = "5678";
mode = "755";
}];
}) + "/nixos.qcow2";
in makeEc2Test {
name = "image-contents";
inherit image;
userData = null;
script = ''
machine.start()
assert "content" in machine.succeed("cat /testFile")
fileDetails = machine.succeed("ls -l /testFile")
assert "1234" in fileDetails
assert "5678" in fileDetails
assert "rwxr-xr-x" in fileDetails
'';
}

View file

@ -0,0 +1,35 @@
{ system ? builtins.currentSystem
, config ? {}
, pkgs ? import ../.. { inherit system config; }
, lib ? pkgs.lib
, testing ? import ../lib/testing-python.nix { inherit system pkgs; }
}:
let
secretInStore = pkgs.writeText "topsecret" "iamasecret";
testWithCompressor = compressor: testing.makeTest {
name = "initrd-secrets-${compressor}";
meta.maintainers = [ lib.maintainers.lheckemann ];
machine = { ... }: {
virtualisation.useBootLoader = true;
boot.initrd.secrets."/test" = secretInStore;
boot.initrd.postMountCommands = ''
cp /test /mnt-root/secret-from-initramfs
'';
boot.initrd.compressor = compressor;
# zstd compression is only supported from 5.9 onwards. Remove when 5.10 becomes default.
boot.kernelPackages = pkgs.linuxPackages_latest;
};
testScript = ''
start_all()
machine.wait_for_unit("multi-user.target")
machine.succeed(
"cmp ${secretInStore} /secret-from-initramfs"
)
'';
};
in lib.flip lib.genAttrs testWithCompressor [
"cat" "gzip" "bzip2" "xz" "lzma" "lzop" "pigz" "pixz" "zstd"
]

View file

@ -80,15 +80,6 @@ let
}) { inherit system; });
in with pkgs; {
kafka_0_9 = makeKafkaTest "kafka_0_9" apacheKafka_0_9;
kafka_0_10 = makeKafkaTest "kafka_0_10" apacheKafka_0_10;
kafka_0_11 = makeKafkaTest "kafka_0_11" apacheKafka_0_11;
kafka_1_0 = makeKafkaTest "kafka_1_0" apacheKafka_1_0;
kafka_1_1 = makeKafkaTest "kafka_1_1" apacheKafka_1_1;
kafka_2_0 = makeKafkaTest "kafka_2_0" apacheKafka_2_0;
kafka_2_1 = makeKafkaTest "kafka_2_1" apacheKafka_2_1;
kafka_2_2 = makeKafkaTest "kafka_2_2" apacheKafka_2_2;
kafka_2_3 = makeKafkaTest "kafka_2_3" apacheKafka_2_3;
kafka_2_4 = makeKafkaTest "kafka_2_4" apacheKafka_2_4;
kafka_2_5 = makeKafkaTest "kafka_2_5" apacheKafka_2_5;
}

View file

@ -0,0 +1,62 @@
import ./make-test-python.nix ({ lib, pkgs, ... }:
let inherit (import ./ssh-keys.nix pkgs) snakeOilPrivateKey snakeOilPublicKey;
in {
name = "locate";
meta.maintainers = with pkgs.stdenv.lib.maintainers; [ chkno ];
nodes = rec {
a = {
environment.systemPackages = with pkgs; [ sshfs ];
fileSystems = lib.mkVMOverride {
"/ssh" = {
device = "alice@b:/";
fsType = "fuse.sshfs";
options = [
"allow_other"
"IdentityFile=/privkey"
"noauto"
"StrictHostKeyChecking=no"
"UserKnownHostsFile=/dev/null"
];
};
};
services.locate = {
enable = true;
interval = "*:*:0/5";
};
};
b = {
services.openssh.enable = true;
users.users.alice = {
isNormalUser = true;
openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
};
};
};
testScript = ''
start_all()
# Set up sshfs mount
a.succeed(
"(umask 077; cat ${snakeOilPrivateKey} > /privkey)"
)
b.succeed("touch /file-on-b-machine")
b.wait_for_open_port(22)
a.succeed("mkdir /ssh")
a.succeed("mount /ssh")
# Core locatedb functionality
a.succeed("touch /file-on-a-machine-1")
a.wait_for_file("/var/cache/locatedb")
a.wait_until_succeeds("locate file-on-a-machine-1")
# Wait for a second update to make sure we're using a locatedb from a run
# that began after the sshfs mount
a.succeed("touch /file-on-a-machine-2")
a.wait_until_succeeds("locate file-on-a-machine-2")
# We shouldn't be able to see files on the other machine
a.fail("locate file-on-b-machine")
'';
})

View file

@ -6,7 +6,7 @@ import ./make-test-python.nix ({ pkgs, ... }: {
testScript = ''
lsd.succeed('echo "abc" > /tmp/foo')
assert "4 B /tmp/foo" in lsd.succeed('lsd --classic --blocks "size,name" /tmp/foo')
assert "4 B /tmp/foo" in lsd.succeed('lsd --classic --blocks "size,name" -l /tmp/foo')
assert "lsd ${pkgs.lsd.version}" in lsd.succeed("lsd --version")
'';
})

View file

@ -0,0 +1,24 @@
import ./make-test-python.nix ({ lib, ... }: {
name = "mailhog";
meta.maintainers = with lib.maintainers; [ jojosch ];
machine = { pkgs, ... }: {
services.mailhog.enable = true;
environment.systemPackages = with pkgs; [ swaks ];
};
testScript = ''
start_all()
machine.wait_for_unit("mailhog.service")
machine.wait_for_open_port("1025")
machine.wait_for_open_port("8025")
machine.succeed(
'echo "this is the body of the email" | swaks --to root@example.org --body - --server localhost:1025'
)
assert "this is the body of the email" in machine.succeed(
"curl --fail http://localhost:8025/api/v2/messages"
)
'';
})

View file

@ -21,7 +21,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
in ''
client.wait_for_x()
client.execute("su - alice -c minecraft-launcher &")
client.wait_for_text("CONTINUE WITHOUT LOGIN")
client.wait_for_text("Create a new Microsoft account")
client.sleep(10)
client.screenshot("launcher")
'';

View file

@ -27,10 +27,12 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
after = [ "mpd.service" ];
wantedBy = [ "default.target" ];
script = ''
mkdir -p ${musicDirectory} && chown -R ${user}:${group} ${musicDirectory}
cp ${track} ${musicDirectory}
chown ${user}:${group} ${musicDirectory}/$(basename ${track})
'';
serviceConfig = {
User = user;
Group = group;
};
};
mkServer = { mpd, musicService, }:

View file

@ -35,6 +35,9 @@ import ./make-test-python.nix ({ pkgs, ...} :
machine.wait_until_succeeds("pgrep plasmashell")
machine.wait_for_window("^Desktop ")
with subtest("Check that KDED is running"):
machine.succeed("pgrep kded5")
with subtest("Check that logging in has given the user ownership of devices"):
machine.succeed("getfacl -p /dev/snd/timer | grep -q ${user.name}")

View file

@ -444,6 +444,67 @@ let
'';
};
nginxlog = {
exporterConfig = {
enable = true;
group = "nginx";
settings = {
namespaces = [
{
name = "filelogger";
source = {
files = [ "/var/log/nginx/filelogger.access.log" ];
};
}
{
name = "syslogger";
source = {
syslog = {
listen_address = "udp://127.0.0.1:10000";
format = "rfc3164";
tags = ["nginx"];
};
};
}
];
};
};
metricProvider = {
services.nginx = {
enable = true;
httpConfig = ''
server {
listen 80;
server_name filelogger.local;
access_log /var/log/nginx/filelogger.access.log;
}
server {
listen 81;
server_name syslogger.local;
access_log syslog:server=127.0.0.1:10000,tag=nginx,severity=info;
}
'';
};
};
exporterTest = ''
wait_for_unit("nginx.service")
wait_for_unit("prometheus-nginxlog-exporter.service")
wait_for_open_port(9117)
wait_for_open_port(80)
wait_for_open_port(81)
succeed("curl http://localhost")
execute("sleep 1")
succeed(
"curl -sSf http://localhost:9117/metrics | grep 'filelogger_http_response_count_total' | grep -q 1"
)
succeed("curl http://localhost:81")
execute("sleep 1")
succeed(
"curl -sSf http://localhost:9117/metrics | grep 'syslogger_http_response_count_total' | grep -q 1"
)
'';
};
node = {
exporterConfig = {
enable = true;
@ -530,6 +591,21 @@ let
'';
};
py-air-control = {
nodeName = "py_air_control";
exporterConfig = {
enable = true;
deviceHostname = "127.0.0.1";
};
exporterTest = ''
wait_for_unit("prometheus-py-air-control-exporter.service")
wait_for_open_port(9896)
succeed(
"curl -sSf http://localhost:9896/metrics | grep -q 'py_air_control_sampling_error_total'"
)
'';
};
redis = {
exporterConfig = {
enable = true;

View file

@ -36,6 +36,7 @@ in import ./make-test-python.nix {
nodes = {
prometheus = { pkgs, ... }: {
virtualisation.diskSize = 2 * 1024;
virtualisation.memorySize = 2048;
environment.systemPackages = [ pkgs.jq ];
networking.firewall.allowedTCPPorts = [ grpcPort ];
services.prometheus = {
@ -132,6 +133,7 @@ in import ./make-test-python.nix {
store = { pkgs, ... }: {
virtualisation.diskSize = 2 * 1024;
virtualisation.memorySize = 2048;
environment.systemPackages = with pkgs; [ jq thanos ];
services.thanos.store = {
enable = true;

View file

@ -0,0 +1,13 @@
import ./make-test-python.nix ({ pkgs, ... }: {
name = "ripgrep";
meta = with pkgs.stdenv.lib.maintainers; { maintainers = [ nequissimus ]; };
nodes.ripgrep = { pkgs, ... }: { environment.systemPackages = [ pkgs.ripgrep ]; };
testScript = ''
ripgrep.succeed('echo "abc\nbcd\ncde" > /tmp/foo')
assert "bcd" in ripgrep.succeed("rg -N 'bcd' /tmp/foo")
assert "bcd\ncde" in ripgrep.succeed("rg -N 'cd' /tmp/foo")
assert "ripgrep ${pkgs.ripgrep.version}" in ripgrep.succeed("rg --version | head -1")
'';
})

View file

@ -0,0 +1,102 @@
let
password1 = "foobar";
password2 = "helloworld";
password3 = "bazqux";
in import ./make-test-python.nix ({ pkgs, ... }: {
name = "shadow";
meta = with pkgs.stdenv.lib.maintainers; { maintainers = [ nequissimus ]; };
nodes.shadow = { pkgs, ... }: {
environment.systemPackages = [ pkgs.shadow ];
users = {
mutableUsers = true;
users.emma = {
password = password1;
shell = pkgs.bash;
};
users.layla = {
password = password2;
shell = pkgs.shadow;
};
};
};
testScript = ''
shadow.wait_for_unit("multi-user.target")
shadow.wait_until_succeeds("pgrep -f 'agetty.*tty1'")
with subtest("Normal login"):
shadow.send_key("alt-f2")
shadow.wait_until_succeeds(f"[ $(fgconsole) = 2 ]")
shadow.wait_for_unit(f"getty@tty2.service")
shadow.wait_until_succeeds(f"pgrep -f 'agetty.*tty2'")
shadow.wait_until_tty_matches(2, "login: ")
shadow.send_chars("emma\n")
shadow.wait_until_tty_matches(2, "login: emma")
shadow.wait_until_succeeds("pgrep login")
shadow.sleep(2)
shadow.send_chars("${password1}\n")
shadow.send_chars("whoami > /tmp/1\n")
shadow.wait_for_file("/tmp/1")
assert "emma" in shadow.succeed("cat /tmp/1")
with subtest("Change password"):
shadow.send_key("alt-f3")
shadow.wait_until_succeeds(f"[ $(fgconsole) = 3 ]")
shadow.wait_for_unit(f"getty@tty3.service")
shadow.wait_until_succeeds(f"pgrep -f 'agetty.*tty3'")
shadow.wait_until_tty_matches(3, "login: ")
shadow.send_chars("emma\n")
shadow.wait_until_tty_matches(3, "login: emma")
shadow.wait_until_succeeds("pgrep login")
shadow.sleep(2)
shadow.send_chars("${password1}\n")
shadow.send_chars("passwd\n")
shadow.sleep(2)
shadow.send_chars("${password1}\n")
shadow.sleep(2)
shadow.send_chars("${password3}\n")
shadow.sleep(2)
shadow.send_chars("${password3}\n")
shadow.sleep(2)
shadow.send_key("alt-f4")
shadow.wait_until_succeeds(f"[ $(fgconsole) = 4 ]")
shadow.wait_for_unit(f"getty@tty4.service")
shadow.wait_until_succeeds(f"pgrep -f 'agetty.*tty4'")
shadow.wait_until_tty_matches(4, "login: ")
shadow.send_chars("emma\n")
shadow.wait_until_tty_matches(4, "login: emma")
shadow.wait_until_succeeds("pgrep login")
shadow.sleep(2)
shadow.send_chars("${password1}\n")
shadow.wait_until_tty_matches(4, "Login incorrect")
shadow.wait_until_tty_matches(4, "login:")
shadow.send_chars("emma\n")
shadow.wait_until_tty_matches(4, "login: emma")
shadow.wait_until_succeeds("pgrep login")
shadow.sleep(2)
shadow.send_chars("${password3}\n")
shadow.send_chars("whoami > /tmp/2\n")
shadow.wait_for_file("/tmp/2")
assert "emma" in shadow.succeed("cat /tmp/2")
with subtest("Groups"):
assert "foobar" not in shadow.succeed("groups emma")
shadow.succeed("groupadd foobar")
shadow.succeed("usermod -a -G foobar emma")
assert "foobar" in shadow.succeed("groups emma")
with subtest("nologin shell"):
shadow.send_key("alt-f5")
shadow.wait_until_succeeds(f"[ $(fgconsole) = 5 ]")
shadow.wait_for_unit(f"getty@tty5.service")
shadow.wait_until_succeeds(f"pgrep -f 'agetty.*tty5'")
shadow.wait_until_tty_matches(5, "login: ")
shadow.send_chars("layla\n")
shadow.wait_until_tty_matches(5, "login: layla")
shadow.wait_until_succeeds("pgrep login")
shadow.send_chars("${password2}\n")
shadow.wait_until_tty_matches(5, "login:")
'';
})

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