nixos/acme: Update release note, remove redundant requires
Merge remote-tracking branch 'remotes/upstream/master'
This commit is contained in:
commit
75fa8027eb
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
@ -14,7 +14,9 @@
|
|||||||
/lib @edolstra @nbp @infinisil
|
/lib @edolstra @nbp @infinisil
|
||||||
/lib/systems @nbp @ericson2314 @matthewbauer
|
/lib/systems @nbp @ericson2314 @matthewbauer
|
||||||
/lib/generators.nix @edolstra @nbp @Profpatsch
|
/lib/generators.nix @edolstra @nbp @Profpatsch
|
||||||
|
/lib/cli.nix @edolstra @nbp @Profpatsch
|
||||||
/lib/debug.nix @edolstra @nbp @Profpatsch
|
/lib/debug.nix @edolstra @nbp @Profpatsch
|
||||||
|
/lib/asserts.nix @edolstra @nbp @Profpatsch
|
||||||
|
|
||||||
# Nixpkgs Internals
|
# Nixpkgs Internals
|
||||||
/default.nix @nbp
|
/default.nix @nbp
|
||||||
@ -162,7 +164,7 @@
|
|||||||
/pkgs/top-level/emacs-packages.nix @adisbladis
|
/pkgs/top-level/emacs-packages.nix @adisbladis
|
||||||
|
|
||||||
# VimPlugins
|
# VimPlugins
|
||||||
/pkgs/misc/vim-plugins @jonringer
|
/pkgs/misc/vim-plugins @jonringer @softinio
|
||||||
|
|
||||||
# VsCode Extensions
|
# VsCode Extensions
|
||||||
/pkgs/misc/vscode-extensions @jonringer
|
/pkgs/misc/vscode-extensions @jonringer
|
||||||
|
9
.github/CONTRIBUTING.md
vendored
9
.github/CONTRIBUTING.md
vendored
@ -48,6 +48,15 @@ In addition to writing properly formatted commit messages, it's important to inc
|
|||||||
|
|
||||||
For package version upgrades and such a one-line commit message is usually sufficient.
|
For package version upgrades and such a one-line commit message is usually sufficient.
|
||||||
|
|
||||||
|
## Backporting changes
|
||||||
|
|
||||||
|
To [backport a change into a release branch](https://nixos.org/nixpkgs/manual/#submitting-changes-stable-release-branches):
|
||||||
|
|
||||||
|
1. Take note of the commit in which the change was introduced into `master`.
|
||||||
|
2. Check out the target _release branch_, e.g. `release-19.09`. Do not use a _channel branch_ like `nixos-19.09` or `nixpkgs-19.09`.
|
||||||
|
3. Use `git cherry-pick -x <original commit>`.
|
||||||
|
4. Open your backport PR. Make sure to select the release branch (e.g. `release-19.09`) as the target branch of the PR, and link to the PR in which the original change was made to `master`.
|
||||||
|
|
||||||
## Reviewing contributions
|
## Reviewing contributions
|
||||||
|
|
||||||
See the nixpkgs manual for more details on how to [Review contributions](https://nixos.org/nixpkgs/manual/#chap-reviewing-contributions).
|
See the nixpkgs manual for more details on how to [Review contributions](https://nixos.org/nixpkgs/manual/#chap-reviewing-contributions).
|
||||||
|
@ -80,7 +80,7 @@ appimageTools.wrapType2 { # or wrapType1
|
|||||||
<varname>src</varname> specifies the AppImage file to extract.
|
<varname>src</varname> specifies the AppImage file to extract.
|
||||||
</para>
|
</para>
|
||||||
</callout>
|
</callout>
|
||||||
<callout arearefs='ex-appimageTools-wrapping-2'>
|
<callout arearefs='ex-appimageTools-wrapping-3'>
|
||||||
<para>
|
<para>
|
||||||
<varname>extraPkgs</varname> allows you to pass a function to include additional packages inside the FHS environment your AppImage is going to run in. There are a few ways to learn which dependencies an application needs:
|
<varname>extraPkgs</varname> allows you to pass a function to include additional packages inside the FHS environment your AppImage is going to run in. There are a few ways to learn which dependencies an application needs:
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
|
@ -496,8 +496,8 @@ and in this case the `python35` interpreter is automatically used.
|
|||||||
|
|
||||||
### Interpreters
|
### Interpreters
|
||||||
|
|
||||||
Versions 2.7, 3.5, 3.6 and 3.7 of the CPython interpreter are available as
|
Versions 2.7, 3.5, 3.6, 3.7 and 3.8 of the CPython interpreter are available as
|
||||||
respectively `python27`, `python35`, `python36` and `python37`. The aliases
|
respectively `python27`, `python35`, `python36`, `python37` and `python38`. The aliases
|
||||||
`python2` and `python3` correspond to respectively `python27` and
|
`python2` and `python3` correspond to respectively `python27` and
|
||||||
`python37`. The default interpreter, `python`, maps to `python2`. The PyPy
|
`python37`. The default interpreter, `python`, maps to `python2`. The PyPy
|
||||||
interpreters compatible with Python 2.7 and 3 are available as `pypy27` and
|
interpreters compatible with Python 2.7 and 3 are available as `pypy27` and
|
||||||
@ -833,6 +833,7 @@ used in `buildPythonPackage`.
|
|||||||
- `pythonRemoveBinBytecode` to remove bytecode from the `/bin` folder.
|
- `pythonRemoveBinBytecode` to remove bytecode from the `/bin` folder.
|
||||||
- `setuptoolsBuildHook` to build a wheel using `setuptools`.
|
- `setuptoolsBuildHook` to build a wheel using `setuptools`.
|
||||||
- `setuptoolsCheckHook` to run tests with `python setup.py test`.
|
- `setuptoolsCheckHook` to run tests with `python setup.py test`.
|
||||||
|
- `venvShellHook` to source a Python 3 `venv` at the `venvDir` location. A `venv` is created if it does not yet exist.
|
||||||
- `wheelUnpackHook` to move a wheel to the correct folder so it can be installed with the `pipInstallHook`.
|
- `wheelUnpackHook` to move a wheel to the correct folder so it can be installed with the `pipInstallHook`.
|
||||||
|
|
||||||
### Development mode
|
### Development mode
|
||||||
@ -1028,36 +1029,41 @@ If you want to create a Python environment for development, then the recommended
|
|||||||
method is to use `nix-shell`, either with or without the `python.buildEnv`
|
method is to use `nix-shell`, either with or without the `python.buildEnv`
|
||||||
function.
|
function.
|
||||||
|
|
||||||
### How to consume python modules using pip in a virtualenv like I am used to on other Operating Systems ?
|
### How to consume python modules using pip in a virtual environment like I am used to on other Operating Systems?
|
||||||
|
|
||||||
This is an example of a `default.nix` for a `nix-shell`, which allows to consume a `virtualenv` environment,
|
While this approach is not very idiomatic from Nix perspective, it can still be useful when dealing with pre-existing
|
||||||
|
projects or in situations where it's not feasible or desired to write derivations for all required dependencies.
|
||||||
|
|
||||||
|
This is an example of a `default.nix` for a `nix-shell`, which allows to consume a virtual environment created by `venv`,
|
||||||
and install python modules through `pip` the traditional way.
|
and install python modules through `pip` the traditional way.
|
||||||
|
|
||||||
Create this `default.nix` file, together with a `requirements.txt` and simply execute `nix-shell`.
|
Create this `default.nix` file, together with a `requirements.txt` and simply execute `nix-shell`.
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
with import <nixpkgs> {};
|
with import <nixpkgs> { };
|
||||||
|
|
||||||
let
|
let
|
||||||
pythonPackages = python27Packages;
|
pythonPackages = python3Packages;
|
||||||
in
|
in pkgs.mkShell rec {
|
||||||
|
|
||||||
stdenv.mkDerivation {
|
|
||||||
name = "impurePythonEnv";
|
name = "impurePythonEnv";
|
||||||
|
venvDir = "./.venv";
|
||||||
src = null;
|
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
# these packages are required for virtualenv and pip to work:
|
# A python interpreter including the 'venv' module is required to bootstrap
|
||||||
#
|
# the environment.
|
||||||
pythonPackages.virtualenv
|
pythonPackages.python
|
||||||
pythonPackages.pip
|
|
||||||
# the following packages are related to the dependencies of your python
|
# This execute some shell code to initialize a venv in $venvDir before
|
||||||
# project.
|
# dropping into the shell
|
||||||
# In this particular example the python modules listed in the
|
pythonPackages.venvShellHook
|
||||||
# requirements.txt require the following packages to be installed locally
|
|
||||||
# in order to compile any binary extensions they may require.
|
# Those are dependencies that we would like to use from nixpkgs, which will
|
||||||
#
|
# add them to PYTHONPATH and thus make them accessible from within the venv.
|
||||||
|
pythonPackages.numpy
|
||||||
|
pythonPackages.requests
|
||||||
|
|
||||||
|
# In this particular example, in order to compile any binary extensions they may
|
||||||
|
# require, the python modules listed in the hypothetical requirements.txt need
|
||||||
|
# the following packages to be installed locally:
|
||||||
taglib
|
taglib
|
||||||
openssl
|
openssl
|
||||||
git
|
git
|
||||||
@ -1067,11 +1073,54 @@ stdenv.mkDerivation {
|
|||||||
zlib
|
zlib
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Now we can execute any commands within the virtual environment.
|
||||||
|
# This is optional and can be left out to run pip manually.
|
||||||
|
postShellHook = ''
|
||||||
|
pip install -r requirements.txt
|
||||||
|
'';
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In case the supplied venvShellHook is insufficient, or when python 2 support is needed,
|
||||||
|
you can define your own shell hook and adapt to your needs like in the following example:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
with import <nixpkgs> { };
|
||||||
|
|
||||||
|
let
|
||||||
|
venvDir = "./.venv";
|
||||||
|
pythonPackages = python3Packages;
|
||||||
|
in pkgs.mkShell rec {
|
||||||
|
name = "impurePythonEnv";
|
||||||
|
buildInputs = [
|
||||||
|
pythonPackages.python
|
||||||
|
# Needed when using python 2.7
|
||||||
|
# pythonPackages.virtualenv
|
||||||
|
# ...
|
||||||
|
];
|
||||||
|
|
||||||
|
# This is very close to how venvShellHook is implemented, but
|
||||||
|
# adapted to use 'virtualenv'
|
||||||
shellHook = ''
|
shellHook = ''
|
||||||
# set SOURCE_DATE_EPOCH so that we can use python wheels
|
|
||||||
SOURCE_DATE_EPOCH=$(date +%s)
|
SOURCE_DATE_EPOCH=$(date +%s)
|
||||||
virtualenv --python=${pythonPackages.python.interpreter} --no-setuptools venv
|
|
||||||
export PATH=$PWD/venv/bin:$PATH
|
if [ -d "${venvDir}" ]; then
|
||||||
|
echo "Skipping venv creation, '${venvDir}' already exists"
|
||||||
|
else
|
||||||
|
echo "Creating new venv environment in path: '${venvDir}'"
|
||||||
|
# Note that the module venv was only introduced in python 3, so for 2.7
|
||||||
|
# this needs to be replaced with a call to virtualenv
|
||||||
|
${pythonPackages.python.interpreter} -m venv "${venvDir}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Under some circumstances it might be necessary to add your virtual
|
||||||
|
# environment to PYTHONPATH, which you can do here too;
|
||||||
|
# PYTHONPATH=$PWD/${venvDir}/${pythonPackages.python.sitePackages}/:$PYTHONPATH
|
||||||
|
|
||||||
|
source "${venvDir}/bin/activate"
|
||||||
|
|
||||||
|
# As in the previous example, this is optional.
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,6 @@ cargo
|
|||||||
into the `environment.systemPackages` or bring them into
|
into the `environment.systemPackages` or bring them into
|
||||||
scope with `nix-shell -p rustc cargo`.
|
scope with `nix-shell -p rustc cargo`.
|
||||||
|
|
||||||
> If you are using NixOS and you want to use rust without a nix expression you
|
|
||||||
> probably want to add the following in your `configuration.nix` to build
|
|
||||||
> crates with C dependencies.
|
|
||||||
>
|
|
||||||
> environment.systemPackages = [binutils gcc gnumake openssl pkgconfig]
|
|
||||||
|
|
||||||
For daily builds (beta and nightly) use either rustup from
|
For daily builds (beta and nightly) use either rustup from
|
||||||
nixpkgs or use the [Rust nightlies
|
nixpkgs or use the [Rust nightlies
|
||||||
overlay](#using-the-rust-nightlies-overlay).
|
overlay](#using-the-rust-nightlies-overlay).
|
||||||
|
@ -1,9 +1,22 @@
|
|||||||
.docbook .xref img[src^=images\/callouts\/],
|
.docbook .xref img[src^=images\/callouts\/],
|
||||||
.screen img,
|
.screen img,
|
||||||
.programlisting img {
|
.programlisting img,
|
||||||
|
.literallayout img,
|
||||||
|
.synopsis img {
|
||||||
width: 1em;
|
width: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calloutlist img {
|
.calloutlist img {
|
||||||
width: 1.5em;
|
width: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prompt,
|
||||||
|
.screen img,
|
||||||
|
.programlisting img,
|
||||||
|
.literallayout img,
|
||||||
|
.synopsis img {
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
@ -60,7 +60,7 @@ rec {
|
|||||||
[ { name = head attrPath; value = setAttrByPath (tail attrPath) value; } ];
|
[ { name = head attrPath; value = setAttrByPath (tail attrPath) value; } ];
|
||||||
|
|
||||||
|
|
||||||
/* Like `getAttrPath' without a default value. If it doesn't find the
|
/* Like `attrByPath' without a default value. If it doesn't find the
|
||||||
path it will throw.
|
path it will throw.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
83
lib/cli.nix
Normal file
83
lib/cli.nix
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
{ lib }:
|
||||||
|
|
||||||
|
rec {
|
||||||
|
/* Automatically convert an attribute set to command-line options.
|
||||||
|
|
||||||
|
This helps protect against malformed command lines and also to reduce
|
||||||
|
boilerplate related to command-line construction for simple use cases.
|
||||||
|
|
||||||
|
`toGNUCommandLine` returns a list of nix strings.
|
||||||
|
`toGNUCommandLineShell` returns an escaped shell string.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
cli.toGNUCommandLine {} {
|
||||||
|
data = builtins.toJSON { id = 0; };
|
||||||
|
X = "PUT";
|
||||||
|
retry = 3;
|
||||||
|
retry-delay = null;
|
||||||
|
url = [ "https://example.com/foo" "https://example.com/bar" ];
|
||||||
|
silent = false;
|
||||||
|
verbose = true;
|
||||||
|
}
|
||||||
|
=> [
|
||||||
|
"-X" "PUT"
|
||||||
|
"--data" "{\"id\":0}"
|
||||||
|
"--retry" "3"
|
||||||
|
"--url" "https://example.com/foo"
|
||||||
|
"--url" "https://example.com/bar"
|
||||||
|
"--verbose"
|
||||||
|
]
|
||||||
|
|
||||||
|
cli.toGNUCommandLineShell {} {
|
||||||
|
data = builtins.toJSON { id = 0; };
|
||||||
|
X = "PUT";
|
||||||
|
retry = 3;
|
||||||
|
retry-delay = null;
|
||||||
|
url = [ "https://example.com/foo" "https://example.com/bar" ];
|
||||||
|
silent = false;
|
||||||
|
verbose = true;
|
||||||
|
}
|
||||||
|
=> "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
|
||||||
|
*/
|
||||||
|
toGNUCommandLineShell =
|
||||||
|
options: attrs: lib.escapeShellArgs (toGNUCommandLine options attrs);
|
||||||
|
|
||||||
|
toGNUCommandLine = {
|
||||||
|
# how to string-format the option name;
|
||||||
|
# by default one character is a short option (`-`),
|
||||||
|
# more than one characters a long option (`--`).
|
||||||
|
mkOptionName ?
|
||||||
|
k: if builtins.stringLength k == 1
|
||||||
|
then "-${k}"
|
||||||
|
else "--${k}",
|
||||||
|
|
||||||
|
# how to format a boolean value to a command list;
|
||||||
|
# by default it’s a flag option
|
||||||
|
# (only the option name if true, left out completely if false).
|
||||||
|
mkBool ? k: v: lib.optional v (mkOptionName k),
|
||||||
|
|
||||||
|
# how to format a list value to a command list;
|
||||||
|
# by default the option name is repeated for each value
|
||||||
|
# and `mkOption` is applied to the values themselves.
|
||||||
|
mkList ? k: v: lib.concatMap (mkOption k) v,
|
||||||
|
|
||||||
|
# how to format any remaining value to a command list;
|
||||||
|
# on the toplevel, booleans and lists are handled by `mkBool` and `mkList`,
|
||||||
|
# though they can still appear as values of a list.
|
||||||
|
# By default, everything is printed verbatim and complex types
|
||||||
|
# are forbidden (lists, attrsets, functions). `null` values are omitted.
|
||||||
|
mkOption ?
|
||||||
|
k: v: if v == null
|
||||||
|
then []
|
||||||
|
else [ (mkOptionName k) (lib.generators.mkValueStringDefault {} v) ]
|
||||||
|
}:
|
||||||
|
options:
|
||||||
|
let
|
||||||
|
render = k: v:
|
||||||
|
if builtins.isBool v then mkBool k v
|
||||||
|
else if builtins.isList v then mkList k v
|
||||||
|
else mkOption k v;
|
||||||
|
|
||||||
|
in
|
||||||
|
builtins.concatLists (lib.mapAttrsToList render options);
|
||||||
|
}
|
@ -37,10 +37,13 @@ let
|
|||||||
licenses = callLibs ./licenses.nix;
|
licenses = callLibs ./licenses.nix;
|
||||||
systems = callLibs ./systems;
|
systems = callLibs ./systems;
|
||||||
|
|
||||||
|
# serialization
|
||||||
|
cli = callLibs ./cli.nix;
|
||||||
|
generators = callLibs ./generators.nix;
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
asserts = callLibs ./asserts.nix;
|
asserts = callLibs ./asserts.nix;
|
||||||
debug = callLibs ./debug.nix;
|
debug = callLibs ./debug.nix;
|
||||||
generators = callLibs ./generators.nix;
|
|
||||||
misc = callLibs ./deprecated.nix;
|
misc = callLibs ./deprecated.nix;
|
||||||
|
|
||||||
# domain-specific
|
# domain-specific
|
||||||
@ -100,7 +103,7 @@ let
|
|||||||
inherit (sources) pathType pathIsDirectory cleanSourceFilter
|
inherit (sources) pathType pathIsDirectory cleanSourceFilter
|
||||||
cleanSource sourceByRegex sourceFilesBySuffices
|
cleanSource sourceByRegex sourceFilesBySuffices
|
||||||
commitIdFromGitRepo cleanSourceWith pathHasContext
|
commitIdFromGitRepo cleanSourceWith pathHasContext
|
||||||
canCleanSource;
|
canCleanSource pathIsRegularFile pathIsGitRepo;
|
||||||
inherit (modules) evalModules unifyModuleSyntax
|
inherit (modules) evalModules unifyModuleSyntax
|
||||||
applyIfFunction mergeModules
|
applyIfFunction mergeModules
|
||||||
mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions
|
mergeModules' mergeOptionDecls evalOptionValue mergeDefinitions
|
||||||
|
@ -46,7 +46,10 @@ rec {
|
|||||||
else if isList v then err "lists" v
|
else if isList v then err "lists" v
|
||||||
# same as for lists, might want to replace
|
# same as for lists, might want to replace
|
||||||
else if isAttrs v then err "attrsets" v
|
else if isAttrs v then err "attrsets" v
|
||||||
|
# functions can’t be printed of course
|
||||||
else if isFunction v then err "functions" v
|
else if isFunction v then err "functions" v
|
||||||
|
# let’s not talk about floats. There is no sensible `toString` for them.
|
||||||
|
else if isFloat v then err "floats" v
|
||||||
else err "this value is" (toString v);
|
else err "this value is" (toString v);
|
||||||
|
|
||||||
|
|
||||||
|
@ -536,11 +536,6 @@ lib.mapAttrs (n: v: v // { shortName = n; }) {
|
|||||||
fullName = "University of Illinois/NCSA Open Source License";
|
fullName = "University of Illinois/NCSA Open Source License";
|
||||||
};
|
};
|
||||||
|
|
||||||
notion_lgpl = {
|
|
||||||
url = "https://raw.githubusercontent.com/raboof/notion/master/LICENSE";
|
|
||||||
fullName = "Notion modified LGPL";
|
|
||||||
};
|
|
||||||
|
|
||||||
nposl3 = spdx {
|
nposl3 = spdx {
|
||||||
spdxId = "NPOSL-3.0";
|
spdxId = "NPOSL-3.0";
|
||||||
fullName = "Non-Profit Open Software License 3.0";
|
fullName = "Non-Profit Open Software License 3.0";
|
||||||
|
@ -764,12 +764,15 @@ rec {
|
|||||||
fromOpt = getAttrFromPath from options;
|
fromOpt = getAttrFromPath from options;
|
||||||
toOf = attrByPath to
|
toOf = attrByPath to
|
||||||
(abort "Renaming error: option `${showOption to}' does not exist.");
|
(abort "Renaming error: option `${showOption to}' does not exist.");
|
||||||
|
toType = let opt = attrByPath to {} options; in opt.type or null;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options = setAttrByPath from (mkOption {
|
options = setAttrByPath from (mkOption {
|
||||||
inherit visible;
|
inherit visible;
|
||||||
description = "Alias of <option>${showOption to}</option>.";
|
description = "Alias of <option>${showOption to}</option>.";
|
||||||
apply = x: use (toOf config);
|
apply = x: use (toOf config);
|
||||||
|
} // optionalAttrs (toType != null) {
|
||||||
|
type = toType;
|
||||||
});
|
});
|
||||||
config = mkMerge [
|
config = mkMerge [
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,9 @@ rec {
|
|||||||
# Returns true if the path exists and is a directory, false otherwise
|
# Returns true if the path exists and is a directory, false otherwise
|
||||||
pathIsDirectory = p: if builtins.pathExists p then (pathType p) == "directory" else false;
|
pathIsDirectory = p: if builtins.pathExists p then (pathType p) == "directory" else false;
|
||||||
|
|
||||||
|
# Returns true if the path exists and is a regular file, false otherwise
|
||||||
|
pathIsRegularFile = p: if builtins.pathExists p then (pathType p) == "regular" else false;
|
||||||
|
|
||||||
# Bring in a path as a source, filtering out all Subversion and CVS
|
# Bring in a path as a source, filtering out all Subversion and CVS
|
||||||
# directories, as well as backup files (*~).
|
# directories, as well as backup files (*~).
|
||||||
cleanSourceFilter = name: type: let baseName = baseNameOf (toString name); in ! (
|
cleanSourceFilter = name: type: let baseName = baseNameOf (toString name); in ! (
|
||||||
@ -102,6 +105,7 @@ rec {
|
|||||||
in type == "directory" || lib.any (ext: lib.hasSuffix ext base) exts;
|
in type == "directory" || lib.any (ext: lib.hasSuffix ext base) exts;
|
||||||
in cleanSourceWith { inherit filter; src = path; };
|
in cleanSourceWith { inherit filter; src = path; };
|
||||||
|
|
||||||
|
pathIsGitRepo = path: (builtins.tryEval (commitIdFromGitRepo path)).success;
|
||||||
|
|
||||||
# Get the commit id of a git repo
|
# Get the commit id of a git repo
|
||||||
# Example: commitIdFromGitRepo <nixpkgs/.git>
|
# Example: commitIdFromGitRepo <nixpkgs/.git>
|
||||||
@ -110,24 +114,45 @@ rec {
|
|||||||
with builtins;
|
with builtins;
|
||||||
let fileName = toString path + "/" + file;
|
let fileName = toString path + "/" + file;
|
||||||
packedRefsName = toString path + "/packed-refs";
|
packedRefsName = toString path + "/packed-refs";
|
||||||
in if lib.pathExists fileName
|
absolutePath = base: path:
|
||||||
|
if lib.hasPrefix "/" path
|
||||||
|
then path
|
||||||
|
else toString (/. + "${base}/${path}");
|
||||||
|
in if pathIsRegularFile path
|
||||||
|
# Resolve git worktrees. See gitrepository-layout(5)
|
||||||
then
|
then
|
||||||
let fileContent = lib.fileContents fileName;
|
let m = match "^gitdir: (.*)$" (lib.fileContents path);
|
||||||
|
in if m == null
|
||||||
|
then throw ("File contains no gitdir reference: " + path)
|
||||||
|
else
|
||||||
|
let gitDir = absolutePath (dirOf path) (lib.head m);
|
||||||
|
commonDir' = if pathIsRegularFile "${gitDir}/commondir"
|
||||||
|
then lib.fileContents "${gitDir}/commondir"
|
||||||
|
else gitDir;
|
||||||
|
commonDir = absolutePath gitDir commonDir';
|
||||||
|
refFile = lib.removePrefix "${commonDir}/" "${gitDir}/${file}";
|
||||||
|
in readCommitFromFile refFile commonDir
|
||||||
|
|
||||||
|
else if pathIsRegularFile fileName
|
||||||
# Sometimes git stores the commitId directly in the file but
|
# Sometimes git stores the commitId directly in the file but
|
||||||
# sometimes it stores something like: «ref: refs/heads/branch-name»
|
# sometimes it stores something like: «ref: refs/heads/branch-name»
|
||||||
|
then
|
||||||
|
let fileContent = lib.fileContents fileName;
|
||||||
matchRef = match "^ref: (.*)$" fileContent;
|
matchRef = match "^ref: (.*)$" fileContent;
|
||||||
in if matchRef == null
|
in if matchRef == null
|
||||||
then fileContent
|
then fileContent
|
||||||
else readCommitFromFile (lib.head matchRef) path
|
else readCommitFromFile (lib.head matchRef) path
|
||||||
|
|
||||||
|
else if pathIsRegularFile packedRefsName
|
||||||
# Sometimes, the file isn't there at all and has been packed away in the
|
# Sometimes, the file isn't there at all and has been packed away in the
|
||||||
# packed-refs file, so we have to grep through it:
|
# packed-refs file, so we have to grep through it:
|
||||||
else if lib.pathExists packedRefsName
|
|
||||||
then
|
then
|
||||||
let fileContent = readFile packedRefsName;
|
let fileContent = readFile packedRefsName;
|
||||||
matchRef = match (".*\n([^\n ]*) " + file + "\n.*") fileContent;
|
matchRef = match (".*\n([^\n ]*) " + file + "\n.*") fileContent;
|
||||||
in if matchRef == null
|
in if matchRef == null
|
||||||
then throw ("Could not find " + file + " in " + packedRefsName)
|
then throw ("Could not find " + file + " in " + packedRefsName)
|
||||||
else lib.head matchRef
|
else lib.head matchRef
|
||||||
|
|
||||||
else throw ("Not a .git directory: " + path);
|
else throw ("Not a .git directory: " + path);
|
||||||
in readCommitFromFile "HEAD";
|
in readCommitFromFile "HEAD";
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ rec {
|
|||||||
Also note that Nix treats strings as a list of bytes and thus doesn't
|
Also note that Nix treats strings as a list of bytes and thus doesn't
|
||||||
handle unicode.
|
handle unicode.
|
||||||
|
|
||||||
Type: stringtoCharacters :: string -> [string]
|
Type: stringToCharacters :: string -> [string]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
stringToCharacters ""
|
stringToCharacters ""
|
||||||
|
@ -84,7 +84,7 @@ rec {
|
|||||||
else final.parsed.cpu.name;
|
else final.parsed.cpu.name;
|
||||||
|
|
||||||
qemuArch =
|
qemuArch =
|
||||||
if final.isArm then "arm"
|
if final.isAarch32 then "arm"
|
||||||
else if final.isx86_64 then "x86_64"
|
else if final.isx86_64 then "x86_64"
|
||||||
else if final.isx86 then "i386"
|
else if final.isx86 then "i386"
|
||||||
else {
|
else {
|
||||||
|
@ -170,8 +170,8 @@ rec {
|
|||||||
iphone64 = {
|
iphone64 = {
|
||||||
config = "aarch64-apple-ios";
|
config = "aarch64-apple-ios";
|
||||||
# config = "aarch64-apple-darwin14";
|
# config = "aarch64-apple-darwin14";
|
||||||
sdkVer = "10.2";
|
sdkVer = "12.4";
|
||||||
xcodeVer = "8.2";
|
xcodeVer = "10.3";
|
||||||
xcodePlatform = "iPhoneOS";
|
xcodePlatform = "iPhoneOS";
|
||||||
useiOSPrebuilt = true;
|
useiOSPrebuilt = true;
|
||||||
platform = {};
|
platform = {};
|
||||||
@ -180,8 +180,8 @@ rec {
|
|||||||
iphone32 = {
|
iphone32 = {
|
||||||
config = "armv7a-apple-ios";
|
config = "armv7a-apple-ios";
|
||||||
# config = "arm-apple-darwin10";
|
# config = "arm-apple-darwin10";
|
||||||
sdkVer = "10.2";
|
sdkVer = "12.4";
|
||||||
xcodeVer = "8.2";
|
xcodeVer = "10.3";
|
||||||
xcodePlatform = "iPhoneOS";
|
xcodePlatform = "iPhoneOS";
|
||||||
useiOSPrebuilt = true;
|
useiOSPrebuilt = true;
|
||||||
platform = {};
|
platform = {};
|
||||||
@ -190,8 +190,8 @@ rec {
|
|||||||
iphone64-simulator = {
|
iphone64-simulator = {
|
||||||
config = "x86_64-apple-ios";
|
config = "x86_64-apple-ios";
|
||||||
# config = "x86_64-apple-darwin14";
|
# config = "x86_64-apple-darwin14";
|
||||||
sdkVer = "10.2";
|
sdkVer = "12.4";
|
||||||
xcodeVer = "8.2";
|
xcodeVer = "10.3";
|
||||||
xcodePlatform = "iPhoneSimulator";
|
xcodePlatform = "iPhoneSimulator";
|
||||||
useiOSPrebuilt = true;
|
useiOSPrebuilt = true;
|
||||||
platform = {};
|
platform = {};
|
||||||
@ -200,8 +200,8 @@ rec {
|
|||||||
iphone32-simulator = {
|
iphone32-simulator = {
|
||||||
config = "i686-apple-ios";
|
config = "i686-apple-ios";
|
||||||
# config = "i386-apple-darwin11";
|
# config = "i386-apple-darwin11";
|
||||||
sdkVer = "10.2";
|
sdkVer = "12.4";
|
||||||
xcodeVer = "8.2";
|
xcodeVer = "10.3";
|
||||||
xcodePlatform = "iPhoneSimulator";
|
xcodePlatform = "iPhoneSimulator";
|
||||||
useiOSPrebuilt = true;
|
useiOSPrebuilt = true;
|
||||||
platform = {};
|
platform = {};
|
||||||
|
@ -55,9 +55,6 @@ rec {
|
|||||||
|
|
||||||
isEfi = map (family: { cpu.family = family; })
|
isEfi = map (family: { cpu.family = family; })
|
||||||
[ "x86" "arm" "aarch64" ];
|
[ "x86" "arm" "aarch64" ];
|
||||||
|
|
||||||
# Deprecated after 18.03
|
|
||||||
isArm = isAarch32;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
matchAnyAttrs = patterns:
|
matchAnyAttrs = patterns:
|
||||||
|
@ -441,4 +441,41 @@ runTests {
|
|||||||
expected = "«foo»";
|
expected = "«foo»";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
# CLI
|
||||||
|
|
||||||
|
testToGNUCommandLine = {
|
||||||
|
expr = cli.toGNUCommandLine {} {
|
||||||
|
data = builtins.toJSON { id = 0; };
|
||||||
|
X = "PUT";
|
||||||
|
retry = 3;
|
||||||
|
retry-delay = null;
|
||||||
|
url = [ "https://example.com/foo" "https://example.com/bar" ];
|
||||||
|
silent = false;
|
||||||
|
verbose = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
expected = [
|
||||||
|
"-X" "PUT"
|
||||||
|
"--data" "{\"id\":0}"
|
||||||
|
"--retry" "3"
|
||||||
|
"--url" "https://example.com/foo"
|
||||||
|
"--url" "https://example.com/bar"
|
||||||
|
"--verbose"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
testToGNUCommandLineShell = {
|
||||||
|
expr = cli.toGNUCommandLineShell {} {
|
||||||
|
data = builtins.toJSON { id = 0; };
|
||||||
|
X = "PUT";
|
||||||
|
retry = 3;
|
||||||
|
retry-delay = null;
|
||||||
|
url = [ "https://example.com/foo" "https://example.com/bar" ];
|
||||||
|
silent = false;
|
||||||
|
verbose = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
expected = "'-X' 'PUT' '--data' '{\"id\":0}' '--retry' '3' '--url' 'https://example.com/foo' '--url' 'https://example.com/bar' '--verbose'";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ rec {
|
|||||||
let
|
let
|
||||||
revisionFile = "${toString ./..}/.git-revision";
|
revisionFile = "${toString ./..}/.git-revision";
|
||||||
gitRepo = "${toString ./..}/.git";
|
gitRepo = "${toString ./..}/.git";
|
||||||
in if lib.pathIsDirectory gitRepo
|
in if lib.pathIsGitRepo gitRepo
|
||||||
then lib.commitIdFromGitRepo gitRepo
|
then lib.commitIdFromGitRepo gitRepo
|
||||||
else if lib.pathExists revisionFile then lib.fileContents revisionFile
|
else if lib.pathExists revisionFile then lib.fileContents revisionFile
|
||||||
else default;
|
else default;
|
||||||
|
@ -367,18 +367,6 @@ rec {
|
|||||||
{ path = [ "services" "geoclue2" "appConfig" ];
|
{ path = [ "services" "geoclue2" "appConfig" ];
|
||||||
name = "desktopID";
|
name = "desktopID";
|
||||||
}
|
}
|
||||||
{ path = [ "home-manager" "users" anyString "programs" "ssh" "matchBlocks" ];
|
|
||||||
name = "host"; # https://github.com/rycee/home-manager/blob/e8dbc3561373b68d12decb3c0d7c1ba245f138f7/modules/programs/ssh.nix#L265
|
|
||||||
}
|
|
||||||
{ path = [ "home-manager" "users" anyString "home" "file" ];
|
|
||||||
name = "target"; # https://github.com/rycee/home-manager/blob/0e9b7aab3c6c27bf020402e0e2ef20b65c040552/modules/files.nix#L33
|
|
||||||
}
|
|
||||||
{ path = [ "home-manager" "users" anyString "xdg" "configFile" ];
|
|
||||||
name = "target"; # https://github.com/rycee/home-manager/blob/54de0e1d79a1370e57a8f23bef89f99f9b92ab67/modules/misc/xdg.nix#L41
|
|
||||||
}
|
|
||||||
{ path = [ "home-manager" "users" anyString "xdg" "dataFile" ];
|
|
||||||
name = "target"; # https://github.com/rycee/home-manager/blob/54de0e1d79a1370e57a8f23bef89f99f9b92ab67/modules/misc/xdg.nix#L58
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
matched = let
|
matched = let
|
||||||
equals = a: b: b == anyString || a == b;
|
equals = a: b: b == anyString || a == b;
|
||||||
@ -418,7 +406,7 @@ rec {
|
|||||||
In file ${def.file}
|
In file ${def.file}
|
||||||
a list is being assigned to the option config.${option}.
|
a list is being assigned to the option config.${option}.
|
||||||
This will soon be an error as type loaOf is deprecated.
|
This will soon be an error as type loaOf is deprecated.
|
||||||
See https://git.io/fj2zm for more information.
|
See https://github.com/NixOS/nixpkgs/pull/63103 for more information.
|
||||||
Do
|
Do
|
||||||
${option} =
|
${option} =
|
||||||
{ ${set}${more}}
|
{ ${set}${more}}
|
||||||
@ -602,7 +590,7 @@ rec {
|
|||||||
tail' = tail ts;
|
tail' = tail ts;
|
||||||
in foldl' either head' tail';
|
in foldl' either head' tail';
|
||||||
|
|
||||||
# Either value of type `finalType` or `coercedType`, the latter is
|
# Either value of type `coercedType` or `finalType`, the former is
|
||||||
# converted to `finalType` using `coerceFunc`.
|
# converted to `finalType` using `coerceFunc`.
|
||||||
coercedTo = coercedType: coerceFunc: finalType:
|
coercedTo = coercedType: coerceFunc: finalType:
|
||||||
assert lib.assertMsg (coercedType.getSubModules == null)
|
assert lib.assertMsg (coercedType.getSubModules == null)
|
||||||
@ -611,12 +599,12 @@ rec {
|
|||||||
mkOptionType rec {
|
mkOptionType rec {
|
||||||
name = "coercedTo";
|
name = "coercedTo";
|
||||||
description = "${finalType.description} or ${coercedType.description} convertible to it";
|
description = "${finalType.description} or ${coercedType.description} convertible to it";
|
||||||
check = x: finalType.check x || (coercedType.check x && finalType.check (coerceFunc x));
|
check = x: (coercedType.check x && finalType.check (coerceFunc x)) || finalType.check x;
|
||||||
merge = loc: defs:
|
merge = loc: defs:
|
||||||
let
|
let
|
||||||
coerceVal = val:
|
coerceVal = val:
|
||||||
if finalType.check val then val
|
if coercedType.check val then coerceFunc val
|
||||||
else coerceFunc val;
|
else val;
|
||||||
in finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs);
|
in finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs);
|
||||||
emptyValue = finalType.emptyValue;
|
emptyValue = finalType.emptyValue;
|
||||||
getSubOptions = finalType.getSubOptions;
|
getSubOptions = finalType.getSubOptions;
|
||||||
|
@ -40,12 +40,6 @@
|
|||||||
See `./scripts/check-maintainer-github-handles.sh` for an example on how to work with this data.
|
See `./scripts/check-maintainer-github-handles.sh` for an example on how to work with this data.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
"00-matt" = {
|
|
||||||
name = "Matt Smith";
|
|
||||||
email = "matt@offtopica.uk";
|
|
||||||
github = "00-matt";
|
|
||||||
githubId = 48835712;
|
|
||||||
};
|
|
||||||
"0x4A6F" = {
|
"0x4A6F" = {
|
||||||
email = "0x4A6F@shackspace.de";
|
email = "0x4A6F@shackspace.de";
|
||||||
name = "Joachim Ernst";
|
name = "Joachim Ernst";
|
||||||
@ -517,6 +511,12 @@
|
|||||||
githubId = 5327697;
|
githubId = 5327697;
|
||||||
name = "Anatolii Prylutskyi";
|
name = "Anatolii Prylutskyi";
|
||||||
};
|
};
|
||||||
|
antoinerg = {
|
||||||
|
email = "roygobeil.antoine@gmail.com";
|
||||||
|
github = "antoinerg";
|
||||||
|
githubId = 301546;
|
||||||
|
name = "Antoine Roy-Gobeil";
|
||||||
|
};
|
||||||
anton-dessiatov = {
|
anton-dessiatov = {
|
||||||
email = "anton.dessiatov@gmail.com";
|
email = "anton.dessiatov@gmail.com";
|
||||||
github = "anton-dessiatov";
|
github = "anton-dessiatov";
|
||||||
@ -594,6 +594,12 @@
|
|||||||
githubId = 1296771;
|
githubId = 1296771;
|
||||||
name = "Anders Riutta";
|
name = "Anders Riutta";
|
||||||
};
|
};
|
||||||
|
arnoldfarkas = {
|
||||||
|
email = "arnold.farkas@gmail.com";
|
||||||
|
github = "arnoldfarkas";
|
||||||
|
githubId = 59696216;
|
||||||
|
name = "Arnold Farkas";
|
||||||
|
};
|
||||||
arobyn = {
|
arobyn = {
|
||||||
email = "shados@shados.net";
|
email = "shados@shados.net";
|
||||||
github = "shados";
|
github = "shados";
|
||||||
@ -676,6 +682,12 @@
|
|||||||
githubId = 192147;
|
githubId = 192147;
|
||||||
name = "aszlig";
|
name = "aszlig";
|
||||||
};
|
};
|
||||||
|
atemu = {
|
||||||
|
name = "Atemu";
|
||||||
|
email = "atemu.main+nixpkgs@gmail.com";
|
||||||
|
github = "Atemu";
|
||||||
|
githubId = 18599032;
|
||||||
|
};
|
||||||
athas = {
|
athas = {
|
||||||
email = "athas@sigkill.dk";
|
email = "athas@sigkill.dk";
|
||||||
github = "athas";
|
github = "athas";
|
||||||
@ -951,6 +963,12 @@
|
|||||||
githubId = 5718007;
|
githubId = 5718007;
|
||||||
name = "Bastian Köcher";
|
name = "Bastian Köcher";
|
||||||
};
|
};
|
||||||
|
blanky0230 = {
|
||||||
|
email = "blanky0230@gmail.com";
|
||||||
|
github = "blanky0230";
|
||||||
|
githubId = 5700358;
|
||||||
|
name = "Thomas Blank";
|
||||||
|
};
|
||||||
blitz = {
|
blitz = {
|
||||||
email = "js@alien8.de";
|
email = "js@alien8.de";
|
||||||
github = "blitz";
|
github = "blitz";
|
||||||
@ -1893,6 +1911,12 @@
|
|||||||
email = "burkett.andrew@gmail.com";
|
email = "burkett.andrew@gmail.com";
|
||||||
name = "Andrew Burkett";
|
name = "Andrew Burkett";
|
||||||
};
|
};
|
||||||
|
drewrisinger = {
|
||||||
|
email = "drisinger+nixpkgs@gmail.com";
|
||||||
|
github = "drewrisinger";
|
||||||
|
gitHubId = 10198051;
|
||||||
|
name = "Drew Risinger";
|
||||||
|
};
|
||||||
dsferruzza = {
|
dsferruzza = {
|
||||||
email = "david.sferruzza@gmail.com";
|
email = "david.sferruzza@gmail.com";
|
||||||
github = "dsferruzza";
|
github = "dsferruzza";
|
||||||
@ -1919,6 +1943,12 @@
|
|||||||
fingerprint = "5DD7 C6F6 0630 F08E DAE7 4711 1525 585D 1B43 C62A";
|
fingerprint = "5DD7 C6F6 0630 F08E DAE7 4711 1525 585D 1B43 C62A";
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
|
dwarfmaster = {
|
||||||
|
email = "nixpkgs@dwarfmaster.net";
|
||||||
|
github = "dwarfmaster";
|
||||||
|
githubId = 2025623;
|
||||||
|
name = "Luc Chabassier";
|
||||||
|
};
|
||||||
dxf = {
|
dxf = {
|
||||||
email = "dingxiangfei2009@gmail.com";
|
email = "dingxiangfei2009@gmail.com";
|
||||||
github = "dingxiangfei2009";
|
github = "dingxiangfei2009";
|
||||||
@ -2393,6 +2423,12 @@
|
|||||||
githubId = 415760;
|
githubId = 415760;
|
||||||
name = "Jonas Höglund";
|
name = "Jonas Höglund";
|
||||||
};
|
};
|
||||||
|
fishi0x01 = {
|
||||||
|
email = "fishi0x01@gmail.com";
|
||||||
|
github = "fishi0x01";
|
||||||
|
githubId = 10799507;
|
||||||
|
name = "Karl Fischer";
|
||||||
|
};
|
||||||
Flakebi = {
|
Flakebi = {
|
||||||
email = "flakebi@t-online.de";
|
email = "flakebi@t-online.de";
|
||||||
github = "Flakebi";
|
github = "Flakebi";
|
||||||
@ -2439,6 +2475,12 @@
|
|||||||
githubId = 844574;
|
githubId = 844574;
|
||||||
name = "Daniel Austin";
|
name = "Daniel Austin";
|
||||||
};
|
};
|
||||||
|
flyfloh = {
|
||||||
|
email = "nix@halbmastwurf.de";
|
||||||
|
github = "flyfloh";
|
||||||
|
githubId = 74379;
|
||||||
|
name = "Florian Pester";
|
||||||
|
};
|
||||||
fmthoma = {
|
fmthoma = {
|
||||||
email = "f.m.thoma@googlemail.com";
|
email = "f.m.thoma@googlemail.com";
|
||||||
github = "fmthoma";
|
github = "fmthoma";
|
||||||
@ -2520,6 +2562,12 @@
|
|||||||
githubId = 1943632;
|
githubId = 1943632;
|
||||||
name = "fro_ozen";
|
name = "fro_ozen";
|
||||||
};
|
};
|
||||||
|
Frostman = {
|
||||||
|
email = "me@slukjanov.name";
|
||||||
|
github = "Frostman";
|
||||||
|
githubId = 134872;
|
||||||
|
name = "Sergei Lukianov";
|
||||||
|
};
|
||||||
frontsideair = {
|
frontsideair = {
|
||||||
email = "photonia@gmail.com";
|
email = "photonia@gmail.com";
|
||||||
github = "frontsideair";
|
github = "frontsideair";
|
||||||
@ -2992,6 +3040,12 @@
|
|||||||
githubId = 4401220;
|
githubId = 4401220;
|
||||||
name = "Michael Eden";
|
name = "Michael Eden";
|
||||||
};
|
};
|
||||||
|
ilya-fedin = {
|
||||||
|
email = "fedin-ilja2010@ya.ru";
|
||||||
|
github = "ilya-fedin";
|
||||||
|
githubId = 17829319;
|
||||||
|
name = "Ilya Fedin";
|
||||||
|
};
|
||||||
ilya-kolpakov = {
|
ilya-kolpakov = {
|
||||||
email = "ilya.kolpakov@gmail.com";
|
email = "ilya.kolpakov@gmail.com";
|
||||||
github = "ilya-kolpakov";
|
github = "ilya-kolpakov";
|
||||||
@ -3474,6 +3528,12 @@
|
|||||||
github = "jorsn";
|
github = "jorsn";
|
||||||
githubId = 4646725;
|
githubId = 4646725;
|
||||||
};
|
};
|
||||||
|
jpas = {
|
||||||
|
name = "Jarrod Pas";
|
||||||
|
email = "jarrod@jarrodpas.com";
|
||||||
|
github = "jpas";
|
||||||
|
githubId = 5689724;
|
||||||
|
};
|
||||||
jpdoyle = {
|
jpdoyle = {
|
||||||
email = "joethedoyle@gmail.com";
|
email = "joethedoyle@gmail.com";
|
||||||
github = "jpdoyle";
|
github = "jpdoyle";
|
||||||
@ -3504,6 +3564,16 @@
|
|||||||
githubId = 4611077;
|
githubId = 4611077;
|
||||||
name = "Raymond Gauthier";
|
name = "Raymond Gauthier";
|
||||||
};
|
};
|
||||||
|
jtcoolen = {
|
||||||
|
email = "jtcoolen@pm.me";
|
||||||
|
name = "Julien Coolen";
|
||||||
|
github = "jtcoolen";
|
||||||
|
githubId = 54635632;
|
||||||
|
keys = [{
|
||||||
|
longkeyid = "rsa4096/0x19642151C218F6F5";
|
||||||
|
fingerprint = "4C68 56EE DFDA 20FB 77E8 9169 1964 2151 C218 F6F5";
|
||||||
|
}];
|
||||||
|
};
|
||||||
jtobin = {
|
jtobin = {
|
||||||
email = "jared@jtobin.io";
|
email = "jared@jtobin.io";
|
||||||
github = "jtobin";
|
github = "jtobin";
|
||||||
@ -3790,6 +3860,12 @@
|
|||||||
githubId = 787421;
|
githubId = 787421;
|
||||||
name = "Kevin Quick";
|
name = "Kevin Quick";
|
||||||
};
|
};
|
||||||
|
kraem = {
|
||||||
|
email = "me@kraem.xyz";
|
||||||
|
github = "kraem";
|
||||||
|
githubId = 26622971;
|
||||||
|
name = "Ronnie Ebrin";
|
||||||
|
};
|
||||||
kragniz = {
|
kragniz = {
|
||||||
email = "louis@kragniz.eu";
|
email = "louis@kragniz.eu";
|
||||||
github = "kragniz";
|
github = "kragniz";
|
||||||
@ -3808,6 +3884,12 @@
|
|||||||
githubId = 17659803;
|
githubId = 17659803;
|
||||||
name = "Matthias Axel Kröll";
|
name = "Matthias Axel Kröll";
|
||||||
};
|
};
|
||||||
|
kristian-brucaj = {
|
||||||
|
email = "kbrucaj@gmail.com";
|
||||||
|
github = "kristian-brucaj";
|
||||||
|
githubID = "8893110";
|
||||||
|
name = "Kristian Brucaj";
|
||||||
|
};
|
||||||
kristoff3r = {
|
kristoff3r = {
|
||||||
email = "k.soeholm@gmail.com";
|
email = "k.soeholm@gmail.com";
|
||||||
github = "kristoff3r";
|
github = "kristoff3r";
|
||||||
@ -3838,6 +3920,12 @@
|
|||||||
githubId = 449813;
|
githubId = 449813;
|
||||||
name = "Roman Kuznetsov";
|
name = "Roman Kuznetsov";
|
||||||
};
|
};
|
||||||
|
kwohlfahrt = {
|
||||||
|
email = "kai.wohlfahrt@gmail.com";
|
||||||
|
github = "kwohlfahrt";
|
||||||
|
githubId = 2422454;
|
||||||
|
name = "Kai Wohlfahrt";
|
||||||
|
};
|
||||||
kylesferrazza = {
|
kylesferrazza = {
|
||||||
name = "Kyle Sferrazza";
|
name = "Kyle Sferrazza";
|
||||||
email = "kyle.sferrazza@gmail.com";
|
email = "kyle.sferrazza@gmail.com";
|
||||||
@ -3903,6 +3991,12 @@
|
|||||||
githubId = 32152;
|
githubId = 32152;
|
||||||
name = "Luka Blaskovic";
|
name = "Luka Blaskovic";
|
||||||
};
|
};
|
||||||
|
ldelelis = {
|
||||||
|
email = "ldelelis@est.frba.utn.edu.ar";
|
||||||
|
github = "ldelelis";
|
||||||
|
githubId = 20250323;
|
||||||
|
name = "Lucio Delelis";
|
||||||
|
};
|
||||||
ldesgoui = {
|
ldesgoui = {
|
||||||
email = "ldesgoui@gmail.com";
|
email = "ldesgoui@gmail.com";
|
||||||
github = "ldesgoui";
|
github = "ldesgoui";
|
||||||
@ -4147,12 +4241,6 @@
|
|||||||
github = "ltavard";
|
github = "ltavard";
|
||||||
name = "Laure Tavard";
|
name = "Laure Tavard";
|
||||||
};
|
};
|
||||||
lucas8 = {
|
|
||||||
email = "luc.linux@mailoo.org";
|
|
||||||
github = "lucas8";
|
|
||||||
githubId = 2025623;
|
|
||||||
name = "Luc Chabassier";
|
|
||||||
};
|
|
||||||
lucus16 = {
|
lucus16 = {
|
||||||
email = "lars.jellema@gmail.com";
|
email = "lars.jellema@gmail.com";
|
||||||
github = "Lucus16";
|
github = "Lucus16";
|
||||||
@ -5088,6 +5176,12 @@
|
|||||||
githubId = 7588406;
|
githubId = 7588406;
|
||||||
name = "Andrew R. M.";
|
name = "Andrew R. M.";
|
||||||
};
|
};
|
||||||
|
nloomans = {
|
||||||
|
email = "noah@nixos.noahloomans.com";
|
||||||
|
github = "nloomans";
|
||||||
|
githubId = 7829481;
|
||||||
|
name = "Noah Loomans";
|
||||||
|
};
|
||||||
nmattia = {
|
nmattia = {
|
||||||
email = "nicolas@nmattia.com";
|
email = "nicolas@nmattia.com";
|
||||||
github = "nmattia";
|
github = "nmattia";
|
||||||
@ -5403,6 +5497,12 @@
|
|||||||
githubId = 3250809;
|
githubId = 3250809;
|
||||||
name = "Milan Pässler";
|
name = "Milan Pässler";
|
||||||
};
|
};
|
||||||
|
petercommand = {
|
||||||
|
email = "petercommand@gmail.com";
|
||||||
|
github = "petercommand";
|
||||||
|
githubId = 1260660;
|
||||||
|
name = "petercommand";
|
||||||
|
};
|
||||||
peterhoeg = {
|
peterhoeg = {
|
||||||
email = "peter@hoeg.com";
|
email = "peter@hoeg.com";
|
||||||
github = "peterhoeg";
|
github = "peterhoeg";
|
||||||
@ -6147,6 +6247,16 @@
|
|||||||
githubId = 6022042;
|
githubId = 6022042;
|
||||||
name = "Sam Parkinson";
|
name = "Sam Parkinson";
|
||||||
};
|
};
|
||||||
|
samlich = {
|
||||||
|
email = "nixos@samli.ch";
|
||||||
|
github = "samlich";
|
||||||
|
githubId = 1349989;
|
||||||
|
name = "samlich";
|
||||||
|
keys = [{
|
||||||
|
longkeyid = "rsa4096/B1568953B1939F1C";
|
||||||
|
fingerprint = "AE8C 0836 FDF6 3FFC 9580 C588 B156 8953 B193 9F1C";
|
||||||
|
}];
|
||||||
|
};
|
||||||
samrose = {
|
samrose = {
|
||||||
email = "samuel.rose@gmail.com";
|
email = "samuel.rose@gmail.com";
|
||||||
github = "samrose";
|
github = "samrose";
|
||||||
@ -6254,6 +6364,12 @@
|
|||||||
github = "scubed2";
|
github = "scubed2";
|
||||||
name = "Sterling Stein";
|
name = "Sterling Stein";
|
||||||
};
|
};
|
||||||
|
sdier = {
|
||||||
|
email = "scott@dier.name";
|
||||||
|
github = "sdier";
|
||||||
|
githubId = 11613056;
|
||||||
|
name = "Scott Dier";
|
||||||
|
};
|
||||||
sdll = {
|
sdll = {
|
||||||
email = "sasha.delly@gmail.com";
|
email = "sasha.delly@gmail.com";
|
||||||
github = "sdll";
|
github = "sdll";
|
||||||
@ -6841,6 +6957,12 @@
|
|||||||
githubId = 870673;
|
githubId = 870673;
|
||||||
name = "Takuo Yonezawa";
|
name = "Takuo Yonezawa";
|
||||||
};
|
};
|
||||||
|
talkara = {
|
||||||
|
email = "taito.horiuchi@relexsolutions.com";
|
||||||
|
github = "talkara";
|
||||||
|
githubId = 51232929;
|
||||||
|
name = "Taito Horiuchi";
|
||||||
|
};
|
||||||
talyz = {
|
talyz = {
|
||||||
email = "kim.lindberger@gmail.com";
|
email = "kim.lindberger@gmail.com";
|
||||||
github = "talyz";
|
github = "talyz";
|
||||||
@ -7032,6 +7154,11 @@
|
|||||||
github = "timbertson";
|
github = "timbertson";
|
||||||
name = "Tim Cuthbertson";
|
name = "Tim Cuthbertson";
|
||||||
};
|
};
|
||||||
|
timma = {
|
||||||
|
email = "kunduru.it.iitb@gmail.com";
|
||||||
|
github = "ktrsoft";
|
||||||
|
name = "Timma";
|
||||||
|
};
|
||||||
timokau = {
|
timokau = {
|
||||||
email = "timokau@zoho.com";
|
email = "timokau@zoho.com";
|
||||||
github = "timokau";
|
github = "timokau";
|
||||||
@ -7823,6 +7950,12 @@
|
|||||||
githubId = 1069303;
|
githubId = 1069303;
|
||||||
name = "Kim Simmons";
|
name = "Kim Simmons";
|
||||||
};
|
};
|
||||||
|
zowoq = {
|
||||||
|
email = "59103226+zowoq@users.noreply.github.com";
|
||||||
|
github = "zowoq";
|
||||||
|
githubId = 59103226;
|
||||||
|
name = "zowoq";
|
||||||
|
};
|
||||||
zraexy = {
|
zraexy = {
|
||||||
email = "zraexy@gmail.com";
|
email = "zraexy@gmail.com";
|
||||||
github = "zraexy";
|
github = "zraexy";
|
||||||
@ -7895,4 +8028,16 @@
|
|||||||
githubId = 8686360;
|
githubId = 8686360;
|
||||||
name = "Illia Shestakov";
|
name = "Illia Shestakov";
|
||||||
};
|
};
|
||||||
|
foxit64 = {
|
||||||
|
email = "o4nsxy05@gmail.com";
|
||||||
|
github = "foxit64";
|
||||||
|
githubId = 56247270;
|
||||||
|
name = "Foxit";
|
||||||
|
};
|
||||||
|
masaeedu = {
|
||||||
|
email = "masaeedu@gmail.com";
|
||||||
|
github = "masaeedu";
|
||||||
|
githubId = 3674056;
|
||||||
|
name = "Asad Saeeduddin";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,8 @@ find . -type f | while read src; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
cat >"$SRCS" <<EOF
|
cat >"$SRCS" <<EOF
|
||||||
# DO NOT EDIT! This file is generated automatically by fetch-kde-qt.sh
|
# DO NOT EDIT! This file is generated automatically.
|
||||||
|
# Command: $0 $@
|
||||||
{ fetchurl, mirror }:
|
{ fetchurl, mirror }:
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -11,13 +11,14 @@ compat53,,,,,vcunat
|
|||||||
coxpcall,,,1.17.0-1,,
|
coxpcall,,,1.17.0-1,,
|
||||||
cqueues,,,,,vcunat
|
cqueues,,,,,vcunat
|
||||||
cyrussasl,,,,,vcunat
|
cyrussasl,,,,,vcunat
|
||||||
digestif,,http://luarocks.org/dev,,lua5_3,
|
digestif,,,,lua5_3,
|
||||||
dkjson,,,,,
|
dkjson,,,,,
|
||||||
fifo,,,,,
|
fifo,,,,,
|
||||||
http,,,,,vcunat
|
http,,,,,vcunat
|
||||||
inspect,,,,,
|
inspect,,,,,
|
||||||
ldoc,,,,,
|
ldoc,,,,,
|
||||||
lgi,,,,,
|
lgi,,,,,
|
||||||
|
linenoise,,,,,
|
||||||
ljsyscall,,,,lua5_1,lblasc
|
ljsyscall,,,,lua5_1,lblasc
|
||||||
lpeg,,,,,vyp
|
lpeg,,,,,vyp
|
||||||
lpeg_patterns,,,,,
|
lpeg_patterns,,,,,
|
||||||
@ -43,6 +44,7 @@ luadbi-mysql,,,,,
|
|||||||
luadbi-postgresql,,,,,
|
luadbi-postgresql,,,,,
|
||||||
luadbi-sqlite3,,,,,
|
luadbi-sqlite3,,,,,
|
||||||
luadoc,,,,,
|
luadoc,,,,,
|
||||||
|
luaepnf,,,,,
|
||||||
luaevent,,,,,
|
luaevent,,,,,
|
||||||
luaexpat,,,1.3.0-1,,arobyn flosse
|
luaexpat,,,1.3.0-1,,arobyn flosse
|
||||||
luaffi,,http://luarocks.org/dev,,,
|
luaffi,,http://luarocks.org/dev,,,
|
||||||
@ -50,6 +52,7 @@ luafilesystem,,,1.7.0-2,,flosse vcunat
|
|||||||
lualogging,,,,,
|
lualogging,,,,,
|
||||||
luaossl,,,,lua5_1,vcunat
|
luaossl,,,,lua5_1,vcunat
|
||||||
luaposix,,,,,vyp lblasc
|
luaposix,,,,,vyp lblasc
|
||||||
|
luarepl,,,,,
|
||||||
luasec,,,,,flosse
|
luasec,,,,,flosse
|
||||||
luasocket,,,,,
|
luasocket,,,,,
|
||||||
luasql-sqlite3,,,,,vyp
|
luasql-sqlite3,,,,,vyp
|
||||||
@ -72,3 +75,4 @@ std__debug,std._debug,,,,
|
|||||||
std_normalize,std.normalize,,,,
|
std_normalize,std.normalize,,,,
|
||||||
stdlib,,,,,vyp
|
stdlib,,,,,vyp
|
||||||
pulseaudio,,,,,doronbehar
|
pulseaudio,,,,,doronbehar
|
||||||
|
vstruct,,,,,
|
||||||
|
|
@ -19,7 +19,7 @@ export LUAROCKS_CONFIG="$NIXPKGS_PATH/maintainers/scripts/luarocks-config.lua"
|
|||||||
|
|
||||||
# 10 is a pretty arbitrary number of simultaneous jobs, but it is generally
|
# 10 is a pretty arbitrary number of simultaneous jobs, but it is generally
|
||||||
# impolite to hit a webserver with *too* many simultaneous connections :)
|
# impolite to hit a webserver with *too* many simultaneous connections :)
|
||||||
PARALLEL_JOBS=10
|
PARALLEL_JOBS=1
|
||||||
|
|
||||||
exit_trap() {
|
exit_trap() {
|
||||||
local lc="$BASH_COMMAND" rc=$?
|
local lc="$BASH_COMMAND" rc=$?
|
||||||
|
@ -19,6 +19,12 @@
|
|||||||
<command>nixos-rebuild switch</command>.
|
<command>nixos-rebuild switch</command>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
Some packages require additional global configuration such as D-Bus or systemd service registration so adding them to <xref linkend="opt-environment.systemPackages"/> might not be sufficient. You are advised to check the <link xlink:href="#ch-options">list of options</link> whether a NixOS module for the package does not exist.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
You can get a list of the available packages as follows:
|
You can get a list of the available packages as follows:
|
||||||
<screen>
|
<screen>
|
||||||
|
@ -37,4 +37,38 @@ Enter passphrase for /dev/disk/by-uuid/3f6b0024-3a44-4fde-a43a-767b872abe5d: ***
|
|||||||
on an encrypted partition, it is necessary to add the following grub option:
|
on an encrypted partition, it is necessary to add the following grub option:
|
||||||
<programlisting><xref linkend="opt-boot.loader.grub.enableCryptodisk"/> = true;</programlisting>
|
<programlisting><xref linkend="opt-boot.loader.grub.enableCryptodisk"/> = true;</programlisting>
|
||||||
</para>
|
</para>
|
||||||
|
<section xml:id="sec-luks-file-systems-fido2">
|
||||||
|
<title>FIDO2</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
NixOS also supports unlocking your LUKS-Encrypted file system using a FIDO2 compatible token. In the following example, we will create a new FIDO2 credential
|
||||||
|
and add it as a new key to our existing device <filename>/dev/sda2</filename>:
|
||||||
|
|
||||||
|
<screen>
|
||||||
|
# export FIDO2_LABEL="/dev/sda2 @ $HOSTNAME"
|
||||||
|
# fido2luks credential "$FIDO2_LABEL"
|
||||||
|
f1d00200108b9d6e849a8b388da457688e3dd653b4e53770012d8f28e5d3b269865038c346802f36f3da7278b13ad6a3bb6a1452e24ebeeaa24ba40eef559b1b287d2a2f80b7
|
||||||
|
|
||||||
|
# fido2luks -i add-key /dev/sda2 f1d00200108b9d6e849a8b388da457688e3dd653b4e53770012d8f28e5d3b269865038c346802f36f3da7278b13ad6a3bb6a1452e24ebeeaa24ba40eef559b1b287d2a2f80b7
|
||||||
|
Password:
|
||||||
|
Password (again):
|
||||||
|
Old password:
|
||||||
|
Old password (again):
|
||||||
|
Added to key to device /dev/sda2, slot: 2
|
||||||
|
</screen>
|
||||||
|
|
||||||
|
To ensure that this file system is decrypted using the FIDO2 compatible key, add the following to <filename>configuration.nix</filename>:
|
||||||
|
<programlisting>
|
||||||
|
<link linkend="opt-boot.initrd.luks.fido2Support">boot.initrd.luks.fido2Support</link> = true;
|
||||||
|
<link linkend="opt-boot.initrd.luks.devices._name__.fido2.credential">boot.initrd.luks.devices."/dev/sda2".fido2.credential</link> = "f1d00200108b9d6e849a8b388da457688e3dd653b4e53770012d8f28e5d3b269865038c346802f36f3da7278b13ad6a3bb6a1452e24ebeeaa24ba40eef559b1b287d2a2f80b7";
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
You can also use the FIDO2 passwordless setup, but for security reasons, you might want to enable it only when your device is PIN protected, such as <link xlink:href="https://trezor.io/">Trezor</link>.
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
<link linkend="opt-boot.initrd.luks.devices._name__.fido2.passwordLess">boot.initrd.luks.devices."/dev/sda2".fido2.passwordLess</link> = true;
|
||||||
|
</programlisting>
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
@ -28,17 +28,21 @@
|
|||||||
<command>nmtui</command> (curses-based terminal user interface). See their
|
<command>nmtui</command> (curses-based terminal user interface). See their
|
||||||
manual pages for details on their usage. Some desktop environments (GNOME,
|
manual pages for details on their usage. Some desktop environments (GNOME,
|
||||||
KDE) have their own configuration tools for NetworkManager. On XFCE, there is
|
KDE) have their own configuration tools for NetworkManager. On XFCE, there is
|
||||||
no configuration tool for NetworkManager by default: by adding
|
no configuration tool for NetworkManager by default: by enabling <xref linkend="opt-programs.nm-applet.enable"/>, the
|
||||||
<code>networkmanagerapplet</code> to the list of system packages, the
|
graphical applet will be installed and will launch automatically when the graphical session is started.
|
||||||
graphical applet will be installed and will launch automatically when XFCE is
|
|
||||||
starting (and will show in the status tray).
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
<code>networking.networkmanager</code> and <code>networking.wireless</code>
|
<code>networking.networkmanager</code> and <code>networking.wireless</code>
|
||||||
(WPA Supplicant) cannot be enabled at the same time: you can still connect
|
(WPA Supplicant) can be used together if desired. To do this you need to instruct
|
||||||
to the wireless networks using NetworkManager.
|
NetworkManager to ignore those interfaces like:
|
||||||
|
<programlisting>
|
||||||
|
<xref linkend="opt-networking.networkmanager.unmanaged"/> = [
|
||||||
|
"*" "except:type:wwan" "except:type:gsm"
|
||||||
|
];
|
||||||
|
</programlisting>
|
||||||
|
Refer to the option description for the exact syntax and references to external documentation.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
</section>
|
</section>
|
||||||
|
@ -85,11 +85,14 @@
|
|||||||
<programlisting>
|
<programlisting>
|
||||||
<xref linkend="opt-services.xserver.displayManager.defaultSession"/> = "none+i3";
|
<xref linkend="opt-services.xserver.displayManager.defaultSession"/> = "none+i3";
|
||||||
</programlisting>
|
</programlisting>
|
||||||
And, finally, to enable auto-login for a user <literal>johndoe</literal>:
|
Every display manager in NixOS supports auto-login, here is an example
|
||||||
|
using lightdm for a user <literal>alice</literal>:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
<xref linkend="opt-services.xserver.displayManager.auto.enable"/> = true;
|
<xref linkend="opt-services.xserver.displayManager.lightdm.enable"/> = true;
|
||||||
<xref linkend="opt-services.xserver.displayManager.auto.user"/> = "johndoe";
|
<xref linkend="opt-services.xserver.displayManager.lightdm.autoLogin.enable"/> = true;
|
||||||
|
<xref linkend="opt-services.xserver.displayManager.lightdm.autoLogin.user"/> = "alice";
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
The options are named identically for all other display managers.
|
||||||
</para>
|
</para>
|
||||||
</simplesect>
|
</simplesect>
|
||||||
<simplesect xml:id="sec-x11-graphics-cards-nvidia">
|
<simplesect xml:id="sec-x11-graphics-cards-nvidia">
|
||||||
|
@ -28,25 +28,14 @@
|
|||||||
<para>
|
<para>
|
||||||
Some Xfce programs are not installed automatically. To install them manually
|
Some Xfce programs are not installed automatically. To install them manually
|
||||||
(system wide), put them into your
|
(system wide), put them into your
|
||||||
<xref linkend="opt-environment.systemPackages"/>.
|
<xref linkend="opt-environment.systemPackages"/> from <literal>pkgs.xfce</literal>.
|
||||||
</para>
|
</para>
|
||||||
<simplesect xml:id="sec-xfce-thunar-volumes">
|
<simplesect xml:id="sec-xfce-thunar-plugins">
|
||||||
<title>Thunar Volume Support</title>
|
<title>Thunar Plugins</title>
|
||||||
<para>
|
<para>
|
||||||
To enable <emphasis>Thunar</emphasis> volume support, put
|
If you'd like to add extra plugins to Thunar, add them to
|
||||||
<programlisting>
|
<xref linkend="opt-services.xserver.desktopManager.xfce.thunarPlugins"/>.
|
||||||
<xref linkend="opt-services.xserver.desktopManager.xfce.enable"/> = true;
|
You shouldn't just add them to <xref linkend="opt-environment.systemPackages"/>.
|
||||||
</programlisting>
|
|
||||||
into your <emphasis>configuration.nix</emphasis>.
|
|
||||||
</para>
|
|
||||||
</simplesect>
|
|
||||||
<simplesect xml:id="sec-xfce-polkit">
|
|
||||||
<title>Polkit Authentication Agent</title>
|
|
||||||
<para>
|
|
||||||
There is no authentication agent automatically installed alongside Xfce. To
|
|
||||||
allow mounting of local (non-removable) filesystems, you will need to
|
|
||||||
install one. Installing <emphasis>polkit_gnome</emphasis>, a rebuild, logout
|
|
||||||
and login did the trick.
|
|
||||||
</para>
|
</para>
|
||||||
</simplesect>
|
</simplesect>
|
||||||
<simplesect xml:id="sec-xfce-troubleshooting">
|
<simplesect xml:id="sec-xfce-troubleshooting">
|
||||||
|
@ -236,6 +236,10 @@
|
|||||||
introduced to their role, making it easier to pass on knowledge and
|
introduced to their role, making it easier to pass on knowledge and
|
||||||
experience.
|
experience.
|
||||||
</para>
|
</para>
|
||||||
|
<para>
|
||||||
|
Release managers for the current NixOS release are tracked by GitHub team
|
||||||
|
<link xlink:href="https://github.com/orgs/NixOS/teams/nixos-release-managers/members"><literal>@NixOS/nixos-release-managers</literal></link>.
|
||||||
|
</para>
|
||||||
<para>
|
<para>
|
||||||
A release manager's role and responsibilities are:
|
A release manager's role and responsibilities are:
|
||||||
</para>
|
</para>
|
||||||
|
@ -120,12 +120,17 @@ nixos https://nixos.org/channels/nixos-unstable
|
|||||||
to <filename>configuration.nix</filename>:
|
to <filename>configuration.nix</filename>:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
<xref linkend="opt-system.autoUpgrade.enable"/> = true;
|
<xref linkend="opt-system.autoUpgrade.enable"/> = true;
|
||||||
|
<xref linkend="opt-system.autoUpgrade.allowReboot"/> = true;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
This enables a periodically executed systemd service named
|
This enables a periodically executed systemd service named
|
||||||
<literal>nixos-upgrade.service</literal>. It runs <command>nixos-rebuild
|
<literal>nixos-upgrade.service</literal>. If the <literal>allowReboot</literal>
|
||||||
switch --upgrade</command> to upgrade NixOS to the latest version in the
|
option is <literal>false</literal>, it runs <command>nixos-rebuild switch
|
||||||
current channel. (To see when the service runs, see <command>systemctl
|
--upgrade</command> to upgrade NixOS to the latest version in the current
|
||||||
list-timers</command>.) You can also specify a channel explicitly, e.g.
|
channel. (To see when the service runs, see <command>systemctl list-timers</command>.)
|
||||||
|
If <literal>allowReboot</literal> is <literal>true</literal>, then the
|
||||||
|
system will automatically reboot if the new generation contains a different
|
||||||
|
kernel, initrd or kernel modules.
|
||||||
|
You can also specify a channel explicitly, e.g.
|
||||||
<programlisting>
|
<programlisting>
|
||||||
<xref linkend="opt-system.autoUpgrade.channel"/> = https://nixos.org/channels/nixos-19.09;
|
<xref linkend="opt-system.autoUpgrade.channel"/> = https://nixos.org/channels/nixos-19.09;
|
||||||
</programlisting>
|
</programlisting>
|
||||||
|
@ -210,7 +210,7 @@
|
|||||||
The closure must be an appropriately configured NixOS system, with boot
|
The closure must be an appropriately configured NixOS system, with boot
|
||||||
loader and partition configuration that fits the target host. Such a
|
loader and partition configuration that fits the target host. Such a
|
||||||
closure is typically obtained with a command such as <command>nix-build
|
closure is typically obtained with a command such as <command>nix-build
|
||||||
-I nixos-config=./configuration.nix '<nixos>' -A system
|
-I nixos-config=./configuration.nix '<nixpkgs/nixos>' -A system
|
||||||
--no-out-link</command>
|
--no-out-link</command>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
@ -14,12 +14,16 @@
|
|||||||
<refsynopsisdiv>
|
<refsynopsisdiv>
|
||||||
<cmdsynopsis>
|
<cmdsynopsis>
|
||||||
<command>nixos-option</command>
|
<command>nixos-option</command>
|
||||||
|
|
||||||
<arg>
|
<arg>
|
||||||
<option>-I</option> <replaceable>path</replaceable>
|
<group choice='req'>
|
||||||
|
<arg choice='plain'><option>-r</option></arg>
|
||||||
|
<arg choice='plain'><option>--recursive</option></arg>
|
||||||
|
</group>
|
||||||
</arg>
|
</arg>
|
||||||
|
|
||||||
<arg>
|
<arg>
|
||||||
<option>--all</option>
|
<option>-I</option> <replaceable>path</replaceable>
|
||||||
</arg>
|
</arg>
|
||||||
|
|
||||||
<arg>
|
<arg>
|
||||||
@ -45,6 +49,15 @@
|
|||||||
This command accepts the following options:
|
This command accepts the following options:
|
||||||
</para>
|
</para>
|
||||||
<variablelist>
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-r</option></term>
|
||||||
|
<term><option>--recursive</option></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Print all the values at or below the specified path recursively.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term>
|
<term>
|
||||||
<option>-I</option> <replaceable>path</replaceable>
|
<option>-I</option> <replaceable>path</replaceable>
|
||||||
@ -56,16 +69,6 @@
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
<varlistentry>
|
|
||||||
<term>
|
|
||||||
<option>--all</option>
|
|
||||||
</term>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
Print the values of all options.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsection>
|
</refsection>
|
||||||
<refsection>
|
<refsection>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<author><personname><firstname>Eelco</firstname><surname>Dolstra</surname></personname>
|
<author><personname><firstname>Eelco</firstname><surname>Dolstra</surname></personname>
|
||||||
<contrib>Author</contrib>
|
<contrib>Author</contrib>
|
||||||
</author>
|
</author>
|
||||||
<copyright><year>2007-2019</year><holder>Eelco Dolstra</holder>
|
<copyright><year>2007-2020</year><holder>Eelco Dolstra</holder>
|
||||||
</copyright>
|
</copyright>
|
||||||
</info>
|
</info>
|
||||||
<xi:include href="man-configuration.xml" />
|
<xi:include href="man-configuration.xml" />
|
||||||
|
@ -23,6 +23,13 @@
|
|||||||
Support is planned until the end of October 2020, handing over to 20.09.
|
Support is planned until the end of October 2020, handing over to 20.09.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Linux kernel is updated to branch 5.4 by default (from 4.19).
|
||||||
|
Users of Intel GPUs may prefer to explicitly set branch to 4.19 to avoid some regressions.
|
||||||
|
<programlisting>boot.kernelPackages = pkgs.linuxPackages_4_19;</programlisting>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Postgresql for NixOS service now defaults to v11.
|
Postgresql for NixOS service now defaults to v11.
|
||||||
@ -52,7 +59,7 @@
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<command>nixos-option</command> has been rewritten in C++, speeding it up, improving correctness,
|
<command>nixos-option</command> has been rewritten in C++, speeding it up, improving correctness,
|
||||||
and adding a <option>--all</option> option which prints all options and their values.
|
and adding a <option>-r</option> option which prints all options and their values recursively.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
@ -96,6 +103,13 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
|
|||||||
via <option>services.upower</option>.
|
via <option>services.upower</option>.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
To use Geary you should enable <xref linkend="opt-programs.geary.enable"/> instead of
|
||||||
|
just adding it to <xref linkend="opt-environment.systemPackages"/>.
|
||||||
|
It was created so Geary could function properly outside of GNOME.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
@ -126,7 +140,7 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The <literal>dynamicHosts</literal> option has been removed from the
|
The <literal>dynamicHosts</literal> option has been removed from the
|
||||||
<link linkend="opt-networking.networkmanager.enable">networkd</link>
|
<link linkend="opt-networking.networkmanager.enable">NetworkManager</link>
|
||||||
module. Allowing (multiple) regular users to override host entries
|
module. Allowing (multiple) regular users to override host entries
|
||||||
affecting the whole system opens up a huge attack vector.
|
affecting the whole system opens up a huge attack vector.
|
||||||
There seem to be very rare cases where this might be useful.
|
There seem to be very rare cases where this might be useful.
|
||||||
@ -168,6 +182,12 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
|
|||||||
SDDM, GDM, or using the startx module which uses Xinitrc.
|
SDDM, GDM, or using the startx module which uses Xinitrc.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The Way Cooler wayland compositor has been removed, as the project has been officially canceled.
|
||||||
|
There are no more <literal>way-cooler</literal> attribute and <literal>programs.way-cooler</literal> options.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The BEAM package set has been deleted. You will only find there the different interpreters.
|
The BEAM package set has been deleted. You will only find there the different interpreters.
|
||||||
@ -226,6 +246,23 @@ services.xserver.displayManager.defaultSession = "xfce+icewm";
|
|||||||
upstream issue</link> for more information.
|
upstream issue</link> for more information.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <literal>roundcube</literal> module has been hardened.
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The password of the database is not written world readable in the store any more. If <literal>database.host</literal> is set to <literal>localhost</literal>, then a unix user of the same name as the database will be created and PostreSQL peer authentication will be used, removing the need for a password. Otherwise, a password is still needed and can be provided with the new option <literal>database.passwordFile</literal>, which should be set to the path of a file containing the password and readable by the user <literal>nginx</literal> only. The <literal>database.password</literal> option is insecure and deprecated. Usage of this option will print a warning.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
A random <literal>des_key</literal> is set by default in the configuration of roundcube, instead of using the hardcoded and insecure default. To ensure a clean migration, all users will be logged out when you upgrade to this release.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
The packages <literal>openobex</literal> and <literal>obexftp</literal>
|
The packages <literal>openobex</literal> and <literal>obexftp</literal>
|
||||||
@ -401,6 +438,183 @@ users.users.me =
|
|||||||
the type to <literal>either path (submodule ...)</literal>.
|
the type to <literal>either path (submodule ...)</literal>.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <link linkend="opt-services.buildkite-agent.enable">Buildkite Agent</link>
|
||||||
|
module and corresponding packages have been updated to 3.x.
|
||||||
|
While doing so, the following options have been changed:
|
||||||
|
</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>services.buildkite-agent.meta-data</literal> has been renamed to
|
||||||
|
<link linkend="opt-services.buildkite-agent.tags">services.buildkite-agent.tags</link>,
|
||||||
|
to match upstreams naming for 3.x.
|
||||||
|
Its type has also changed - it now accepts an attrset of strings.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The<literal>services.buildkite-agent.openssh.publicKeyPath</literal> option
|
||||||
|
has been removed, as it's not necessary to deploy public keys to clone private
|
||||||
|
repositories.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>services.buildkite-agent.openssh.privateKeyPath</literal>
|
||||||
|
has been renamed to
|
||||||
|
<link linkend="opt-services.buildkite-agent.privateSshKeyPath">buildkite-agent.privateSshKeyPath</link>,
|
||||||
|
as the whole <literal>openssh</literal> now only contained that single option.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<link linkend="opt-services.buildkite-agent.shell">services.buildkite-agent.shell</link>
|
||||||
|
has been introduced, allowing to specify a custom shell to be used.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <literal>citrix_workspace_19_3_0</literal> package has been removed as
|
||||||
|
it will be EOLed within the lifespan of 20.03. For further information,
|
||||||
|
please refer to the <link xlink:href="https://www.citrix.com/de-de/support/product-lifecycle/milestones/receiver.html">support and maintenance information</link> from upstream.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <literal>gcc5</literal> and <literal>gfortran5</literal> packages have been removed.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <option>services.xserver.displayManager.auto</option> module has been removed.
|
||||||
|
It was only intended for use in internal NixOS tests, and gave the false impression
|
||||||
|
of it being a special display manager when it's actually LightDM.
|
||||||
|
Please use the <xref linkend="opt-services.xserver.displayManager.lightdm.autoLogin"/> options instead,
|
||||||
|
or any other display manager in NixOS as they all support auto-login. If you used this module specifically
|
||||||
|
because it permitted root auto-login you can override the lightdm-autologin pam module like:
|
||||||
|
<programlisting>
|
||||||
|
<link xlink:href="#opt-security.pam.services._name__.text">security.pam.services.lightdm-autologin.text</link> = lib.mkForce ''
|
||||||
|
auth requisite pam_nologin.so
|
||||||
|
auth required pam_succeed_if.so quiet
|
||||||
|
auth required pam_permit.so
|
||||||
|
|
||||||
|
account include lightdm
|
||||||
|
|
||||||
|
password include lightdm
|
||||||
|
|
||||||
|
session include lightdm
|
||||||
|
'';
|
||||||
|
</programlisting>
|
||||||
|
The difference is the:
|
||||||
|
<programlisting>
|
||||||
|
auth required pam_succeed_if.so quiet
|
||||||
|
</programlisting>
|
||||||
|
line, where default it's:
|
||||||
|
<programlisting>
|
||||||
|
auth required pam_succeed_if.so uid >= 1000 quiet
|
||||||
|
</programlisting>
|
||||||
|
not permitting users with uid's below 1000 (like root).
|
||||||
|
All other display managers in NixOS are configured like this.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
There have been lots of improvements to the Mailman module. As
|
||||||
|
a result,
|
||||||
|
</para>
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <option>services.mailman.hyperkittyBaseUrl</option>
|
||||||
|
option has been renamed to <xref
|
||||||
|
linkend="opt-services.mailman.hyperkitty.baseUrl"/>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <option>services.mailman.hyperkittyApiKey</option>
|
||||||
|
option has been removed. This is because having an option
|
||||||
|
for the Hyperkitty API key meant that the API key would be
|
||||||
|
stored in the world-readable Nix store, which was a
|
||||||
|
security vulnerability. A new Hyperkitty API key will be
|
||||||
|
generated the first time the new Hyperkitty service is run,
|
||||||
|
and it will then be persisted outside of the Nix store. To
|
||||||
|
continue using Hyperkitty, you must set <xref
|
||||||
|
linkend="opt-services.mailman.hyperkitty.enable"/> to
|
||||||
|
<literal>true</literal>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Additionally, some Postfix configuration must now be set
|
||||||
|
manually instead of automatically by the Mailman module:
|
||||||
|
<programlisting>
|
||||||
|
<xref linkend="opt-services.postfix.relayDomains"/> = [ "hash:/var/lib/mailman/data/postfix_domains" ];
|
||||||
|
<xref linkend="opt-services.postfix.config"/>.transport_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
|
||||||
|
<xref linkend="opt-services.postfix.config"/>.local_recipient_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
|
||||||
|
</programlisting>
|
||||||
|
This is because some users may want to include other values
|
||||||
|
in these lists as well, and this was not possible if they
|
||||||
|
were set automatically by the Mailman module. It would not
|
||||||
|
have been possible to just concatenate values from multiple
|
||||||
|
modules each setting the values they needed, because the
|
||||||
|
order of elements in the list is significant.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>The LLVM versions 3.5, 3.9 and 4 (including the corresponding CLang versions) have been dropped.</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <option>networking.interfaces.*.preferTempAddress</option> option has
|
||||||
|
been replaced by <option>networking.interfaces.*.tempAddress</option>.
|
||||||
|
The new option allows better control of the IPv6 temporary addresses,
|
||||||
|
including completely disabling them for interfaces where they are not
|
||||||
|
needed.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Rspamd was updated to version 2.2. Read
|
||||||
|
<link xlink:href="https://rspamd.com/doc/migration.html#migration-to-rspamd-20">
|
||||||
|
the upstream migration notes</link> carefully. Please be especially
|
||||||
|
aware that some modules were removed and the default Bayes backend is
|
||||||
|
now Redis.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <literal>*psu</literal> versions of <package>oraclejdk8</package> have been removed
|
||||||
|
as they aren't provided by upstream anymore.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The <option>services.dnscrypt-proxy</option> module has been removed
|
||||||
|
as it used the deprecated version of dnscrypt-proxy. We've added
|
||||||
|
<xref linkend="opt-services.dnscrypt-proxy2.enable"/> to use the supported version.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>qesteidutil</literal> has been deprecated in favor of <literal>qdigidoc</literal>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<package>sqldeveloper_18</package> has been removed as it's not maintained anymore,
|
||||||
|
<package>sqldeveloper</package> has been updated to version <literal>19.4</literal>.
|
||||||
|
Please note that this means that this means that the <package>oraclejdk</package> is now
|
||||||
|
required. For further information please read the
|
||||||
|
<link xlink:href="https://www.oracle.com/technetwork/developer-tools/sql-developer/downloads/sqldev-relnotes-194-5908846.html">release notes</link>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@ -452,9 +666,14 @@ users.users.me =
|
|||||||
As well as this, the options <literal>security.acme.acceptTerms</literal> and either
|
As well as this, the options <literal>security.acme.acceptTerms</literal> and either
|
||||||
<literal>security.acme.email</literal> or <literal>security.acme.certs.<name>.email</literal>
|
<literal>security.acme.email</literal> or <literal>security.acme.certs.<name>.email</literal>
|
||||||
must be set in order to use the ACME module.
|
must be set in order to use the ACME module.
|
||||||
Certificates will be regenerated from new on the next renewal date. The credentials for simp-le are
|
Certificates will be regenerated anew on the next renewal date. The credentials for simp-le are
|
||||||
preserved and thus it is possible to roll back to previous versions without breaking certificate
|
preserved and thus it is possible to roll back to previous versions without breaking certificate
|
||||||
generation.
|
generation.
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
It is now possible to unlock LUKS-Encrypted file systems using a FIDO2 token
|
||||||
|
via <option>boot.initrd.luks.fido2Support</option>.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
@ -17,9 +17,9 @@ in
|
|||||||
else throw "Unknown QEMU serial device for system '${pkgs.stdenv.hostPlatform.system}'";
|
else throw "Unknown QEMU serial device for system '${pkgs.stdenv.hostPlatform.system}'";
|
||||||
|
|
||||||
qemuBinary = qemuPkg: {
|
qemuBinary = qemuPkg: {
|
||||||
x86_64-linux = "${qemuPkg}/bin/qemu-kvm -cpu kvm64";
|
x86_64-linux = "${qemuPkg}/bin/qemu-kvm -cpu host";
|
||||||
armv7l-linux = "${qemuPkg}/bin/qemu-system-arm -enable-kvm -machine virt -cpu host";
|
armv7l-linux = "${qemuPkg}/bin/qemu-system-arm -enable-kvm -machine virt -cpu host";
|
||||||
aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -enable-kvm -machine virt,gic-version=host -cpu host";
|
aarch64-linux = "${qemuPkg}/bin/qemu-system-aarch64 -enable-kvm -machine virt,gic-version=host -cpu host";
|
||||||
x86_64-darwin = "${qemuPkg}/bin/qemu-kvm -cpu kvm64";
|
x86_64-darwin = "${qemuPkg}/bin/qemu-kvm -cpu host";
|
||||||
}.${pkgs.stdenv.hostPlatform.system} or "${qemuPkg}/bin/qemu-kvm";
|
}.${pkgs.stdenv.hostPlatform.system} or "${qemuPkg}/bin/qemu-kvm";
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
#! /somewhere/python3
|
#! /somewhere/python3
|
||||||
from contextlib import contextmanager, _GeneratorContextManager
|
from contextlib import contextmanager, _GeneratorContextManager
|
||||||
|
from queue import Queue, Empty
|
||||||
|
from typing import Tuple, Any, Callable, Dict, Iterator, Optional, List
|
||||||
from xml.sax.saxutils import XMLGenerator
|
from xml.sax.saxutils import XMLGenerator
|
||||||
import _thread
|
import _thread
|
||||||
import atexit
|
import atexit
|
||||||
|
import base64
|
||||||
import os
|
import os
|
||||||
|
import pathlib
|
||||||
import ptpython.repl
|
import ptpython.repl
|
||||||
import pty
|
import pty
|
||||||
from queue import Queue, Empty
|
|
||||||
import re
|
import re
|
||||||
|
import shlex
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -15,9 +19,6 @@ import sys
|
|||||||
import tempfile
|
import tempfile
|
||||||
import time
|
import time
|
||||||
import unicodedata
|
import unicodedata
|
||||||
from typing import Tuple, Any, Callable, Dict, Iterator, Optional, List
|
|
||||||
import shlex
|
|
||||||
import pathlib
|
|
||||||
|
|
||||||
CHAR_TO_KEY = {
|
CHAR_TO_KEY = {
|
||||||
"A": "shift-a",
|
"A": "shift-a",
|
||||||
@ -84,7 +85,7 @@ CHAR_TO_KEY = {
|
|||||||
|
|
||||||
# Forward references
|
# Forward references
|
||||||
nr_tests: int
|
nr_tests: int
|
||||||
nr_succeeded: int
|
failed_tests: list
|
||||||
log: "Logger"
|
log: "Logger"
|
||||||
machines: "List[Machine]"
|
machines: "List[Machine]"
|
||||||
|
|
||||||
@ -221,7 +222,7 @@ class Machine:
|
|||||||
return path
|
return path
|
||||||
|
|
||||||
self.state_dir = create_dir("vm-state-{}".format(self.name))
|
self.state_dir = create_dir("vm-state-{}".format(self.name))
|
||||||
self.shared_dir = create_dir("{}/xchg".format(self.state_dir))
|
self.shared_dir = create_dir("shared-xchg")
|
||||||
|
|
||||||
self.booted = False
|
self.booted = False
|
||||||
self.connected = False
|
self.connected = False
|
||||||
@ -395,7 +396,7 @@ class Machine:
|
|||||||
status_code_pattern = re.compile(r"(.*)\|\!EOF\s+(\d+)")
|
status_code_pattern = re.compile(r"(.*)\|\!EOF\s+(\d+)")
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
chunk = self.shell.recv(4096).decode()
|
chunk = self.shell.recv(4096).decode(errors="ignore")
|
||||||
match = status_code_pattern.match(chunk)
|
match = status_code_pattern.match(chunk)
|
||||||
if match:
|
if match:
|
||||||
output += match[1]
|
output += match[1]
|
||||||
@ -566,6 +567,41 @@ class Machine:
|
|||||||
if ret.returncode != 0:
|
if ret.returncode != 0:
|
||||||
raise Exception("Cannot convert screenshot")
|
raise Exception("Cannot convert screenshot")
|
||||||
|
|
||||||
|
def copy_from_host_via_shell(self, source: str, target: str) -> None:
|
||||||
|
"""Copy a file from the host into the guest by piping it over the
|
||||||
|
shell into the destination file. Works without host-guest shared folder.
|
||||||
|
Prefer copy_from_host for whenever possible.
|
||||||
|
"""
|
||||||
|
with open(source, "rb") as fh:
|
||||||
|
content_b64 = base64.b64encode(fh.read()).decode()
|
||||||
|
self.succeed(
|
||||||
|
f"mkdir -p $(dirname {target})",
|
||||||
|
f"echo -n {content_b64} | base64 -d > {target}",
|
||||||
|
)
|
||||||
|
|
||||||
|
def copy_from_host(self, source: str, target: str) -> None:
|
||||||
|
"""Copy a file from the host into the guest via the `shared_dir` shared
|
||||||
|
among all the VMs (using a temporary directory).
|
||||||
|
"""
|
||||||
|
host_src = pathlib.Path(source)
|
||||||
|
vm_target = pathlib.Path(target)
|
||||||
|
with tempfile.TemporaryDirectory(dir=self.shared_dir) as shared_td:
|
||||||
|
shared_temp = pathlib.Path(shared_td)
|
||||||
|
host_intermediate = shared_temp / host_src.name
|
||||||
|
vm_shared_temp = pathlib.Path("/tmp/shared") / shared_temp.name
|
||||||
|
vm_intermediate = vm_shared_temp / host_src.name
|
||||||
|
|
||||||
|
self.succeed(make_command(["mkdir", "-p", vm_shared_temp]))
|
||||||
|
if host_src.is_dir():
|
||||||
|
shutil.copytree(host_src, host_intermediate)
|
||||||
|
else:
|
||||||
|
shutil.copy(host_src, host_intermediate)
|
||||||
|
self.succeed("sync")
|
||||||
|
self.succeed(make_command(["mkdir", "-p", vm_target.parent]))
|
||||||
|
self.succeed(make_command(["cp", "-r", vm_intermediate, vm_target]))
|
||||||
|
# Make sure the cleanup is synced into VM
|
||||||
|
self.succeed("sync")
|
||||||
|
|
||||||
def copy_from_vm(self, source: str, target_dir: str = "") -> None:
|
def copy_from_vm(self, source: str, target_dir: str = "") -> None:
|
||||||
"""Copy a file from the VM (specified by an in-VM source path) to a path
|
"""Copy a file from the VM (specified by an in-VM source path) to a path
|
||||||
relative to `$out`. The file is copied via the `shared_dir` shared among
|
relative to `$out`. The file is copied via the `shared_dir` shared among
|
||||||
@ -576,7 +612,7 @@ class Machine:
|
|||||||
vm_src = pathlib.Path(source)
|
vm_src = pathlib.Path(source)
|
||||||
with tempfile.TemporaryDirectory(dir=self.shared_dir) as shared_td:
|
with tempfile.TemporaryDirectory(dir=self.shared_dir) as shared_td:
|
||||||
shared_temp = pathlib.Path(shared_td)
|
shared_temp = pathlib.Path(shared_td)
|
||||||
vm_shared_temp = pathlib.Path("/tmp/xchg") / shared_temp.name
|
vm_shared_temp = pathlib.Path("/tmp/shared") / shared_temp.name
|
||||||
vm_intermediate = vm_shared_temp / vm_src.name
|
vm_intermediate = vm_shared_temp / vm_src.name
|
||||||
intermediate = shared_temp / vm_src.name
|
intermediate = shared_temp / vm_src.name
|
||||||
# Copy the file to the shared directory inside VM
|
# Copy the file to the shared directory inside VM
|
||||||
@ -704,7 +740,8 @@ class Machine:
|
|||||||
|
|
||||||
def process_serial_output() -> None:
|
def process_serial_output() -> None:
|
||||||
for _line in self.process.stdout:
|
for _line in self.process.stdout:
|
||||||
line = _line.decode("unicode_escape").replace("\r", "").rstrip()
|
# Ignore undecodable bytes that may occur in boot menus
|
||||||
|
line = _line.decode(errors="ignore").replace("\r", "").rstrip()
|
||||||
eprint("{} # {}".format(self.name, line))
|
eprint("{} # {}".format(self.name, line))
|
||||||
self.logger.enqueue({"msg": line, "machine": self.name})
|
self.logger.enqueue({"msg": line, "machine": self.name})
|
||||||
|
|
||||||
@ -841,23 +878,31 @@ def run_tests() -> None:
|
|||||||
machine.execute("sync")
|
machine.execute("sync")
|
||||||
|
|
||||||
if nr_tests != 0:
|
if nr_tests != 0:
|
||||||
|
nr_succeeded = nr_tests - len(failed_tests)
|
||||||
eprint("{} out of {} tests succeeded".format(nr_succeeded, nr_tests))
|
eprint("{} out of {} tests succeeded".format(nr_succeeded, nr_tests))
|
||||||
if nr_tests > nr_succeeded:
|
if len(failed_tests) > 0:
|
||||||
|
eprint(
|
||||||
|
"The following tests have failed:\n - {}".format(
|
||||||
|
"\n - ".join(failed_tests)
|
||||||
|
)
|
||||||
|
)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def subtest(name: str) -> Iterator[None]:
|
def subtest(name: str) -> Iterator[None]:
|
||||||
global nr_tests
|
global nr_tests
|
||||||
global nr_succeeded
|
global failed_tests
|
||||||
|
|
||||||
with log.nested(name):
|
with log.nested(name):
|
||||||
nr_tests += 1
|
nr_tests += 1
|
||||||
try:
|
try:
|
||||||
yield
|
yield
|
||||||
nr_succeeded += 1
|
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
failed_tests.append(
|
||||||
|
'Test "{}" failed with error: "{}"'.format(name, str(e))
|
||||||
|
)
|
||||||
log.log("error: {}".format(str(e)))
|
log.log("error: {}".format(str(e)))
|
||||||
|
|
||||||
return False
|
return False
|
||||||
@ -879,7 +924,7 @@ if __name__ == "__main__":
|
|||||||
exec("\n".join(machine_eval))
|
exec("\n".join(machine_eval))
|
||||||
|
|
||||||
nr_tests = 0
|
nr_tests = 0
|
||||||
nr_succeeded = 0
|
failed_tests = []
|
||||||
|
|
||||||
@atexit.register
|
@atexit.register
|
||||||
def clean_up() -> None:
|
def clean_up() -> None:
|
||||||
|
@ -155,7 +155,7 @@ in rec {
|
|||||||
--add-flags "''${vms[*]}" \
|
--add-flags "''${vms[*]}" \
|
||||||
${lib.optionalString enableOCR
|
${lib.optionalString enableOCR
|
||||||
"--prefix PATH : '${ocrProg}/bin:${imagemagick_tiff}/bin'"} \
|
"--prefix PATH : '${ocrProg}/bin:${imagemagick_tiff}/bin'"} \
|
||||||
--run "export testScript=\"\$(cat $out/test-script)\"" \
|
--run "export testScript=\"\$(${coreutils}/bin/cat $out/test-script)\"" \
|
||||||
--set VLANS '${toString vlans}'
|
--set VLANS '${toString vlans}'
|
||||||
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-run-vms
|
ln -s ${testDriver}/bin/nixos-test-driver $out/bin/nixos-run-vms
|
||||||
wrapProgram $out/bin/nixos-run-vms \
|
wrapProgram $out/bin/nixos-run-vms \
|
||||||
|
@ -4,7 +4,7 @@ stdenv.mkDerivation rec {
|
|||||||
name = "jquery-ui-1.11.4";
|
name = "jquery-ui-1.11.4";
|
||||||
|
|
||||||
src = fetchurl {
|
src = fetchurl {
|
||||||
url = "http://jqueryui.com/resources/download/${name}.zip";
|
url = "https://jqueryui.com/resources/download/${name}.zip";
|
||||||
sha256 = "0ciyaj1acg08g8hpzqx6whayq206fvf4whksz2pjgxlv207lqgjh";
|
sha256 = "0ciyaj1acg08g8hpzqx6whayq206fvf4whksz2pjgxlv207lqgjh";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ stdenv.mkDerivation rec {
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
homepage = http://jqueryui.com/;
|
homepage = https://jqueryui.com/;
|
||||||
description = "A library of JavaScript widgets and effects";
|
description = "A library of JavaScript widgets and effects";
|
||||||
platforms = stdenv.lib.platforms.all;
|
platforms = stdenv.lib.platforms.all;
|
||||||
};
|
};
|
||||||
|
@ -28,8 +28,6 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
nslcdConfig = writeText "nslcd.conf" ''
|
nslcdConfig = writeText "nslcd.conf" ''
|
||||||
uid nslcd
|
|
||||||
gid nslcd
|
|
||||||
uri ${cfg.server}
|
uri ${cfg.server}
|
||||||
base ${cfg.base}
|
base ${cfg.base}
|
||||||
timelimit ${toString cfg.timeLimit}
|
timelimit ${toString cfg.timeLimit}
|
||||||
@ -282,6 +280,7 @@ in
|
|||||||
Group = "nslcd";
|
Group = "nslcd";
|
||||||
RuntimeDirectory = [ "nslcd" ];
|
RuntimeDirectory = [ "nslcd" ];
|
||||||
PIDFile = "/run/nslcd/nslcd.pid";
|
PIDFile = "/run/nslcd/nslcd.pid";
|
||||||
|
AmbientCapabilities = "CAP_SYS_RESOURCE";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -248,6 +248,9 @@ in {
|
|||||||
security.rtkit.enable = true;
|
security.rtkit.enable = true;
|
||||||
|
|
||||||
systemd.packages = [ overriddenPackage ];
|
systemd.packages = [ overriddenPackage ];
|
||||||
|
|
||||||
|
# PulseAudio is packaged with udev rules to handle various audio device quirks
|
||||||
|
services.udev.packages = [ overriddenPackage ];
|
||||||
})
|
})
|
||||||
|
|
||||||
(mkIf (cfg.extraModules != []) {
|
(mkIf (cfg.extraModules != []) {
|
||||||
|
@ -38,6 +38,7 @@ in
|
|||||||
(mkRenamedOptionModule [ "networking" "dnsExtensionMechanism" ] [ "networking" "resolvconf" "dnsExtensionMechanism" ])
|
(mkRenamedOptionModule [ "networking" "dnsExtensionMechanism" ] [ "networking" "resolvconf" "dnsExtensionMechanism" ])
|
||||||
(mkRenamedOptionModule [ "networking" "extraResolvconfConf" ] [ "networking" "resolvconf" "extraConfig" ])
|
(mkRenamedOptionModule [ "networking" "extraResolvconfConf" ] [ "networking" "resolvconf" "extraConfig" ])
|
||||||
(mkRenamedOptionModule [ "networking" "resolvconfOptions" ] [ "networking" "resolvconf" "extraOptions" ])
|
(mkRenamedOptionModule [ "networking" "resolvconfOptions" ] [ "networking" "resolvconf" "extraOptions" ])
|
||||||
|
(mkRemovedOptionModule [ "networking" "resolvconf" "useHostResolvConf" ] "This option was never used for anything anyways")
|
||||||
];
|
];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
@ -53,15 +54,6 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
useHostResolvConf = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = false;
|
|
||||||
description = ''
|
|
||||||
In containers, whether to use the
|
|
||||||
<filename>resolv.conf</filename> supplied by the host.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
dnsSingleRequest = lib.mkOption {
|
dnsSingleRequest = lib.mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
@ -43,11 +43,11 @@ in
|
|||||||
description = ''
|
description = ''
|
||||||
Whether to enable OpenGL drivers. This is needed to enable
|
Whether to enable OpenGL drivers. This is needed to enable
|
||||||
OpenGL support in X11 systems, as well as for Wayland compositors
|
OpenGL support in X11 systems, as well as for Wayland compositors
|
||||||
like sway, way-cooler and Weston. It is enabled by default
|
like sway and Weston. It is enabled by default
|
||||||
by the corresponding modules, so you do not usually have to
|
by the corresponding modules, so you do not usually have to
|
||||||
set it yourself, only if there is no module for your wayland
|
set it yourself, only if there is no module for your wayland
|
||||||
compositor of choice. See services.xserver.enable,
|
compositor of choice. See services.xserver.enable and
|
||||||
programs.sway.enable, and programs.way-cooler.enable.
|
programs.sway.enable.
|
||||||
'';
|
'';
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
default = false;
|
default = false;
|
||||||
|
@ -49,7 +49,7 @@ in
|
|||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
hardware.openrazer = {
|
hardware.openrazer = {
|
||||||
enable = mkEnableOption "OpenRazer drivers and userspace daemon.";
|
enable = mkEnableOption "OpenRazer drivers and userspace daemon";
|
||||||
|
|
||||||
verboseLogging = mkOption {
|
verboseLogging = mkOption {
|
||||||
type = types.bool;
|
type = types.bool;
|
||||||
|
35
nixos/modules/hardware/tuxedo-keyboard.nix
Normal file
35
nixos/modules/hardware/tuxedo-keyboard.nix
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.hardware.tuxedo-keyboard;
|
||||||
|
tuxedo-keyboard = config.boot.kernelPackages.tuxedo-keyboard;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.hardware.tuxedo-keyboard = {
|
||||||
|
enable = mkEnableOption ''
|
||||||
|
Enables the tuxedo-keyboard driver.
|
||||||
|
|
||||||
|
To configure the driver, pass the options to the <option>boot.kernelParams</option> configuration.
|
||||||
|
There are several parameters you can change. It's best to check at the source code description which options are supported.
|
||||||
|
You can find all the supported parameters at: <link xlink:href="https://github.com/tuxedocomputers/tuxedo-keyboard#kernelparam" />
|
||||||
|
|
||||||
|
In order to use the <literal>custom</literal> lighting with the maximumg brightness and a color of <literal>0xff0a0a</literal> one would put pass <option>boot.kernelParams</option> like this:
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
boot.kernelParams = [
|
||||||
|
"tuxedo_keyboard.mode=0"
|
||||||
|
"tuxedo_keyboard.brightness=255"
|
||||||
|
"tuxedo_keyboard.color_left=0xff0a0a"
|
||||||
|
];
|
||||||
|
</programlisting>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable
|
||||||
|
{
|
||||||
|
boot.kernelModules = ["tuxedo_keyboard"];
|
||||||
|
boot.extraModulePackages = [ tuxedo-keyboard ];
|
||||||
|
};
|
||||||
|
}
|
@ -21,6 +21,19 @@ with lib;
|
|||||||
###### implementation
|
###### implementation
|
||||||
|
|
||||||
config = mkIf config.hardware.usbWwan.enable {
|
config = mkIf config.hardware.usbWwan.enable {
|
||||||
|
# Attaches device specific handlers.
|
||||||
services.udev.packages = with pkgs; [ usb-modeswitch-data ];
|
services.udev.packages = with pkgs; [ usb-modeswitch-data ];
|
||||||
|
|
||||||
|
# Triggered by udev, usb-modeswitch creates systemd services via a
|
||||||
|
# template unit in the usb-modeswitch package.
|
||||||
|
systemd.packages = with pkgs; [ usb-modeswitch ];
|
||||||
|
|
||||||
|
# The systemd service requires the usb-modeswitch-data. The
|
||||||
|
# usb-modeswitch package intends to discover this via the
|
||||||
|
# filesystem at /usr/share/usb_modeswitch, and merge it with user
|
||||||
|
# configuration in /etc/usb_modeswitch.d. Configuring the correct
|
||||||
|
# path in the package is difficult, as it would cause a cyclic
|
||||||
|
# dependency.
|
||||||
|
environment.etc."usb_modeswitch.d".source = "${pkgs.usb-modeswitch-data}/share/usb_modeswitch";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [ ./installation-cd-graphical-kde.nix ];
|
imports = [ ./installation-cd-graphical-plasma5.nix ];
|
||||||
|
|
||||||
boot.kernelPackages = pkgs.linuxPackages_latest;
|
boot.kernelPackages = pkgs.linuxPackages_latest;
|
||||||
}
|
}
|
@ -569,14 +569,18 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
fileSystems."/nix/store" =
|
fileSystems."/nix/store" =
|
||||||
{ fsType = "unionfs-fuse";
|
{ fsType = "overlay";
|
||||||
device = "unionfs";
|
device = "overlay";
|
||||||
options = [ "allow_other" "cow" "nonempty" "chroot=/mnt-root" "max_files=32768" "hide_meta_files" "dirs=/nix/.rw-store=rw:/nix/.ro-store=ro" ];
|
options = [
|
||||||
|
"lowerdir=/nix/.ro-store"
|
||||||
|
"upperdir=/nix/.rw-store/store"
|
||||||
|
"workdir=/nix/.rw-store/work"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
boot.initrd.availableKernelModules = [ "squashfs" "iso9660" "uas" ];
|
boot.initrd.availableKernelModules = [ "squashfs" "iso9660" "uas" "overlay" ];
|
||||||
|
|
||||||
boot.initrd.kernelModules = [ "loop" ];
|
boot.initrd.kernelModules = [ "loop" "overlay" ];
|
||||||
|
|
||||||
# Closures to be copied to the Nix store on the CD, namely the init
|
# Closures to be copied to the Nix store on the CD, namely the init
|
||||||
# script and the top-level system configuration directory.
|
# script and the top-level system configuration directory.
|
||||||
|
@ -50,14 +50,18 @@ with lib;
|
|||||||
};
|
};
|
||||||
|
|
||||||
fileSystems."/nix/store" =
|
fileSystems."/nix/store" =
|
||||||
{ fsType = "unionfs-fuse";
|
{ fsType = "overlay";
|
||||||
device = "unionfs";
|
device = "overlay";
|
||||||
options = [ "allow_other" "cow" "nonempty" "chroot=/mnt-root" "max_files=32768" "hide_meta_files" "dirs=/nix/.rw-store=rw:/nix/.ro-store=ro" ];
|
options = [
|
||||||
|
"lowerdir=/nix/.ro-store"
|
||||||
|
"upperdir=/nix/.rw-store/store"
|
||||||
|
"workdir=/nix/.rw-store/work"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
boot.initrd.availableKernelModules = [ "squashfs" ];
|
boot.initrd.availableKernelModules = [ "squashfs" "overlay" ];
|
||||||
|
|
||||||
boot.initrd.kernelModules = [ "loop" ];
|
boot.initrd.kernelModules = [ "loop" "overlay" ];
|
||||||
|
|
||||||
# Closures to be copied to the Nix store, namely the init
|
# Closures to be copied to the Nix store, namely the init
|
||||||
# script and the top-level system configuration directory.
|
# script and the top-level system configuration directory.
|
||||||
|
@ -131,12 +131,12 @@ bool isOption(Context & ctx, const Value & v)
|
|||||||
if (v.type != tAttrs) {
|
if (v.type != tAttrs) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto & atualType = v.attrs->find(ctx.underscoreType);
|
const auto & actualType = v.attrs->find(ctx.underscoreType);
|
||||||
if (atualType == v.attrs->end()) {
|
if (actualType == v.attrs->end()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Value evaluatedType = evaluateValue(ctx, *atualType->value);
|
Value evaluatedType = evaluateValue(ctx, *actualType->value);
|
||||||
if (evaluatedType.type != tString) {
|
if (evaluatedType.type != tString) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -197,9 +197,107 @@ void recurse(const std::function<bool(const std::string & path, std::variant<Val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calls f on all the option names
|
bool optionTypeIs(Context & ctx, Value & v, const std::string & soughtType)
|
||||||
void mapOptions(const std::function<void(const std::string & path)> & f, Context & ctx, Value root)
|
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
|
const auto & typeLookup = v.attrs->find(ctx.state.sType);
|
||||||
|
if (typeLookup == v.attrs->end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Value type = evaluateValue(ctx, *typeLookup->value);
|
||||||
|
if (type.type != tAttrs) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto & nameLookup = type.attrs->find(ctx.state.sName);
|
||||||
|
if (nameLookup == type.attrs->end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Value name = evaluateValue(ctx, *nameLookup->value);
|
||||||
|
if (name.type != tString) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return name.string.s == soughtType;
|
||||||
|
} catch (Error &) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAggregateOptionType(Context & ctx, Value & v)
|
||||||
|
{
|
||||||
|
return optionTypeIs(ctx, v, "attrsOf") || optionTypeIs(ctx, v, "listOf") || optionTypeIs(ctx, v, "loaOf");
|
||||||
|
}
|
||||||
|
|
||||||
|
MakeError(OptionPathError, EvalError);
|
||||||
|
|
||||||
|
Value getSubOptions(Context & ctx, Value & option)
|
||||||
|
{
|
||||||
|
Value getSubOptions = evaluateValue(ctx, *findAlongAttrPath(ctx.state, "type.getSubOptions", ctx.autoArgs, option));
|
||||||
|
if (getSubOptions.type != tLambda) {
|
||||||
|
throw OptionPathError("Option's type.getSubOptions isn't a function");
|
||||||
|
}
|
||||||
|
Value emptyString{};
|
||||||
|
nix::mkString(emptyString, "");
|
||||||
|
Value v;
|
||||||
|
ctx.state.callFunction(getSubOptions, emptyString, v, nix::Pos{});
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carefully walk an option path, looking for sub-options when a path walks past
|
||||||
|
// an option value.
|
||||||
|
struct FindAlongOptionPathRet
|
||||||
|
{
|
||||||
|
Value option;
|
||||||
|
std::string path;
|
||||||
|
};
|
||||||
|
FindAlongOptionPathRet findAlongOptionPath(Context & ctx, const std::string & path)
|
||||||
|
{
|
||||||
|
Strings tokens = parseAttrPath(path);
|
||||||
|
Value v = ctx.optionsRoot;
|
||||||
|
std::string processedPath;
|
||||||
|
for (auto i = tokens.begin(); i != tokens.end(); i++) {
|
||||||
|
const auto & attr = *i;
|
||||||
|
try {
|
||||||
|
bool lastAttribute = std::next(i) == tokens.end();
|
||||||
|
v = evaluateValue(ctx, v);
|
||||||
|
if (attr.empty()) {
|
||||||
|
throw OptionPathError("empty attribute name");
|
||||||
|
}
|
||||||
|
if (isOption(ctx, v) && optionTypeIs(ctx, v, "submodule")) {
|
||||||
|
v = getSubOptions(ctx, v);
|
||||||
|
}
|
||||||
|
if (isOption(ctx, v) && isAggregateOptionType(ctx, v)) {
|
||||||
|
auto subOptions = getSubOptions(ctx, v);
|
||||||
|
if (lastAttribute && subOptions.attrs->empty()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v = subOptions;
|
||||||
|
// Note that we've consumed attr, but didn't actually use it. This is the path component that's looked
|
||||||
|
// up in the list or attribute set that doesn't name an option -- the "root" in "users.users.root.name".
|
||||||
|
} else if (v.type != tAttrs) {
|
||||||
|
throw OptionPathError("Value is %s while a set was expected", showType(v));
|
||||||
|
} else {
|
||||||
|
const auto & next = v.attrs->find(ctx.state.symbols.create(attr));
|
||||||
|
if (next == v.attrs->end()) {
|
||||||
|
throw OptionPathError("Attribute not found", attr, path);
|
||||||
|
}
|
||||||
|
v = *next->value;
|
||||||
|
}
|
||||||
|
processedPath = appendPath(processedPath, attr);
|
||||||
|
} catch (OptionPathError & e) {
|
||||||
|
throw OptionPathError("At '%s' in path '%s': %s", attr, path, e.msg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {v, processedPath};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calls f on all the option names at or below the option described by `path`.
|
||||||
|
// Note that "the option described by `path`" is not trivial -- if path describes a value inside an aggregate
|
||||||
|
// option (such as users.users.root), the *option* described by that path is one path component shorter
|
||||||
|
// (eg: users.users), which results in f being called on sibling-paths (eg: users.users.nixbld1). If f
|
||||||
|
// doesn't want these, it must do its own filtering.
|
||||||
|
void mapOptions(const std::function<void(const std::string & path)> & f, Context & ctx, const std::string & path)
|
||||||
|
{
|
||||||
|
auto root = findAlongOptionPath(ctx, path);
|
||||||
recurse(
|
recurse(
|
||||||
[f, &ctx](const std::string & path, std::variant<Value, std::exception_ptr> v) {
|
[f, &ctx](const std::string & path, std::variant<Value, std::exception_ptr> v) {
|
||||||
bool isOpt = std::holds_alternative<std::exception_ptr>(v) || isOption(ctx, std::get<Value>(v));
|
bool isOpt = std::holds_alternative<std::exception_ptr>(v) || isOption(ctx, std::get<Value>(v));
|
||||||
@ -208,7 +306,7 @@ void mapOptions(const std::function<void(const std::string & path)> & f, Context
|
|||||||
}
|
}
|
||||||
return !isOpt;
|
return !isOpt;
|
||||||
},
|
},
|
||||||
ctx, root, "");
|
ctx, root.option, root.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calls f on all the config values inside one option.
|
// Calls f on all the config values inside one option.
|
||||||
@ -294,10 +392,12 @@ void printAttrs(Context & ctx, Out & out, Value & v, const std::string & path)
|
|||||||
Out attrsOut(out, "{", "}", v.attrs->size());
|
Out attrsOut(out, "{", "}", v.attrs->size());
|
||||||
for (const auto & a : v.attrs->lexicographicOrder()) {
|
for (const auto & a : v.attrs->lexicographicOrder()) {
|
||||||
std::string name = a->name;
|
std::string name = a->name;
|
||||||
|
if (!forbiddenRecursionName(name)) {
|
||||||
attrsOut << name << " = ";
|
attrsOut << name << " = ";
|
||||||
printValue(ctx, attrsOut, *a->value, appendPath(path, name));
|
printValue(ctx, attrsOut, *a->value, appendPath(path, name));
|
||||||
attrsOut << ";" << Out::sep;
|
attrsOut << ";" << Out::sep;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void multiLineStringEscape(Out & out, const std::string & s)
|
void multiLineStringEscape(Out & out, const std::string & s)
|
||||||
@ -380,17 +480,26 @@ void printConfigValue(Context & ctx, Out & out, const std::string & path, std::v
|
|||||||
out << ";\n";
|
out << ";\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void printAll(Context & ctx, Out & out)
|
// Replace with std::starts_with when C++20 is available
|
||||||
|
bool starts_with(const std::string & s, const std::string & prefix)
|
||||||
|
{
|
||||||
|
return s.size() >= prefix.size() &&
|
||||||
|
std::equal(s.begin(), std::next(s.begin(), prefix.size()), prefix.begin(), prefix.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void printRecursive(Context & ctx, Out & out, const std::string & path)
|
||||||
{
|
{
|
||||||
mapOptions(
|
mapOptions(
|
||||||
[&ctx, &out](const std::string & optionPath) {
|
[&ctx, &out, &path](const std::string & optionPath) {
|
||||||
mapConfigValuesInOption(
|
mapConfigValuesInOption(
|
||||||
[&ctx, &out](const std::string & configPath, std::variant<Value, std::exception_ptr> v) {
|
[&ctx, &out, &path](const std::string & configPath, std::variant<Value, std::exception_ptr> v) {
|
||||||
|
if (starts_with(configPath, path)) {
|
||||||
printConfigValue(ctx, out, configPath, v);
|
printConfigValue(ctx, out, configPath, v);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
optionPath, ctx);
|
optionPath, ctx);
|
||||||
},
|
},
|
||||||
ctx, ctx.optionsRoot);
|
ctx, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printAttr(Context & ctx, Out & out, const std::string & path, Value & root)
|
void printAttr(Context & ctx, Out & out, const std::string & path, Value & root)
|
||||||
@ -450,95 +559,17 @@ void printListing(Out & out, Value & v)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool optionTypeIs(Context & ctx, Value & v, const std::string & soughtType)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
const auto & typeLookup = v.attrs->find(ctx.state.sType);
|
|
||||||
if (typeLookup == v.attrs->end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Value type = evaluateValue(ctx, *typeLookup->value);
|
|
||||||
if (type.type != tAttrs) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto & nameLookup = type.attrs->find(ctx.state.sName);
|
|
||||||
if (nameLookup == type.attrs->end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Value name = evaluateValue(ctx, *nameLookup->value);
|
|
||||||
if (name.type != tString) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return name.string.s == soughtType;
|
|
||||||
} catch (Error &) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isAggregateOptionType(Context & ctx, Value & v)
|
|
||||||
{
|
|
||||||
return optionTypeIs(ctx, v, "attrsOf") || optionTypeIs(ctx, v, "listOf") || optionTypeIs(ctx, v, "loaOf");
|
|
||||||
}
|
|
||||||
|
|
||||||
MakeError(OptionPathError, EvalError);
|
|
||||||
|
|
||||||
Value getSubOptions(Context & ctx, Value & option)
|
|
||||||
{
|
|
||||||
Value getSubOptions = evaluateValue(ctx, *findAlongAttrPath(ctx.state, "type.getSubOptions", ctx.autoArgs, option));
|
|
||||||
if (getSubOptions.type != tLambda) {
|
|
||||||
throw OptionPathError("Option's type.getSubOptions isn't a function");
|
|
||||||
}
|
|
||||||
Value emptyString{};
|
|
||||||
nix::mkString(emptyString, "");
|
|
||||||
Value v;
|
|
||||||
ctx.state.callFunction(getSubOptions, emptyString, v, nix::Pos{});
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Carefully walk an option path, looking for sub-options when a path walks past
|
|
||||||
// an option value.
|
|
||||||
Value findAlongOptionPath(Context & ctx, const std::string & path)
|
|
||||||
{
|
|
||||||
Strings tokens = parseAttrPath(path);
|
|
||||||
Value v = ctx.optionsRoot;
|
|
||||||
for (auto i = tokens.begin(); i != tokens.end(); i++) {
|
|
||||||
const auto & attr = *i;
|
|
||||||
try {
|
|
||||||
bool lastAttribute = std::next(i) == tokens.end();
|
|
||||||
v = evaluateValue(ctx, v);
|
|
||||||
if (attr.empty()) {
|
|
||||||
throw OptionPathError("empty attribute name");
|
|
||||||
}
|
|
||||||
if (isOption(ctx, v) && optionTypeIs(ctx, v, "submodule")) {
|
|
||||||
v = getSubOptions(ctx, v);
|
|
||||||
}
|
|
||||||
if (isOption(ctx, v) && isAggregateOptionType(ctx, v) && !lastAttribute) {
|
|
||||||
v = getSubOptions(ctx, v);
|
|
||||||
// Note that we've consumed attr, but didn't actually use it. This is the path component that's looked
|
|
||||||
// up in the list or attribute set that doesn't name an option -- the "root" in "users.users.root.name".
|
|
||||||
} else if (v.type != tAttrs) {
|
|
||||||
throw OptionPathError("Value is %s while a set was expected", showType(v));
|
|
||||||
} else {
|
|
||||||
const auto & next = v.attrs->find(ctx.state.symbols.create(attr));
|
|
||||||
if (next == v.attrs->end()) {
|
|
||||||
throw OptionPathError("Attribute not found", attr, path);
|
|
||||||
}
|
|
||||||
v = *next->value;
|
|
||||||
}
|
|
||||||
} catch (OptionPathError & e) {
|
|
||||||
throw OptionPathError("At '%s' in path '%s': %s", attr, path, e.msg());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printOne(Context & ctx, Out & out, const std::string & path)
|
void printOne(Context & ctx, Out & out, const std::string & path)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Value option = findAlongOptionPath(ctx, path);
|
auto result = findAlongOptionPath(ctx, path);
|
||||||
|
Value & option = result.option;
|
||||||
option = evaluateValue(ctx, option);
|
option = evaluateValue(ctx, option);
|
||||||
|
if (path != result.path) {
|
||||||
|
out << "Note: showing " << result.path << " instead of " << path << "\n";
|
||||||
|
}
|
||||||
if (isOption(ctx, option)) {
|
if (isOption(ctx, option)) {
|
||||||
printOption(ctx, out, path, option);
|
printOption(ctx, out, result.path, option);
|
||||||
} else {
|
} else {
|
||||||
printListing(out, option);
|
printListing(out, option);
|
||||||
}
|
}
|
||||||
@ -552,7 +583,7 @@ void printOne(Context & ctx, Out & out, const std::string & path)
|
|||||||
|
|
||||||
int main(int argc, char ** argv)
|
int main(int argc, char ** argv)
|
||||||
{
|
{
|
||||||
bool all = false;
|
bool recursive = false;
|
||||||
std::string path = ".";
|
std::string path = ".";
|
||||||
std::string optionsExpr = "(import <nixpkgs/nixos> {}).options";
|
std::string optionsExpr = "(import <nixpkgs/nixos> {}).options";
|
||||||
std::string configExpr = "(import <nixpkgs/nixos> {}).config";
|
std::string configExpr = "(import <nixpkgs/nixos> {}).config";
|
||||||
@ -568,8 +599,8 @@ int main(int argc, char ** argv)
|
|||||||
nix::showManPage("nixos-option");
|
nix::showManPage("nixos-option");
|
||||||
} else if (*arg == "--version") {
|
} else if (*arg == "--version") {
|
||||||
nix::printVersion("nixos-option");
|
nix::printVersion("nixos-option");
|
||||||
} else if (*arg == "--all") {
|
} else if (*arg == "-r" || *arg == "--recursive") {
|
||||||
all = true;
|
recursive = true;
|
||||||
} else if (*arg == "--path") {
|
} else if (*arg == "--path") {
|
||||||
path = nix::getArg(*arg, arg, end);
|
path = nix::getArg(*arg, arg, end);
|
||||||
} else if (*arg == "--options_expr") {
|
} else if (*arg == "--options_expr") {
|
||||||
@ -598,18 +629,12 @@ int main(int argc, char ** argv)
|
|||||||
Context ctx{*state, *myArgs.getAutoArgs(*state), optionsRoot, configRoot};
|
Context ctx{*state, *myArgs.getAutoArgs(*state), optionsRoot, configRoot};
|
||||||
Out out(std::cout);
|
Out out(std::cout);
|
||||||
|
|
||||||
if (all) {
|
auto print = recursive ? printRecursive : printOne;
|
||||||
if (!args.empty()) {
|
|
||||||
throw UsageError("--all cannot be used with arguments");
|
|
||||||
}
|
|
||||||
printAll(ctx, out);
|
|
||||||
} else {
|
|
||||||
if (args.empty()) {
|
if (args.empty()) {
|
||||||
printOne(ctx, out, "");
|
print(ctx, out, "");
|
||||||
}
|
}
|
||||||
for (const auto & arg : args) {
|
for (const auto & arg : args) {
|
||||||
printOne(ctx, out, arg);
|
print(ctx, out, arg);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.state.printStats();
|
ctx.state.printStats();
|
||||||
|
@ -22,7 +22,7 @@ repair=
|
|||||||
profile=/nix/var/nix/profiles/system
|
profile=/nix/var/nix/profiles/system
|
||||||
buildHost=
|
buildHost=
|
||||||
targetHost=
|
targetHost=
|
||||||
maybeSudo=
|
maybeSudo=()
|
||||||
|
|
||||||
while [ "$#" -gt 0 ]; do
|
while [ "$#" -gt 0 ]; do
|
||||||
i="$1"; shift 1
|
i="$1"; shift 1
|
||||||
@ -91,9 +91,7 @@ while [ "$#" -gt 0 ]; do
|
|||||||
shift 1
|
shift 1
|
||||||
;;
|
;;
|
||||||
--use-remote-sudo)
|
--use-remote-sudo)
|
||||||
# note the trailing space
|
maybeSudo=(sudo --)
|
||||||
maybeSudo="sudo "
|
|
||||||
shift 1
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "$0: unknown option \`$i'"
|
echo "$0: unknown option \`$i'"
|
||||||
@ -102,6 +100,10 @@ while [ "$#" -gt 0 ]; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [ -n "$SUDO_USER" ]; then
|
||||||
|
maybeSudo=(sudo --)
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "$buildHost" -a -n "$targetHost" ]; then
|
if [ -z "$buildHost" -a -n "$targetHost" ]; then
|
||||||
buildHost="$targetHost"
|
buildHost="$targetHost"
|
||||||
fi
|
fi
|
||||||
@ -116,17 +118,17 @@ buildHostCmd() {
|
|||||||
if [ -z "$buildHost" ]; then
|
if [ -z "$buildHost" ]; then
|
||||||
"$@"
|
"$@"
|
||||||
elif [ -n "$remoteNix" ]; then
|
elif [ -n "$remoteNix" ]; then
|
||||||
ssh $SSHOPTS "$buildHost" env PATH="$remoteNix:$PATH" "$maybeSudo$@"
|
ssh $SSHOPTS "$buildHost" env PATH="$remoteNix:$PATH" "${maybeSudo[@]}" "$@"
|
||||||
else
|
else
|
||||||
ssh $SSHOPTS "$buildHost" "$maybeSudo$@"
|
ssh $SSHOPTS "$buildHost" "${maybeSudo[@]}" "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
targetHostCmd() {
|
targetHostCmd() {
|
||||||
if [ -z "$targetHost" ]; then
|
if [ -z "$targetHost" ]; then
|
||||||
"$@"
|
"${maybeSudo[@]}" "$@"
|
||||||
else
|
else
|
||||||
ssh $SSHOPTS "$targetHost" "$maybeSudo$@"
|
ssh $SSHOPTS "$targetHost" "${maybeSudo[@]}" "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ in
|
|||||||
couchpotato = 267;
|
couchpotato = 267;
|
||||||
gogs = 268;
|
gogs = 268;
|
||||||
pdns-recursor = 269;
|
pdns-recursor = 269;
|
||||||
kresd = 270;
|
#kresd = 270; # switched to "knot-resolver" with dynamic ID
|
||||||
rpc = 271;
|
rpc = 271;
|
||||||
geoip = 272;
|
geoip = 272;
|
||||||
fcron = 273;
|
fcron = 273;
|
||||||
@ -600,7 +600,7 @@ in
|
|||||||
headphones = 266;
|
headphones = 266;
|
||||||
couchpotato = 267;
|
couchpotato = 267;
|
||||||
gogs = 268;
|
gogs = 268;
|
||||||
kresd = 270;
|
#kresd = 270; # switched to "knot-resolver" with dynamic ID
|
||||||
#rpc = 271; # unused
|
#rpc = 271; # unused
|
||||||
#geoip = 272; # unused
|
#geoip = 272; # unused
|
||||||
fcron = 273;
|
fcron = 273;
|
||||||
|
@ -131,13 +131,6 @@ in {
|
|||||||
++ optional (isFindutils && cfg.pruneNames != []) "findutils locate does not support pruning by directory component"
|
++ optional (isFindutils && cfg.pruneNames != []) "findutils locate does not support pruning by directory component"
|
||||||
++ optional (isFindutils && cfg.pruneBindMounts) "findutils locate does not support skipping bind mounts";
|
++ optional (isFindutils && cfg.pruneBindMounts) "findutils locate does not support skipping bind mounts";
|
||||||
|
|
||||||
# directory creation needs to be separated from main service
|
|
||||||
# because ReadWritePaths fails when the directory doesn't already exist
|
|
||||||
systemd.tmpfiles.rules =
|
|
||||||
let dir = dirOf cfg.output; in
|
|
||||||
mkIf (dir != "/var/cache")
|
|
||||||
[ "d ${dir} 0755 root root -" ];
|
|
||||||
|
|
||||||
systemd.services.update-locatedb =
|
systemd.services.update-locatedb =
|
||||||
{ description = "Update Locate Database";
|
{ description = "Update Locate Database";
|
||||||
path = mkIf (!isMLocate) [ pkgs.su ];
|
path = mkIf (!isMLocate) [ pkgs.su ];
|
||||||
|
@ -6,6 +6,7 @@ let
|
|||||||
cfg = config.system.nixos;
|
cfg = config.system.nixos;
|
||||||
|
|
||||||
gitRepo = "${toString pkgs.path}/.git";
|
gitRepo = "${toString pkgs.path}/.git";
|
||||||
|
gitRepoValid = lib.pathIsGitRepo gitRepo;
|
||||||
gitCommitId = lib.substring 0 7 (commitIdFromGitRepo gitRepo);
|
gitCommitId = lib.substring 0 7 (commitIdFromGitRepo gitRepo);
|
||||||
in
|
in
|
||||||
|
|
||||||
@ -91,8 +92,8 @@ in
|
|||||||
# These defaults are set here rather than up there so that
|
# These defaults are set here rather than up there so that
|
||||||
# changing them would not rebuild the manual
|
# changing them would not rebuild the manual
|
||||||
version = mkDefault (cfg.release + cfg.versionSuffix);
|
version = mkDefault (cfg.release + cfg.versionSuffix);
|
||||||
revision = mkIf (pathIsDirectory gitRepo) (mkDefault gitCommitId);
|
revision = mkIf gitRepoValid (mkDefault gitCommitId);
|
||||||
versionSuffix = mkIf (pathIsDirectory gitRepo) (mkDefault (".git." + gitCommitId));
|
versionSuffix = mkIf gitRepoValid (mkDefault (".git." + gitCommitId));
|
||||||
};
|
};
|
||||||
|
|
||||||
# Generate /etc/os-release. See
|
# Generate /etc/os-release. See
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
./hardware/printers.nix
|
./hardware/printers.nix
|
||||||
./hardware/raid/hpsa.nix
|
./hardware/raid/hpsa.nix
|
||||||
./hardware/steam-hardware.nix
|
./hardware/steam-hardware.nix
|
||||||
|
./hardware/tuxedo-keyboard.nix
|
||||||
./hardware/usb-wwan.nix
|
./hardware/usb-wwan.nix
|
||||||
./hardware/onlykey.nix
|
./hardware/onlykey.nix
|
||||||
./hardware/video/amdgpu.nix
|
./hardware/video/amdgpu.nix
|
||||||
@ -97,6 +98,7 @@
|
|||||||
./programs/autojump.nix
|
./programs/autojump.nix
|
||||||
./programs/bandwhich.nix
|
./programs/bandwhich.nix
|
||||||
./programs/bash/bash.nix
|
./programs/bash/bash.nix
|
||||||
|
./programs/bash-my-aws.nix
|
||||||
./programs/bcc.nix
|
./programs/bcc.nix
|
||||||
./programs/browserpass.nix
|
./programs/browserpass.nix
|
||||||
./programs/captive-browser.nix
|
./programs/captive-browser.nix
|
||||||
@ -116,6 +118,7 @@
|
|||||||
./programs/fish.nix
|
./programs/fish.nix
|
||||||
./programs/freetds.nix
|
./programs/freetds.nix
|
||||||
./programs/fuse.nix
|
./programs/fuse.nix
|
||||||
|
./programs/geary.nix
|
||||||
./programs/gnome-disks.nix
|
./programs/gnome-disks.nix
|
||||||
./programs/gnome-documents.nix
|
./programs/gnome-documents.nix
|
||||||
./programs/gnome-terminal.nix
|
./programs/gnome-terminal.nix
|
||||||
@ -127,6 +130,7 @@
|
|||||||
./programs/java.nix
|
./programs/java.nix
|
||||||
./programs/kbdlight.nix
|
./programs/kbdlight.nix
|
||||||
./programs/less.nix
|
./programs/less.nix
|
||||||
|
./programs/liboping.nix
|
||||||
./programs/light.nix
|
./programs/light.nix
|
||||||
./programs/mosh.nix
|
./programs/mosh.nix
|
||||||
./programs/mininet.nix
|
./programs/mininet.nix
|
||||||
@ -152,13 +156,13 @@
|
|||||||
./programs/system-config-printer.nix
|
./programs/system-config-printer.nix
|
||||||
./programs/thefuck.nix
|
./programs/thefuck.nix
|
||||||
./programs/tmux.nix
|
./programs/tmux.nix
|
||||||
|
./programs/traceroute.nix
|
||||||
./programs/tsm-client.nix
|
./programs/tsm-client.nix
|
||||||
./programs/udevil.nix
|
./programs/udevil.nix
|
||||||
./programs/usbtop.nix
|
./programs/usbtop.nix
|
||||||
./programs/venus.nix
|
./programs/venus.nix
|
||||||
./programs/vim.nix
|
./programs/vim.nix
|
||||||
./programs/wavemon.nix
|
./programs/wavemon.nix
|
||||||
./programs/way-cooler.nix
|
|
||||||
./programs/waybar.nix
|
./programs/waybar.nix
|
||||||
./programs/wireshark.nix
|
./programs/wireshark.nix
|
||||||
./programs/x2goserver.nix
|
./programs/x2goserver.nix
|
||||||
@ -278,6 +282,7 @@
|
|||||||
./services/databases/riak.nix
|
./services/databases/riak.nix
|
||||||
./services/databases/riak-cs.nix
|
./services/databases/riak-cs.nix
|
||||||
./services/databases/stanchion.nix
|
./services/databases/stanchion.nix
|
||||||
|
./services/databases/victoriametrics.nix
|
||||||
./services/databases/virtuoso.nix
|
./services/databases/virtuoso.nix
|
||||||
./services/desktops/accountsservice.nix
|
./services/desktops/accountsservice.nix
|
||||||
./services/desktops/bamf.nix
|
./services/desktops/bamf.nix
|
||||||
@ -424,6 +429,7 @@
|
|||||||
./services/misc/exhibitor.nix
|
./services/misc/exhibitor.nix
|
||||||
./services/misc/felix.nix
|
./services/misc/felix.nix
|
||||||
./services/misc/folding-at-home.nix
|
./services/misc/folding-at-home.nix
|
||||||
|
./services/misc/freeswitch.nix
|
||||||
./services/misc/fstrim.nix
|
./services/misc/fstrim.nix
|
||||||
./services/misc/gammu-smsd.nix
|
./services/misc/gammu-smsd.nix
|
||||||
./services/misc/geoip-updater.nix
|
./services/misc/geoip-updater.nix
|
||||||
@ -524,6 +530,7 @@
|
|||||||
./services/monitoring/prometheus/alertmanager.nix
|
./services/monitoring/prometheus/alertmanager.nix
|
||||||
./services/monitoring/prometheus/exporters.nix
|
./services/monitoring/prometheus/exporters.nix
|
||||||
./services/monitoring/prometheus/pushgateway.nix
|
./services/monitoring/prometheus/pushgateway.nix
|
||||||
|
./services/monitoring/prometheus/xmpp-alerts.nix
|
||||||
./services/monitoring/riemann.nix
|
./services/monitoring/riemann.nix
|
||||||
./services/monitoring/riemann-dash.nix
|
./services/monitoring/riemann-dash.nix
|
||||||
./services/monitoring/riemann-tools.nix
|
./services/monitoring/riemann-tools.nix
|
||||||
@ -577,6 +584,7 @@
|
|||||||
./services/networking/connman.nix
|
./services/networking/connman.nix
|
||||||
./services/networking/consul.nix
|
./services/networking/consul.nix
|
||||||
./services/networking/coredns.nix
|
./services/networking/coredns.nix
|
||||||
|
./services/networking/corerad.nix
|
||||||
./services/networking/coturn.nix
|
./services/networking/coturn.nix
|
||||||
./services/networking/dante.nix
|
./services/networking/dante.nix
|
||||||
./services/networking/ddclient.nix
|
./services/networking/ddclient.nix
|
||||||
@ -584,7 +592,7 @@
|
|||||||
./services/networking/dhcpd.nix
|
./services/networking/dhcpd.nix
|
||||||
./services/networking/dnscache.nix
|
./services/networking/dnscache.nix
|
||||||
./services/networking/dnschain.nix
|
./services/networking/dnschain.nix
|
||||||
./services/networking/dnscrypt-proxy.nix
|
./services/networking/dnscrypt-proxy2.nix
|
||||||
./services/networking/dnscrypt-wrapper.nix
|
./services/networking/dnscrypt-wrapper.nix
|
||||||
./services/networking/dnsdist.nix
|
./services/networking/dnsdist.nix
|
||||||
./services/networking/dnsmasq.nix
|
./services/networking/dnsmasq.nix
|
||||||
@ -735,6 +743,7 @@
|
|||||||
./services/networking/wicd.nix
|
./services/networking/wicd.nix
|
||||||
./services/networking/wireguard.nix
|
./services/networking/wireguard.nix
|
||||||
./services/networking/wpa_supplicant.nix
|
./services/networking/wpa_supplicant.nix
|
||||||
|
./services/networking/xandikos.nix
|
||||||
./services/networking/xinetd.nix
|
./services/networking/xinetd.nix
|
||||||
./services/networking/xl2tpd.nix
|
./services/networking/xl2tpd.nix
|
||||||
./services/networking/xrdp.nix
|
./services/networking/xrdp.nix
|
||||||
@ -802,6 +811,7 @@
|
|||||||
./services/web-apps/codimd.nix
|
./services/web-apps/codimd.nix
|
||||||
./services/web-apps/cryptpad.nix
|
./services/web-apps/cryptpad.nix
|
||||||
./services/web-apps/documize.nix
|
./services/web-apps/documize.nix
|
||||||
|
./services/web-apps/dokuwiki.nix
|
||||||
./services/web-apps/frab.nix
|
./services/web-apps/frab.nix
|
||||||
./services/web-apps/gotify-server.nix
|
./services/web-apps/gotify-server.nix
|
||||||
./services/web-apps/icingaweb2/icingaweb2.nix
|
./services/web-apps/icingaweb2/icingaweb2.nix
|
||||||
@ -859,7 +869,6 @@
|
|||||||
./services/x11/unclutter.nix
|
./services/x11/unclutter.nix
|
||||||
./services/x11/unclutter-xfixes.nix
|
./services/x11/unclutter-xfixes.nix
|
||||||
./services/x11/desktop-managers/default.nix
|
./services/x11/desktop-managers/default.nix
|
||||||
./services/x11/display-managers/auto.nix
|
|
||||||
./services/x11/display-managers/default.nix
|
./services/x11/display-managers/default.nix
|
||||||
./services/x11/display-managers/gdm.nix
|
./services/x11/display-managers/gdm.nix
|
||||||
./services/x11/display-managers/lightdm.nix
|
./services/x11/display-managers/lightdm.nix
|
||||||
@ -869,7 +878,6 @@
|
|||||||
./services/x11/display-managers/xpra.nix
|
./services/x11/display-managers/xpra.nix
|
||||||
./services/x11/fractalart.nix
|
./services/x11/fractalart.nix
|
||||||
./services/x11/hardware/libinput.nix
|
./services/x11/hardware/libinput.nix
|
||||||
./services/x11/hardware/multitouch.nix
|
|
||||||
./services/x11/hardware/synaptics.nix
|
./services/x11/hardware/synaptics.nix
|
||||||
./services/x11/hardware/wacom.nix
|
./services/x11/hardware/wacom.nix
|
||||||
./services/x11/hardware/digimend.nix
|
./services/x11/hardware/digimend.nix
|
||||||
|
25
nixos/modules/programs/bash-my-aws.nix
Normal file
25
nixos/modules/programs/bash-my-aws.nix
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
prg = config.programs;
|
||||||
|
cfg = prg.bash-my-aws;
|
||||||
|
|
||||||
|
initScript = ''
|
||||||
|
eval $(${pkgs.bash-my-aws}/bin/bma-init)
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
programs.bash-my-aws = {
|
||||||
|
enable = mkEnableOption "bash-my-aws";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
environment.systemPackages = with pkgs; [ bash-my-aws ];
|
||||||
|
|
||||||
|
programs.bash.interactiveShellInit = initScript;
|
||||||
|
};
|
||||||
|
}
|
@ -32,6 +32,10 @@ let
|
|||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
lsColors = optionalString cfg.enableLsColors ''
|
||||||
|
eval "$(${pkgs.coreutils}/bin/dircolors -b)"
|
||||||
|
'';
|
||||||
|
|
||||||
bashAliases = concatStringsSep "\n" (
|
bashAliases = concatStringsSep "\n" (
|
||||||
mapAttrsFlatten (k: v: "alias ${k}=${escapeShellArg v}")
|
mapAttrsFlatten (k: v: "alias ${k}=${escapeShellArg v}")
|
||||||
(filterAttrs (k: v: v != null) cfg.shellAliases)
|
(filterAttrs (k: v: v != null) cfg.shellAliases)
|
||||||
@ -127,6 +131,14 @@ in
|
|||||||
type = types.bool;
|
type = types.bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enableLsColors = mkOption {
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Enable extra colors in directory listings.
|
||||||
|
'';
|
||||||
|
type = types.bool;
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -156,6 +168,7 @@ in
|
|||||||
|
|
||||||
${cfg.promptInit}
|
${cfg.promptInit}
|
||||||
${bashCompletion}
|
${bashCompletion}
|
||||||
|
${lsColors}
|
||||||
${bashAliases}
|
${bashAliases}
|
||||||
|
|
||||||
${cfge.interactiveShellInit}
|
${cfge.interactiveShellInit}
|
||||||
|
20
nixos/modules/programs/geary.nix
Normal file
20
nixos/modules/programs/geary.nix
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.programs.geary;
|
||||||
|
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
programs.geary.enable = mkEnableOption "Geary, a Mail client for GNOME 3";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
environment.systemPackages = [ pkgs.gnome3.geary ];
|
||||||
|
programs.dconf.enable = true;
|
||||||
|
services.gnome3.gnome-keyring.enable = true;
|
||||||
|
services.gnome3.gnome-online-accounts.enable = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -96,7 +96,7 @@ in
|
|||||||
# This overrides the systemd user unit shipped with the gnupg package
|
# This overrides the systemd user unit shipped with the gnupg package
|
||||||
systemd.user.services.gpg-agent = mkIf (cfg.agent.pinentryFlavor != null) {
|
systemd.user.services.gpg-agent = mkIf (cfg.agent.pinentryFlavor != null) {
|
||||||
serviceConfig.ExecStart = [ "" ''
|
serviceConfig.ExecStart = [ "" ''
|
||||||
${pkgs.gnupg}/bin/gpg-agent --supervised \
|
${cfg.package}/bin/gpg-agent --supervised \
|
||||||
--pinentry-program ${pkgs.pinentry.${cfg.agent.pinentryFlavor}}/bin/pinentry
|
--pinentry-program ${pkgs.pinentry.${cfg.agent.pinentryFlavor}}/bin/pinentry
|
||||||
'' ];
|
'' ];
|
||||||
};
|
};
|
||||||
|
22
nixos/modules/programs/liboping.nix
Normal file
22
nixos/modules/programs/liboping.nix
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.programs.liboping;
|
||||||
|
in {
|
||||||
|
options.programs.liboping = {
|
||||||
|
enable = mkEnableOption "liboping";
|
||||||
|
};
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
environment.systemPackages = with pkgs; [ liboping ];
|
||||||
|
security.wrappers = mkMerge (map (
|
||||||
|
exec: {
|
||||||
|
"${exec}" = {
|
||||||
|
source = "${pkgs.liboping}/bin/${exec}";
|
||||||
|
capabilities = "cap_net_raw+p";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
) [ "oping" "noping" ]);
|
||||||
|
};
|
||||||
|
}
|
@ -87,7 +87,8 @@ in {
|
|||||||
type = with types; listOf package;
|
type = with types; listOf package;
|
||||||
default = with pkgs; [
|
default = with pkgs; [
|
||||||
swaylock swayidle
|
swaylock swayidle
|
||||||
xwayland rxvt_unicode dmenu
|
xwayland alacritty dmenu
|
||||||
|
rxvt_unicode # For backward compatibility (old default terminal)
|
||||||
];
|
];
|
||||||
defaultText = literalExample ''
|
defaultText = literalExample ''
|
||||||
with pkgs; [ swaylock swayidle xwayland rxvt_unicode dmenu ];
|
with pkgs; [ swaylock swayidle xwayland rxvt_unicode dmenu ];
|
||||||
|
@ -52,7 +52,7 @@ let
|
|||||||
set -s escape-time ${toString cfg.escapeTime}
|
set -s escape-time ${toString cfg.escapeTime}
|
||||||
set -g history-limit ${toString cfg.historyLimit}
|
set -g history-limit ${toString cfg.historyLimit}
|
||||||
|
|
||||||
${cfg.extraTmuxConf}
|
${cfg.extraConfig}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
in {
|
in {
|
||||||
@ -102,7 +102,7 @@ in {
|
|||||||
description = "Time in milliseconds for which tmux waits after an escape is input.";
|
description = "Time in milliseconds for which tmux waits after an escape is input.";
|
||||||
};
|
};
|
||||||
|
|
||||||
extraTmuxConf = mkOption {
|
extraConfig = mkOption {
|
||||||
default = "";
|
default = "";
|
||||||
description = ''
|
description = ''
|
||||||
Additional contents of /etc/tmux.conf
|
Additional contents of /etc/tmux.conf
|
||||||
@ -181,4 +181,8 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
(lib.mkRenamedOptionModule [ "programs" "tmux" "extraTmuxConf" ] [ "programs" "tmux" "extraConfig" ])
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
26
nixos/modules/programs/traceroute.nix
Normal file
26
nixos/modules/programs/traceroute.nix
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.programs.traceroute;
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
programs.traceroute = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether to configure a setcap wrapper for traceroute.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
security.wrappers.traceroute = {
|
||||||
|
source = "${pkgs.traceroute}/bin/traceroute";
|
||||||
|
capabilities = "cap_net_raw+p";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -1,78 +0,0 @@
|
|||||||
{ config, pkgs, lib, ... }:
|
|
||||||
|
|
||||||
with lib;
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.programs.way-cooler;
|
|
||||||
way-cooler = pkgs.way-cooler;
|
|
||||||
|
|
||||||
wcWrapped = pkgs.writeShellScriptBin "way-cooler" ''
|
|
||||||
${cfg.extraSessionCommands}
|
|
||||||
exec ${pkgs.dbus}/bin/dbus-run-session ${way-cooler}/bin/way-cooler
|
|
||||||
'';
|
|
||||||
wcJoined = pkgs.symlinkJoin {
|
|
||||||
name = "way-cooler-wrapped";
|
|
||||||
paths = [ wcWrapped way-cooler ];
|
|
||||||
};
|
|
||||||
configFile = readFile "${way-cooler}/etc/way-cooler/init.lua";
|
|
||||||
spawnBar = ''
|
|
||||||
util.program.spawn_at_startup("lemonbar");
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.programs.way-cooler = {
|
|
||||||
enable = mkEnableOption "way-cooler";
|
|
||||||
|
|
||||||
extraSessionCommands = mkOption {
|
|
||||||
default = "";
|
|
||||||
type = types.lines;
|
|
||||||
example = ''
|
|
||||||
export XKB_DEFAULT_LAYOUT=us,de
|
|
||||||
export XKB_DEFAULT_VARIANT=,nodeadkeys
|
|
||||||
export XKB_DEFAULT_OPTIONS=grp:caps_toggle,
|
|
||||||
'';
|
|
||||||
description = ''
|
|
||||||
Shell commands executed just before way-cooler is started.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
extraPackages = mkOption {
|
|
||||||
type = with types; listOf package;
|
|
||||||
default = with pkgs; [
|
|
||||||
westonLite xwayland dmenu
|
|
||||||
];
|
|
||||||
example = literalExample ''
|
|
||||||
with pkgs; [
|
|
||||||
westonLite xwayland dmenu
|
|
||||||
]
|
|
||||||
'';
|
|
||||||
description = ''
|
|
||||||
Extra packages to be installed system wide.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
enableBar = mkOption {
|
|
||||||
type = types.bool;
|
|
||||||
default = true;
|
|
||||||
description = ''
|
|
||||||
Whether to enable an unofficial bar.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
environment.systemPackages = [ wcJoined ] ++ cfg.extraPackages;
|
|
||||||
|
|
||||||
security.pam.services.wc-lock = {};
|
|
||||||
environment.etc."way-cooler/init.lua".text = ''
|
|
||||||
${configFile}
|
|
||||||
${optionalString cfg.enableBar spawnBar}
|
|
||||||
'';
|
|
||||||
|
|
||||||
hardware.opengl.enable = mkDefault true;
|
|
||||||
fonts.enableDefaultFonts = mkDefault true;
|
|
||||||
programs.dconf.enable = mkDefault true;
|
|
||||||
};
|
|
||||||
|
|
||||||
meta.maintainers = with maintainers; [ gnidorah ];
|
|
||||||
}
|
|
@ -15,6 +15,24 @@ let
|
|||||||
(filterAttrs (k: v: v != null) cfg.shellAliases)
|
(filterAttrs (k: v: v != null) cfg.shellAliases)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
zshStartupNotes = ''
|
||||||
|
# Note that generated /etc/zprofile and /etc/zshrc files do a lot of
|
||||||
|
# non-standard setup to make zsh usable with no configuration by default.
|
||||||
|
#
|
||||||
|
# Which means that unless you explicitly meticulously override everything
|
||||||
|
# generated, interactions between your ~/.zshrc and these files are likely
|
||||||
|
# to be rather surprising.
|
||||||
|
#
|
||||||
|
# Note however, that you can disable loading of the generated /etc/zprofile
|
||||||
|
# and /etc/zshrc (you can't disable loading of /etc/zshenv, but it is
|
||||||
|
# designed to not set anything surprising) by setting `no_global_rcs` option
|
||||||
|
# in ~/.zshenv:
|
||||||
|
#
|
||||||
|
# echo setopt no_global_rcs >> ~/.zshenv
|
||||||
|
#
|
||||||
|
# See "STARTUP/SHUTDOWN FILES" section of zsh(1) for more info.
|
||||||
|
'';
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -69,6 +87,10 @@ in
|
|||||||
|
|
||||||
promptInit = mkOption {
|
promptInit = mkOption {
|
||||||
default = ''
|
default = ''
|
||||||
|
# Note that to manually override this in ~/.zshrc you should run `prompt off`
|
||||||
|
# before setting your PS1 and etc. Otherwise this will likely to interact with
|
||||||
|
# your ~/.zshrc configuration in unexpected ways as the default prompt sets
|
||||||
|
# a lot of different prompt variables.
|
||||||
autoload -U promptinit && promptinit && prompt walters && setopt prompt_sp
|
autoload -U promptinit && promptinit && prompt walters && setopt prompt_sp
|
||||||
'';
|
'';
|
||||||
description = ''
|
description = ''
|
||||||
@ -100,7 +122,8 @@ in
|
|||||||
];
|
];
|
||||||
example = [ "EXTENDED_HISTORY" "RM_STAR_WAIT" ];
|
example = [ "EXTENDED_HISTORY" "RM_STAR_WAIT" ];
|
||||||
description = ''
|
description = ''
|
||||||
Configure zsh options.
|
Configure zsh options. See
|
||||||
|
<citerefentry><refentrytitle>zshoptions</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -147,6 +170,14 @@ in
|
|||||||
. ${config.system.build.setEnvironment}
|
. ${config.system.build.setEnvironment}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
HELPDIR="${pkgs.zsh}/share/zsh/$ZSH_VERSION/help"
|
||||||
|
|
||||||
|
# Tell zsh how to find installed completions.
|
||||||
|
for p in ''${(z)NIX_PROFILES}; do
|
||||||
|
fpath+=($p/share/zsh/site-functions $p/share/zsh/$ZSH_VERSION/functions $p/share/zsh/vendor-completions)
|
||||||
|
done
|
||||||
|
|
||||||
|
# Setup custom shell init stuff.
|
||||||
${cfge.shellInit}
|
${cfge.shellInit}
|
||||||
|
|
||||||
${cfg.shellInit}
|
${cfg.shellInit}
|
||||||
@ -161,11 +192,14 @@ in
|
|||||||
''
|
''
|
||||||
# /etc/zprofile: DO NOT EDIT -- this file has been generated automatically.
|
# /etc/zprofile: DO NOT EDIT -- this file has been generated automatically.
|
||||||
# This file is read for login shells.
|
# This file is read for login shells.
|
||||||
|
#
|
||||||
|
${zshStartupNotes}
|
||||||
|
|
||||||
# Only execute this file once per shell.
|
# Only execute this file once per shell.
|
||||||
if [ -n "$__ETC_ZPROFILE_SOURCED" ]; then return; fi
|
if [ -n "$__ETC_ZPROFILE_SOURCED" ]; then return; fi
|
||||||
__ETC_ZPROFILE_SOURCED=1
|
__ETC_ZPROFILE_SOURCED=1
|
||||||
|
|
||||||
|
# Setup custom login shell init stuff.
|
||||||
${cfge.loginShellInit}
|
${cfge.loginShellInit}
|
||||||
|
|
||||||
${cfg.loginShellInit}
|
${cfg.loginShellInit}
|
||||||
@ -180,38 +214,44 @@ in
|
|||||||
''
|
''
|
||||||
# /etc/zshrc: DO NOT EDIT -- this file has been generated automatically.
|
# /etc/zshrc: DO NOT EDIT -- this file has been generated automatically.
|
||||||
# This file is read for interactive shells.
|
# This file is read for interactive shells.
|
||||||
|
#
|
||||||
|
${zshStartupNotes}
|
||||||
|
|
||||||
# Only execute this file once per shell.
|
# Only execute this file once per shell.
|
||||||
if [ -n "$__ETC_ZSHRC_SOURCED" -o -n "$NOSYSZSHRC" ]; then return; fi
|
if [ -n "$__ETC_ZSHRC_SOURCED" -o -n "$NOSYSZSHRC" ]; then return; fi
|
||||||
__ETC_ZSHRC_SOURCED=1
|
__ETC_ZSHRC_SOURCED=1
|
||||||
|
|
||||||
. /etc/zinputrc
|
${optionalString (cfg.setOptions != []) ''
|
||||||
|
# Set zsh options.
|
||||||
|
setopt ${concatStringsSep " " cfg.setOptions}
|
||||||
|
''}
|
||||||
|
|
||||||
# Don't export these, otherwise other shells (bash) will try to use same histfile
|
# Setup command line history.
|
||||||
|
# Don't export these, otherwise other shells (bash) will try to use same HISTFILE.
|
||||||
SAVEHIST=${toString cfg.histSize}
|
SAVEHIST=${toString cfg.histSize}
|
||||||
HISTSIZE=${toString cfg.histSize}
|
HISTSIZE=${toString cfg.histSize}
|
||||||
HISTFILE=${cfg.histFile}
|
HISTFILE=${cfg.histFile}
|
||||||
|
|
||||||
HELPDIR="${pkgs.zsh}/share/zsh/$ZSH_VERSION/help"
|
# Configure sane keyboard defaults.
|
||||||
|
. /etc/zinputrc
|
||||||
|
|
||||||
# Tell zsh how to find installed completions
|
${optionalString cfg.enableGlobalCompInit ''
|
||||||
for p in ''${(z)NIX_PROFILES}; do
|
# Enable autocompletion.
|
||||||
fpath+=($p/share/zsh/site-functions $p/share/zsh/$ZSH_VERSION/functions $p/share/zsh/vendor-completions)
|
autoload -U compinit && compinit
|
||||||
done
|
''}
|
||||||
|
|
||||||
${optionalString cfg.enableGlobalCompInit "autoload -U compinit && compinit"}
|
|
||||||
|
|
||||||
|
# Setup custom interactive shell init stuff.
|
||||||
${cfge.interactiveShellInit}
|
${cfge.interactiveShellInit}
|
||||||
|
|
||||||
${cfg.interactiveShellInit}
|
${cfg.interactiveShellInit}
|
||||||
|
|
||||||
${optionalString (cfg.setOptions != []) "setopt ${concatStringsSep " " cfg.setOptions}"}
|
# Setup aliases.
|
||||||
|
|
||||||
${zshAliases}
|
${zshAliases}
|
||||||
|
|
||||||
|
# Setup prompt.
|
||||||
${cfg.promptInit}
|
${cfg.promptInit}
|
||||||
|
|
||||||
# Need to disable features to support TRAMP
|
# Disable some features to support TRAMP.
|
||||||
if [ "$TERM" = dumb ]; then
|
if [ "$TERM" = dumb ]; then
|
||||||
unsetopt zle prompt_cr prompt_subst
|
unsetopt zle prompt_cr prompt_subst
|
||||||
unset RPS1 RPROMPT
|
unset RPS1 RPROMPT
|
||||||
|
@ -27,6 +27,21 @@ with lib;
|
|||||||
(mkRemovedOptionModule [ "services.osquery" ] "The osquery module has been removed")
|
(mkRemovedOptionModule [ "services.osquery" ] "The osquery module has been removed")
|
||||||
(mkRemovedOptionModule [ "services.fourStore" ] "The fourStore module has been removed")
|
(mkRemovedOptionModule [ "services.fourStore" ] "The fourStore module has been removed")
|
||||||
(mkRemovedOptionModule [ "services.fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed")
|
(mkRemovedOptionModule [ "services.fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed")
|
||||||
|
(mkRemovedOptionModule [ "programs" "way-cooler" ] ("way-cooler is abandoned by its author: " +
|
||||||
|
"https://way-cooler.org/blog/2020/01/09/way-cooler-post-mortem.html"))
|
||||||
|
(mkRemovedOptionModule [ "services" "xserver" "multitouch" ] ''
|
||||||
|
services.xserver.multitouch (which uses xf86_input_mtrack) has been removed
|
||||||
|
as the underlying package isn't being maintained. Working alternatives are
|
||||||
|
libinput and synaptics.
|
||||||
|
'')
|
||||||
|
(mkRemovedOptionModule [ "services" "xserver" "displayManager" "auto" ] ''
|
||||||
|
The services.xserver.displayManager.auto module has been removed
|
||||||
|
because it was only intended for use in internal NixOS tests, and gave the
|
||||||
|
false impression of it being a special display manager when it's actually
|
||||||
|
LightDM. Please use the services.xserver.displayManager.lightdm.autoLogin options
|
||||||
|
instead, or any other display manager in NixOS as they all support auto-login.
|
||||||
|
'')
|
||||||
|
(mkRemovedOptionModule [ "services" "dnscrypt-proxy" ] "Use services.dnscrypt-proxy2 instead")
|
||||||
|
|
||||||
# Do NOT add any option renames here, see top of the file
|
# Do NOT add any option renames here, see top of the file
|
||||||
];
|
];
|
||||||
|
@ -12,7 +12,7 @@ let
|
|||||||
ikey=${cfg.ikey}
|
ikey=${cfg.ikey}
|
||||||
skey=${cfg.skey}
|
skey=${cfg.skey}
|
||||||
host=${cfg.host}
|
host=${cfg.host}
|
||||||
${optionalString (cfg.group != "") ("group="+cfg.group)}
|
${optionalString (cfg.groups != "") ("groups="+cfg.groups)}
|
||||||
failmode=${cfg.failmode}
|
failmode=${cfg.failmode}
|
||||||
pushinfo=${boolToStr cfg.pushinfo}
|
pushinfo=${boolToStr cfg.pushinfo}
|
||||||
autopush=${boolToStr cfg.autopush}
|
autopush=${boolToStr cfg.autopush}
|
||||||
@ -42,6 +42,10 @@ let
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
imports = [
|
||||||
|
(mkRenamedOptionModule [ "security" "duosec" "group" ] [ "security" "duosec" "groups" ])
|
||||||
|
];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
security.duosec = {
|
security.duosec = {
|
||||||
ssh.enable = mkOption {
|
ssh.enable = mkOption {
|
||||||
@ -71,10 +75,16 @@ in
|
|||||||
description = "Duo API hostname.";
|
description = "Duo API hostname.";
|
||||||
};
|
};
|
||||||
|
|
||||||
group = mkOption {
|
groups = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "";
|
default = "";
|
||||||
description = "Use Duo authentication for users only in this group.";
|
example = "users,!wheel,!*admin guests";
|
||||||
|
description = ''
|
||||||
|
If specified, Duo authentication is required only for users
|
||||||
|
whose primary group or supplementary group list matches one
|
||||||
|
of the space-separated pattern lists. Refer to
|
||||||
|
<link xlink:href="https://duo.com/docs/duounix"/> for details.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
failmode = mkOption {
|
failmode = mkOption {
|
||||||
|
@ -98,8 +98,8 @@ in {
|
|||||||
will be merged into these options by RabbitMQ at runtime to
|
will be merged into these options by RabbitMQ at runtime to
|
||||||
form the final configuration.
|
form the final configuration.
|
||||||
|
|
||||||
See http://www.rabbitmq.com/configure.html#config-items
|
See https://www.rabbitmq.com/configure.html#config-items
|
||||||
For the distinct formats, see http://www.rabbitmq.com/configure.html#config-file-formats
|
For the distinct formats, see https://www.rabbitmq.com/configure.html#config-file-formats
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -116,8 +116,8 @@ in {
|
|||||||
The contents of this option will be merged into the <literal>configItems</literal>
|
The contents of this option will be merged into the <literal>configItems</literal>
|
||||||
by RabbitMQ at runtime to form the final configuration.
|
by RabbitMQ at runtime to form the final configuration.
|
||||||
|
|
||||||
See the second table on http://www.rabbitmq.com/configure.html#config-items
|
See the second table on https://www.rabbitmq.com/configure.html#config-items
|
||||||
For the distinct formats, see http://www.rabbitmq.com/configure.html#config-file-formats
|
For the distinct formats, see https://www.rabbitmq.com/configure.html#config-file-formats
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -165,7 +165,10 @@ in {
|
|||||||
after = [ "network.target" "epmd.socket" ];
|
after = [ "network.target" "epmd.socket" ];
|
||||||
wants = [ "network.target" "epmd.socket" ];
|
wants = [ "network.target" "epmd.socket" ];
|
||||||
|
|
||||||
path = [ cfg.package pkgs.procps ];
|
path = [
|
||||||
|
cfg.package
|
||||||
|
pkgs.coreutils # mkdir/chown/chmod for preStart
|
||||||
|
];
|
||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
RABBITMQ_MNESIA_BASE = "${cfg.dataDir}/mnesia";
|
RABBITMQ_MNESIA_BASE = "${cfg.dataDir}/mnesia";
|
||||||
|
@ -103,6 +103,34 @@ in
|
|||||||
Create the repository if it doesn't exist.
|
Create the repository if it doesn't exist.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pruneOpts = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
A list of options (--keep-* et al.) for 'restic forget
|
||||||
|
--prune', to automatically prune old snapshots. The
|
||||||
|
'forget' command is run *after* the 'backup' command, so
|
||||||
|
keep that in mind when constructing the --keep-* options.
|
||||||
|
'';
|
||||||
|
example = [
|
||||||
|
"--keep-daily 7"
|
||||||
|
"--keep-weekly 5"
|
||||||
|
"--keep-monthly 12"
|
||||||
|
"--keep-yearly 75"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
dynamicFilesFrom = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
A script that produces a list of files to back up. The
|
||||||
|
results of this command are given to the '--files-from'
|
||||||
|
option.
|
||||||
|
'';
|
||||||
|
example = "find /home/matt/git -type d -name .git";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
default = {};
|
default = {};
|
||||||
@ -134,25 +162,41 @@ in
|
|||||||
let
|
let
|
||||||
extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions;
|
extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions;
|
||||||
resticCmd = "${pkgs.restic}/bin/restic${extraOptions}";
|
resticCmd = "${pkgs.restic}/bin/restic${extraOptions}";
|
||||||
|
filesFromTmpFile = "/run/restic-backups-${name}/includes";
|
||||||
|
backupPaths = if (backup.dynamicFilesFrom == null)
|
||||||
|
then concatStringsSep " " backup.paths
|
||||||
|
else "--files-from ${filesFromTmpFile}";
|
||||||
|
pruneCmd = optionals (builtins.length backup.pruneOpts > 0) [
|
||||||
|
( resticCmd + " forget --prune " + (concatStringsSep " " backup.pruneOpts) )
|
||||||
|
( resticCmd + " check" )
|
||||||
|
];
|
||||||
in nameValuePair "restic-backups-${name}" ({
|
in nameValuePair "restic-backups-${name}" ({
|
||||||
environment = {
|
environment = {
|
||||||
RESTIC_PASSWORD_FILE = backup.passwordFile;
|
RESTIC_PASSWORD_FILE = backup.passwordFile;
|
||||||
RESTIC_REPOSITORY = backup.repository;
|
RESTIC_REPOSITORY = backup.repository;
|
||||||
};
|
};
|
||||||
path = with pkgs; [
|
path = [ pkgs.openssh ];
|
||||||
openssh
|
|
||||||
];
|
|
||||||
restartIfChanged = false;
|
restartIfChanged = false;
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
ExecStart = "${resticCmd} backup ${concatStringsSep " " backup.extraBackupArgs} ${concatStringsSep " " backup.paths}";
|
ExecStart = [ "${resticCmd} backup ${concatStringsSep " " backup.extraBackupArgs} ${backupPaths}" ] ++ pruneCmd;
|
||||||
User = backup.user;
|
User = backup.user;
|
||||||
|
RuntimeDirectory = "restic-backups-${name}";
|
||||||
} // optionalAttrs (backup.s3CredentialsFile != null) {
|
} // optionalAttrs (backup.s3CredentialsFile != null) {
|
||||||
EnvironmentFile = backup.s3CredentialsFile;
|
EnvironmentFile = backup.s3CredentialsFile;
|
||||||
};
|
};
|
||||||
} // optionalAttrs backup.initialize {
|
} // optionalAttrs (backup.initialize || backup.dynamicFilesFrom != null) {
|
||||||
preStart = ''
|
preStart = ''
|
||||||
|
${optionalString (backup.initialize) ''
|
||||||
${resticCmd} snapshots || ${resticCmd} init
|
${resticCmd} snapshots || ${resticCmd} init
|
||||||
|
''}
|
||||||
|
${optionalString (backup.dynamicFilesFrom != null) ''
|
||||||
|
${pkgs.writeScript "dynamicFilesFromScript" backup.dynamicFilesFrom} > ${filesFromTmpFile}
|
||||||
|
''}
|
||||||
|
'';
|
||||||
|
} // optionalAttrs (backup.dynamicFilesFrom != null) {
|
||||||
|
postStart = ''
|
||||||
|
rm ${filesFromTmpFile}
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
) config.services.restic.backups;
|
) config.services.restic.backups;
|
||||||
|
@ -20,6 +20,7 @@ let
|
|||||||
size = 2048;
|
size = 2048;
|
||||||
};
|
};
|
||||||
CN = top.masterAddress;
|
CN = top.masterAddress;
|
||||||
|
hosts = cfg.cfsslAPIExtraSANs;
|
||||||
});
|
});
|
||||||
|
|
||||||
cfsslAPITokenBaseName = "apitoken.secret";
|
cfsslAPITokenBaseName = "apitoken.secret";
|
||||||
@ -66,6 +67,15 @@ in
|
|||||||
type = bool;
|
type = bool;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
cfsslAPIExtraSANs = mkOption {
|
||||||
|
description = ''
|
||||||
|
Extra x509 Subject Alternative Names to be added to the cfssl API webserver TLS cert.
|
||||||
|
'';
|
||||||
|
default = [];
|
||||||
|
example = [ "subdomain.example.com" ];
|
||||||
|
type = listOf str;
|
||||||
|
};
|
||||||
|
|
||||||
genCfsslAPIToken = mkOption {
|
genCfsslAPIToken = mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
Whether to automatically generate cfssl API-token secret,
|
Whether to automatically generate cfssl API-token secret,
|
||||||
|
@ -50,8 +50,8 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
runtimePackages = mkOption {
|
runtimePackages = mkOption {
|
||||||
default = [ pkgs.bash pkgs.nix ];
|
default = [ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ];
|
||||||
defaultText = "[ pkgs.bash pkgs.nix ]";
|
defaultText = "[ pkgs.bash pkgs.gnutar pkgs.gzip pkgs.git pkgs.nix ]";
|
||||||
description = "Add programs to the buildkite-agent environment";
|
description = "Add programs to the buildkite-agent environment";
|
||||||
type = types.listOf types.package;
|
type = types.listOf types.package;
|
||||||
};
|
};
|
||||||
@ -74,13 +74,12 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
meta-data = mkOption {
|
tags = mkOption {
|
||||||
type = types.str;
|
type = types.attrsOf types.str;
|
||||||
default = "";
|
default = {};
|
||||||
example = "queue=default,docker=true,ruby2=true";
|
example = { queue = "default"; docker = "true"; ruby2 ="true"; };
|
||||||
description = ''
|
description = ''
|
||||||
Meta data for the agent. This is a comma-separated list of
|
Tags for the agent.
|
||||||
<code>key=value</code> pairs.
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -93,26 +92,20 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
openssh =
|
privateSshKeyPath = mkOption {
|
||||||
{ privateKeyPath = mkOption {
|
type = types.nullOr types.path;
|
||||||
type = types.path;
|
default = null;
|
||||||
|
## maximum care is taken so that secrets (ssh keys and the CI token)
|
||||||
|
## don't end up in the Nix store.
|
||||||
|
apply = final: if final == null then null else toString final;
|
||||||
|
|
||||||
description = ''
|
description = ''
|
||||||
Private agent key.
|
OpenSSH private key
|
||||||
|
|
||||||
A run-time path to the key file, which is supposed to be provisioned
|
A run-time path to the key file, which is supposed to be provisioned
|
||||||
outside of Nix store.
|
outside of Nix store.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
publicKeyPath = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
description = ''
|
|
||||||
Public agent key.
|
|
||||||
|
|
||||||
A run-time path to the key file, which is supposed to be provisioned
|
|
||||||
outside of Nix store.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
hooks = mkHookOptions [
|
hooks = mkHookOptions [
|
||||||
{ name = "checkout";
|
{ name = "checkout";
|
||||||
@ -181,12 +174,20 @@ in
|
|||||||
instead.
|
instead.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
shell = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "${pkgs.bash}/bin/bash -e -c";
|
||||||
|
description = ''
|
||||||
|
Command that buildkite-agent 3 will execute when it spawns a shell.
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf config.services.buildkite-agent.enable {
|
config = mkIf config.services.buildkite-agent.enable {
|
||||||
users.users.buildkite-agent =
|
users.users.buildkite-agent = {
|
||||||
{ name = "buildkite-agent";
|
name = "buildkite-agent";
|
||||||
home = cfg.dataDir;
|
home = cfg.dataDir;
|
||||||
createHome = true;
|
createHome = true;
|
||||||
description = "Buildkite agent user";
|
description = "Buildkite agent user";
|
||||||
@ -210,17 +211,18 @@ in
|
|||||||
## don't end up in the Nix store.
|
## don't end up in the Nix store.
|
||||||
preStart = let
|
preStart = let
|
||||||
sshDir = "${cfg.dataDir}/.ssh";
|
sshDir = "${cfg.dataDir}/.ssh";
|
||||||
|
tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (name: value: "${name}=${value}") cfg.tags);
|
||||||
in
|
in
|
||||||
''
|
optionalString (cfg.privateSshKeyPath != null) ''
|
||||||
mkdir -m 0700 -p "${sshDir}"
|
mkdir -m 0700 -p "${sshDir}"
|
||||||
cp -f "${toString cfg.openssh.privateKeyPath}" "${sshDir}/id_rsa"
|
cp -f "${toString cfg.privateSshKeyPath}" "${sshDir}/id_rsa"
|
||||||
cp -f "${toString cfg.openssh.publicKeyPath}" "${sshDir}/id_rsa.pub"
|
chmod 600 "${sshDir}"/id_rsa
|
||||||
chmod 600 "${sshDir}"/id_rsa*
|
'' + ''
|
||||||
|
|
||||||
cat > "${cfg.dataDir}/buildkite-agent.cfg" <<EOF
|
cat > "${cfg.dataDir}/buildkite-agent.cfg" <<EOF
|
||||||
token="$(cat ${toString cfg.tokenPath})"
|
token="$(cat ${toString cfg.tokenPath})"
|
||||||
name="${cfg.name}"
|
name="${cfg.name}"
|
||||||
meta-data="${cfg.meta-data}"
|
shell="${cfg.shell}"
|
||||||
|
tags="${tagStr}"
|
||||||
build-path="${cfg.dataDir}/builds"
|
build-path="${cfg.dataDir}/builds"
|
||||||
hooks-path="${cfg.hooksPath}"
|
hooks-path="${cfg.hooksPath}"
|
||||||
${cfg.extraConfig}
|
${cfg.extraConfig}
|
||||||
@ -228,11 +230,14 @@ in
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
serviceConfig =
|
serviceConfig =
|
||||||
{ ExecStart = "${pkgs.buildkite-agent}/bin/buildkite-agent start --config /var/lib/buildkite-agent/buildkite-agent.cfg";
|
{ ExecStart = "${cfg.package}/bin/buildkite-agent start --config /var/lib/buildkite-agent/buildkite-agent.cfg";
|
||||||
User = "buildkite-agent";
|
User = "buildkite-agent";
|
||||||
RestartSec = 5;
|
RestartSec = 5;
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
TimeoutSec = 10;
|
TimeoutSec = 10;
|
||||||
|
# set a long timeout to give buildkite-agent a chance to finish current builds
|
||||||
|
TimeoutStopSec = "2 min";
|
||||||
|
KillMode = "mixed";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -247,7 +252,10 @@ in
|
|||||||
};
|
};
|
||||||
imports = [
|
imports = [
|
||||||
(mkRenamedOptionModule [ "services" "buildkite-agent" "token" ] [ "services" "buildkite-agent" "tokenPath" ])
|
(mkRenamedOptionModule [ "services" "buildkite-agent" "token" ] [ "services" "buildkite-agent" "tokenPath" ])
|
||||||
(mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKey" ] [ "services" "buildkite-agent" "openssh" "privateKeyPath" ])
|
(mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKey" ] [ "services" "buildkite-agent" "privateSshKeyPath" ])
|
||||||
(mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "publicKey" ] [ "services" "buildkite-agent" "openssh" "publicKeyPath" ])
|
(mkRenamedOptionModule [ "services" "buildkite-agent" "openssh" "privateKeyPath" ] [ "services" "buildkite-agent" "privateSshKeyPath" ])
|
||||||
|
(mkRemovedOptionModule [ "services" "buildkite-agent" "openssh" "publicKey" ] "SSH public keys aren't necessary to clone private repos.")
|
||||||
|
(mkRemovedOptionModule [ "services" "buildkite-agent" "openssh" "publicKeyPath" ] "SSH public keys aren't necessary to clone private repos.")
|
||||||
|
(mkRenamedOptionModule [ "services" "buildkite-agent" "meta-data"] [ "services" "buildkite-agent" "tags" ])
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ in
|
|||||||
|
|
||||||
buildMachinesFiles = mkOption {
|
buildMachinesFiles = mkOption {
|
||||||
type = types.listOf types.path;
|
type = types.listOf types.path;
|
||||||
default = [ "/etc/nix/machines" ];
|
default = optional (config.nix.buildMachines != []) "/etc/nix/machines";
|
||||||
example = [ "/etc/nix/machines" "/var/lib/hydra/provisioner/machines" ];
|
example = [ "/etc/nix/machines" "/var/lib/hydra/provisioner/machines" ];
|
||||||
description = "List of files containing build machines.";
|
description = "List of files containing build machines.";
|
||||||
};
|
};
|
||||||
@ -333,7 +333,7 @@ in
|
|||||||
IN_SYSTEMD = "1"; # to get log severity levels
|
IN_SYSTEMD = "1"; # to get log severity levels
|
||||||
};
|
};
|
||||||
serviceConfig =
|
serviceConfig =
|
||||||
{ ExecStart = "@${cfg.package}/bin/hydra-queue-runner hydra-queue-runner -v --option build-use-substitutes ${boolToString cfg.useSubstitutes}";
|
{ ExecStart = "@${cfg.package}/bin/hydra-queue-runner hydra-queue-runner -v";
|
||||||
ExecStopPost = "${cfg.package}/bin/hydra-queue-runner --unlock";
|
ExecStopPost = "${cfg.package}/bin/hydra-queue-runner --unlock";
|
||||||
User = "hydra-queue-runner";
|
User = "hydra-queue-runner";
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
|
70
nixos/modules/services/databases/victoriametrics.nix
Normal file
70
nixos/modules/services/databases/victoriametrics.nix
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
let cfg = config.services.victoriametrics; in
|
||||||
|
{
|
||||||
|
options.services.victoriametrics = with lib; {
|
||||||
|
enable = mkEnableOption "victoriametrics";
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.victoriametrics;
|
||||||
|
defaultText = "pkgs.victoriametrics";
|
||||||
|
description = ''
|
||||||
|
The VictoriaMetrics distribution to use.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
listenAddress = mkOption {
|
||||||
|
default = ":8428";
|
||||||
|
type = types.str;
|
||||||
|
description = ''
|
||||||
|
The listen address for the http interface.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
retentionPeriod = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 1;
|
||||||
|
description = ''
|
||||||
|
Retention period in months.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
extraOptions = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [];
|
||||||
|
description = ''
|
||||||
|
Extra options to pass to VictoriaMetrics. See the README: <link
|
||||||
|
xlink:href="https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/README.md" />
|
||||||
|
or <command>victoriametrics -help</command> for more
|
||||||
|
information.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
systemd.services.victoriametrics = {
|
||||||
|
description = "VictoriaMetrics time series database";
|
||||||
|
after = [ "network.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = 1;
|
||||||
|
StartLimitBurst = 5;
|
||||||
|
StateDirectory = "victoriametrics";
|
||||||
|
DynamicUser = true;
|
||||||
|
ExecStart = ''
|
||||||
|
${cfg.package}/bin/victoria-metrics \
|
||||||
|
-storageDataPath=/var/lib/victoriametrics \
|
||||||
|
-httpListenAddr ${cfg.listenAddress}
|
||||||
|
-retentionPeriod ${toString cfg.retentionPeriod}
|
||||||
|
${lib.escapeShellArgs cfg.extraOptions}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
|
postStart =
|
||||||
|
let
|
||||||
|
bindAddr = (lib.optionalString (lib.hasPrefix ":" cfg.listenAddress) "127.0.0.1") + cfg.listenAddress;
|
||||||
|
in
|
||||||
|
lib.mkBefore ''
|
||||||
|
until ${lib.getBin pkgs.curl}/bin/curl -s -o /dev/null http://${bindAddr}/ping; do
|
||||||
|
sleep 1;
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -18,6 +18,9 @@ with lib;
|
|||||||
description = ''
|
description = ''
|
||||||
Whether to enable at-spi2-core, a service for the Assistive Technologies
|
Whether to enable at-spi2-core, a service for the Assistive Technologies
|
||||||
available on the GNOME platform.
|
available on the GNOME platform.
|
||||||
|
|
||||||
|
Enable this if you get the error or warning
|
||||||
|
<literal>The name org.a11y.Bus was not provided by any .service files</literal>.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -118,15 +118,15 @@ in {
|
|||||||
in {
|
in {
|
||||||
displayName = "Python 3 for machine learning";
|
displayName = "Python 3 for machine learning";
|
||||||
argv = [
|
argv = [
|
||||||
"$ {env.interpreter}"
|
"''${env.interpreter}"
|
||||||
"-m"
|
"-m"
|
||||||
"ipykernel_launcher"
|
"ipykernel_launcher"
|
||||||
"-f"
|
"-f"
|
||||||
"{connection_file}"
|
"{connection_file}"
|
||||||
];
|
];
|
||||||
language = "python";
|
language = "python";
|
||||||
logo32 = "$ {env.sitePackages}/ipykernel/resources/logo-32x32.png";
|
logo32 = "''${env.sitePackages}/ipykernel/resources/logo-32x32.png";
|
||||||
logo64 = "$ {env.sitePackages}/ipykernel/resources/logo-64x64.png";
|
logo64 = "''${env.sitePackages}/ipykernel/resources/logo-64x64.png";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
|
@ -53,7 +53,7 @@ in {
|
|||||||
|
|
||||||
blacklistPlugins = mkOption {
|
blacklistPlugins = mkOption {
|
||||||
type = types.listOf types.str;
|
type = types.listOf types.str;
|
||||||
default = [ "test" ];
|
default = [];
|
||||||
example = [ "udev" ];
|
example = [ "udev" ];
|
||||||
description = ''
|
description = ''
|
||||||
Allow blacklisting specific plugins
|
Allow blacklisting specific plugins
|
||||||
@ -91,6 +91,9 @@ in {
|
|||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
# Disable test related plug-ins implicitly so that users do not have to care about them.
|
||||||
|
services.fwupd.blacklistPlugins = cfg.package.defaultBlacklistedPlugins;
|
||||||
|
|
||||||
environment.systemPackages = [ cfg.package ];
|
environment.systemPackages = [ cfg.package ];
|
||||||
|
|
||||||
environment.etc = {
|
environment.etc = {
|
||||||
|
@ -13,18 +13,12 @@ in
|
|||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
systemd.services = {
|
|
||||||
irqbalance = {
|
|
||||||
description = "irqbalance daemon";
|
|
||||||
path = [ pkgs.irqbalance ];
|
|
||||||
serviceConfig =
|
|
||||||
{ ExecStart = "${pkgs.irqbalance}/bin/irqbalance --foreground"; };
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = [ pkgs.irqbalance ];
|
environment.systemPackages = [ pkgs.irqbalance ];
|
||||||
|
|
||||||
|
systemd.services.irqbalance.wantedBy = ["multi-user.target"];
|
||||||
|
|
||||||
|
systemd.packages = [ pkgs.irqbalance ];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,37 +6,18 @@ let
|
|||||||
|
|
||||||
cfg = config.services.mailman;
|
cfg = config.services.mailman;
|
||||||
|
|
||||||
mailmanPyEnv = pkgs.python3.withPackages (ps: with ps; [mailman mailman-hyperkitty]);
|
# This deliberately doesn't use recursiveUpdate so users can
|
||||||
|
# override the defaults.
|
||||||
|
settings = {
|
||||||
|
DEFAULT_FROM_EMAIL = cfg.siteOwner;
|
||||||
|
SERVER_EMAIL = cfg.siteOwner;
|
||||||
|
ALLOWED_HOSTS = [ "localhost" "127.0.0.1" ] ++ cfg.webHosts;
|
||||||
|
COMPRESS_OFFLINE = true;
|
||||||
|
STATIC_ROOT = "/var/lib/mailman-web/static";
|
||||||
|
MEDIA_ROOT = "/var/lib/mailman-web/media";
|
||||||
|
} // cfg.webSettings;
|
||||||
|
|
||||||
mailmanExe = with pkgs; stdenv.mkDerivation {
|
settingsJSON = pkgs.writeText "settings.json" (builtins.toJSON settings);
|
||||||
name = "mailman-" + python3Packages.mailman.version;
|
|
||||||
buildInputs = [makeWrapper];
|
|
||||||
unpackPhase = ":";
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
makeWrapper ${mailmanPyEnv}/bin/mailman $out/bin/mailman \
|
|
||||||
--set MAILMAN_CONFIG_FILE /etc/mailman.cfg
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
mailmanWeb = pkgs.python3Packages.mailman-web.override {
|
|
||||||
serverEMail = cfg.siteOwner;
|
|
||||||
archiverKey = cfg.hyperkittyApiKey;
|
|
||||||
allowedHosts = cfg.webHosts;
|
|
||||||
};
|
|
||||||
|
|
||||||
mailmanWebPyEnv = pkgs.python3.withPackages (x: with x; [mailman-web]);
|
|
||||||
|
|
||||||
mailmanWebExe = with pkgs; stdenv.mkDerivation {
|
|
||||||
inherit (mailmanWeb) name;
|
|
||||||
buildInputs = [makeWrapper];
|
|
||||||
unpackPhase = ":";
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
makeWrapper ${mailmanWebPyEnv}/bin/django-admin $out/bin/mailman-web \
|
|
||||||
--set DJANGO_SETTINGS_MODULE settings
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
mailmanCfg = ''
|
mailmanCfg = ''
|
||||||
[mailman]
|
[mailman]
|
||||||
@ -53,30 +34,42 @@ let
|
|||||||
etc_dir: /etc
|
etc_dir: /etc
|
||||||
ext_dir: $etc_dir/mailman.d
|
ext_dir: $etc_dir/mailman.d
|
||||||
pid_file: /run/mailman/master.pid
|
pid_file: /run/mailman/master.pid
|
||||||
'' + optionalString (cfg.hyperkittyApiKey != null) ''
|
'' + optionalString cfg.hyperkitty.enable ''
|
||||||
|
|
||||||
[archiver.hyperkitty]
|
[archiver.hyperkitty]
|
||||||
class: mailman_hyperkitty.Archiver
|
class: mailman_hyperkitty.Archiver
|
||||||
enable: yes
|
enable: yes
|
||||||
configuration: ${pkgs.writeText "mailman-hyperkitty.cfg" mailmanHyperkittyCfg}
|
configuration: /var/lib/mailman/mailman-hyperkitty.cfg
|
||||||
'';
|
'';
|
||||||
|
|
||||||
mailmanHyperkittyCfg = ''
|
mailmanHyperkittyCfg = pkgs.writeText "mailman-hyperkitty.cfg" ''
|
||||||
[general]
|
[general]
|
||||||
# This is your HyperKitty installation, preferably on the localhost. This
|
# This is your HyperKitty installation, preferably on the localhost. This
|
||||||
# address will be used by Mailman to forward incoming emails to HyperKitty
|
# address will be used by Mailman to forward incoming emails to HyperKitty
|
||||||
# for archiving. It does not need to be publicly available, in fact it's
|
# for archiving. It does not need to be publicly available, in fact it's
|
||||||
# better if it is not.
|
# better if it is not.
|
||||||
base_url: ${cfg.hyperkittyBaseUrl}
|
base_url: ${cfg.hyperkitty.baseUrl}
|
||||||
|
|
||||||
# Shared API key, must be the identical to the value in HyperKitty's
|
# Shared API key, must be the identical to the value in HyperKitty's
|
||||||
# settings.
|
# settings.
|
||||||
api_key: ${cfg.hyperkittyApiKey}
|
api_key: @API_KEY@
|
||||||
'';
|
'';
|
||||||
|
|
||||||
in {
|
in {
|
||||||
|
|
||||||
###### interface
|
###### interface
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
(mkRenamedOptionModule [ "services" "mailman" "hyperkittyBaseUrl" ]
|
||||||
|
[ "services" "mailman" "hyperkitty" "baseUrl" ])
|
||||||
|
|
||||||
|
(mkRemovedOptionModule [ "services" "mailman" "hyperkittyApiKey" ] ''
|
||||||
|
The Hyperkitty API key is now generated on first run, and not
|
||||||
|
stored in the world-readable Nix store. To continue using
|
||||||
|
Hyperkitty, you must set services.mailman.hyperkitty.enable = true.
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
|
|
||||||
services.mailman = {
|
services.mailman = {
|
||||||
@ -87,9 +80,17 @@ in {
|
|||||||
description = "Enable Mailman on this host. Requires an active Postfix installation.";
|
description = "Enable Mailman on this host. Requires an active Postfix installation.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.mailman;
|
||||||
|
defaultText = "pkgs.mailman";
|
||||||
|
example = "pkgs.mailman.override { archivers = []; }";
|
||||||
|
description = "Mailman package to use";
|
||||||
|
};
|
||||||
|
|
||||||
siteOwner = mkOption {
|
siteOwner = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "postmaster@example.org";
|
example = "postmaster@example.org";
|
||||||
description = ''
|
description = ''
|
||||||
Certain messages that must be delivered to a human, but which can't
|
Certain messages that must be delivered to a human, but which can't
|
||||||
be delivered to a list owner (e.g. a bounce from a list owner), will
|
be delivered to a list owner (e.g. a bounce from a list owner), will
|
||||||
@ -99,12 +100,13 @@ in {
|
|||||||
|
|
||||||
webRoot = mkOption {
|
webRoot = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
default = "${mailmanWeb}/${pkgs.python3.sitePackages}";
|
default = "${pkgs.mailman-web}/${pkgs.python3.sitePackages}";
|
||||||
defaultText = "pkgs.python3Packages.mailman-web";
|
defaultText = "\${pkgs.mailman-web}/\${pkgs.python3.sitePackages}";
|
||||||
description = ''
|
description = ''
|
||||||
The web root for the Hyperkity + Postorius apps provided by Mailman.
|
The web root for the Hyperkity + Postorius apps provided by Mailman.
|
||||||
This variable can be set, of course, but it mainly exists so that site
|
This variable can be set, of course, but it mainly exists so that site
|
||||||
admins can refer to it in their own hand-written httpd configuration files.
|
admins can refer to it in their own hand-written web server
|
||||||
|
configuration files.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -120,7 +122,26 @@ in {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
hyperkittyBaseUrl = mkOption {
|
webUser = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = config.services.httpd.user;
|
||||||
|
description = ''
|
||||||
|
User to run mailman-web as
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
webSettings = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
description = ''
|
||||||
|
Overrides for the default mailman-web Django settings.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
hyperkitty = {
|
||||||
|
enable = mkEnableOption "the Hyperkitty archiver for Mailman";
|
||||||
|
|
||||||
|
baseUrl = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "http://localhost/hyperkitty/";
|
default = "http://localhost/hyperkitty/";
|
||||||
description = ''
|
description = ''
|
||||||
@ -128,16 +149,6 @@ in {
|
|||||||
localhost?
|
localhost?
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
hyperkittyApiKey = mkOption {
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
The shared secret used to authenticate Mailman's internal
|
|
||||||
communication with Hyperkitty. Must be set to enable support for the
|
|
||||||
Hyperkitty archiver. Note that this secret is going to be visible to
|
|
||||||
all local users in the Nix store.
|
|
||||||
'';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -147,25 +158,58 @@ in {
|
|||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
assertions = [
|
assertions = let
|
||||||
{ assertion = cfg.enable -> config.services.postfix.enable;
|
inherit (config.services) postfix;
|
||||||
|
|
||||||
|
requirePostfixHash = optionPath: dataFile:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
expected = "hash:/var/lib/mailman/data/${dataFile}";
|
||||||
|
value = attrByPath optionPath [] postfix;
|
||||||
|
in
|
||||||
|
{ assertion = postfix.enable -> isList value && elem expected value;
|
||||||
|
message = ''
|
||||||
|
services.postfix.${concatStringsSep "." optionPath} must contain
|
||||||
|
"${expected}".
|
||||||
|
See <https://mailman.readthedocs.io/en/latest/src/mailman/docs/mta.html>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in [
|
||||||
|
{ assertion = postfix.enable;
|
||||||
message = "Mailman requires Postfix";
|
message = "Mailman requires Postfix";
|
||||||
}
|
}
|
||||||
|
(requirePostfixHash [ "relayDomains" ] "postfix_domains")
|
||||||
|
(requirePostfixHash [ "config" "transport_maps" ] "postfix_lmtp")
|
||||||
|
(requirePostfixHash [ "config" "local_recipient_maps" ] "postfix_lmtp")
|
||||||
];
|
];
|
||||||
|
|
||||||
users.users.mailman = { description = "GNU Mailman"; isSystemUser = true; };
|
users.users.mailman = { description = "GNU Mailman"; isSystemUser = true; };
|
||||||
|
|
||||||
environment = {
|
environment.etc."mailman.cfg".text = mailmanCfg;
|
||||||
systemPackages = [ mailmanExe mailmanWebExe pkgs.sassc ];
|
|
||||||
etc."mailman.cfg".text = mailmanCfg;
|
environment.etc."mailman3/settings.py".text = ''
|
||||||
};
|
import os
|
||||||
|
|
||||||
|
# Required by mailman_web.settings, but will be overridden when
|
||||||
|
# settings_local.json is loaded.
|
||||||
|
os.environ["SECRET_KEY"] = ""
|
||||||
|
|
||||||
|
from mailman_web.settings import *
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
with open('${settingsJSON}') as f:
|
||||||
|
globals().update(json.load(f))
|
||||||
|
|
||||||
|
with open('/var/lib/mailman-web/settings_local.json') as f:
|
||||||
|
globals().update(json.load(f))
|
||||||
|
'';
|
||||||
|
|
||||||
|
environment.systemPackages = [ cfg.package ] ++ (with pkgs; [ mailman-web ]);
|
||||||
|
|
||||||
services.postfix = {
|
services.postfix = {
|
||||||
relayDomains = [ "hash:/var/lib/mailman/data/postfix_domains" ];
|
|
||||||
recipientDelimiter = "+"; # bake recipient addresses in mail envelopes via VERP
|
recipientDelimiter = "+"; # bake recipient addresses in mail envelopes via VERP
|
||||||
config = {
|
config = {
|
||||||
transport_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
|
|
||||||
local_recipient_maps = [ "hash:/var/lib/mailman/data/postfix_lmtp" ];
|
|
||||||
owner_request_special = "no"; # Mailman handles -owner addresses on its own
|
owner_request_special = "no"; # Mailman handles -owner addresses on its own
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -173,34 +217,71 @@ in {
|
|||||||
systemd.services.mailman = {
|
systemd.services.mailman = {
|
||||||
description = "GNU Mailman Master Process";
|
description = "GNU Mailman Master Process";
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
|
restartTriggers = [ config.environment.etc."mailman.cfg".source ];
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${mailmanExe}/bin/mailman start";
|
ExecStart = "${cfg.package}/bin/mailman start";
|
||||||
ExecStop = "${mailmanExe}/bin/mailman stop";
|
ExecStop = "${cfg.package}/bin/mailman stop";
|
||||||
User = "mailman";
|
User = "mailman";
|
||||||
Type = "forking";
|
Type = "forking";
|
||||||
StateDirectory = "mailman";
|
|
||||||
StateDirectoryMode = "0700";
|
|
||||||
RuntimeDirectory = "mailman";
|
RuntimeDirectory = "mailman";
|
||||||
PIDFile = "/run/mailman/master.pid";
|
PIDFile = "/run/mailman/master.pid";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.mailman-web = {
|
systemd.services.mailman-settings = {
|
||||||
description = "Init Postorius DB";
|
description = "Generate settings files (including secrets) for Mailman";
|
||||||
before = [ "httpd.service" ];
|
before = [ "mailman.service" "mailman-web.service" "hyperkitty.service" "httpd.service" "uwsgi.service" ];
|
||||||
requiredBy = [ "httpd.service" ];
|
requiredBy = [ "mailman.service" "mailman-web.service" "hyperkitty.service" "httpd.service" "uwsgi.service" ];
|
||||||
|
path = with pkgs; [ jq ];
|
||||||
script = ''
|
script = ''
|
||||||
${mailmanWebExe}/bin/mailman-web migrate
|
mailmanDir=/var/lib/mailman
|
||||||
rm -rf static
|
mailmanWebDir=/var/lib/mailman-web
|
||||||
${mailmanWebExe}/bin/mailman-web collectstatic
|
|
||||||
${mailmanWebExe}/bin/mailman-web compress
|
mailmanCfg=$mailmanDir/mailman-hyperkitty.cfg
|
||||||
|
mailmanWebCfg=$mailmanWebDir/settings_local.json
|
||||||
|
|
||||||
|
install -m 0700 -o mailman -g nogroup -d $mailmanDir
|
||||||
|
install -m 0700 -o ${cfg.webUser} -g nogroup -d $mailmanWebDir
|
||||||
|
|
||||||
|
if [ ! -e $mailmanWebCfg ]; then
|
||||||
|
hyperkittyApiKey=$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 64)
|
||||||
|
secretKey=$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 64)
|
||||||
|
|
||||||
|
mailmanWebCfgTmp=$(mktemp)
|
||||||
|
jq -n '.MAILMAN_ARCHIVER_KEY=$archiver_key | .SECRET_KEY=$secret_key' \
|
||||||
|
--arg archiver_key "$hyperkittyApiKey" \
|
||||||
|
--arg secret_key "$secretKey" \
|
||||||
|
>"$mailmanWebCfgTmp"
|
||||||
|
chown ${cfg.webUser} "$mailmanWebCfgTmp"
|
||||||
|
mv -n "$mailmanWebCfgTmp" $mailmanWebCfg
|
||||||
|
fi
|
||||||
|
|
||||||
|
hyperkittyApiKey="$(jq -r .MAILMAN_ARCHIVER_KEY $mailmanWebCfg)"
|
||||||
|
mailmanCfgTmp=$(mktemp)
|
||||||
|
sed "s/@API_KEY@/$hyperkittyApiKey/g" ${mailmanHyperkittyCfg} >"$mailmanCfgTmp"
|
||||||
|
chown mailman "$mailmanCfgTmp"
|
||||||
|
mv "$mailmanCfgTmp" $mailmanCfg
|
||||||
'';
|
'';
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
User = config.services.httpd.user;
|
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
StateDirectory = "mailman-web";
|
};
|
||||||
StateDirectoryMode = "0700";
|
};
|
||||||
|
|
||||||
|
systemd.services.mailman-web = {
|
||||||
|
description = "Init Postorius DB";
|
||||||
|
before = [ "httpd.service" "uwsgi.service" ];
|
||||||
|
requiredBy = [ "httpd.service" "uwsgi.service" ];
|
||||||
|
restartTriggers = [ config.environment.etc."mailman3/settings.py".source ];
|
||||||
|
script = ''
|
||||||
|
${pkgs.mailman-web}/bin/mailman-web migrate
|
||||||
|
rm -rf static
|
||||||
|
${pkgs.mailman-web}/bin/mailman-web collectstatic
|
||||||
|
${pkgs.mailman-web}/bin/mailman-web compress
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
User = cfg.webUser;
|
||||||
|
Type = "oneshot";
|
||||||
WorkingDirectory = "/var/lib/mailman-web";
|
WorkingDirectory = "/var/lib/mailman-web";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -208,86 +289,94 @@ in {
|
|||||||
systemd.services.mailman-daily = {
|
systemd.services.mailman-daily = {
|
||||||
description = "Trigger daily Mailman events";
|
description = "Trigger daily Mailman events";
|
||||||
startAt = "daily";
|
startAt = "daily";
|
||||||
|
restartTriggers = [ config.environment.etc."mailman.cfg".source ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${mailmanExe}/bin/mailman digests --send";
|
ExecStart = "${cfg.package}/bin/mailman digests --send";
|
||||||
User = "mailman";
|
User = "mailman";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.hyperkitty = {
|
systemd.services.hyperkitty = {
|
||||||
enable = cfg.hyperkittyApiKey != null;
|
inherit (cfg.hyperkitty) enable;
|
||||||
description = "GNU Hyperkitty QCluster Process";
|
description = "GNU Hyperkitty QCluster Process";
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
|
restartTriggers = [ config.environment.etc."mailman3/settings.py".source ];
|
||||||
wantedBy = [ "mailman.service" "multi-user.target" ];
|
wantedBy = [ "mailman.service" "multi-user.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${mailmanWebExe}/bin/mailman-web qcluster";
|
ExecStart = "${pkgs.mailman-web}/bin/mailman-web qcluster";
|
||||||
User = config.services.httpd.user;
|
User = cfg.webUser;
|
||||||
WorkingDirectory = "/var/lib/mailman-web";
|
WorkingDirectory = "/var/lib/mailman-web";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.hyperkitty-minutely = {
|
systemd.services.hyperkitty-minutely = {
|
||||||
enable = cfg.hyperkittyApiKey != null;
|
inherit (cfg.hyperkitty) enable;
|
||||||
description = "Trigger minutely Hyperkitty events";
|
description = "Trigger minutely Hyperkitty events";
|
||||||
startAt = "minutely";
|
startAt = "minutely";
|
||||||
|
restartTriggers = [ config.environment.etc."mailman3/settings.py".source ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs minutely";
|
ExecStart = "${pkgs.mailman-web}/bin/mailman-web runjobs minutely";
|
||||||
User = config.services.httpd.user;
|
User = cfg.webUser;
|
||||||
WorkingDirectory = "/var/lib/mailman-web";
|
WorkingDirectory = "/var/lib/mailman-web";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.hyperkitty-quarter-hourly = {
|
systemd.services.hyperkitty-quarter-hourly = {
|
||||||
enable = cfg.hyperkittyApiKey != null;
|
inherit (cfg.hyperkitty) enable;
|
||||||
description = "Trigger quarter-hourly Hyperkitty events";
|
description = "Trigger quarter-hourly Hyperkitty events";
|
||||||
startAt = "*:00/15";
|
startAt = "*:00/15";
|
||||||
|
restartTriggers = [ config.environment.etc."mailman3/settings.py".source ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs quarter_hourly";
|
ExecStart = "${pkgs.mailman-web}/bin/mailman-web runjobs quarter_hourly";
|
||||||
User = config.services.httpd.user;
|
User = cfg.webUser;
|
||||||
WorkingDirectory = "/var/lib/mailman-web";
|
WorkingDirectory = "/var/lib/mailman-web";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.hyperkitty-hourly = {
|
systemd.services.hyperkitty-hourly = {
|
||||||
enable = cfg.hyperkittyApiKey != null;
|
inherit (cfg.hyperkitty) enable;
|
||||||
description = "Trigger hourly Hyperkitty events";
|
description = "Trigger hourly Hyperkitty events";
|
||||||
startAt = "hourly";
|
startAt = "hourly";
|
||||||
|
restartTriggers = [ config.environment.etc."mailman3/settings.py".source ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs hourly";
|
ExecStart = "${pkgs.mailman-web}/bin/mailman-web runjobs hourly";
|
||||||
User = config.services.httpd.user;
|
User = cfg.webUser;
|
||||||
WorkingDirectory = "/var/lib/mailman-web";
|
WorkingDirectory = "/var/lib/mailman-web";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.hyperkitty-daily = {
|
systemd.services.hyperkitty-daily = {
|
||||||
enable = cfg.hyperkittyApiKey != null;
|
inherit (cfg.hyperkitty) enable;
|
||||||
description = "Trigger daily Hyperkitty events";
|
description = "Trigger daily Hyperkitty events";
|
||||||
startAt = "daily";
|
startAt = "daily";
|
||||||
|
restartTriggers = [ config.environment.etc."mailman3/settings.py".source ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs daily";
|
ExecStart = "${pkgs.mailman-web}/bin/mailman-web runjobs daily";
|
||||||
User = config.services.httpd.user;
|
User = cfg.webUser;
|
||||||
WorkingDirectory = "/var/lib/mailman-web";
|
WorkingDirectory = "/var/lib/mailman-web";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.hyperkitty-weekly = {
|
systemd.services.hyperkitty-weekly = {
|
||||||
enable = cfg.hyperkittyApiKey != null;
|
inherit (cfg.hyperkitty) enable;
|
||||||
description = "Trigger weekly Hyperkitty events";
|
description = "Trigger weekly Hyperkitty events";
|
||||||
startAt = "weekly";
|
startAt = "weekly";
|
||||||
|
restartTriggers = [ config.environment.etc."mailman3/settings.py".source ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs weekly";
|
ExecStart = "${pkgs.mailman-web}/bin/mailman-web runjobs weekly";
|
||||||
User = config.services.httpd.user;
|
User = cfg.webUser;
|
||||||
WorkingDirectory = "/var/lib/mailman-web";
|
WorkingDirectory = "/var/lib/mailman-web";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.hyperkitty-yearly = {
|
systemd.services.hyperkitty-yearly = {
|
||||||
enable = cfg.hyperkittyApiKey != null;
|
inherit (cfg.hyperkitty) enable;
|
||||||
description = "Trigger yearly Hyperkitty events";
|
description = "Trigger yearly Hyperkitty events";
|
||||||
startAt = "yearly";
|
startAt = "yearly";
|
||||||
|
restartTriggers = [ config.environment.etc."mailman3/settings.py".source ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${mailmanWebExe}/bin/mailman-web runjobs yearly";
|
ExecStart = "${pkgs.mailman-web}/bin/mailman-web runjobs yearly";
|
||||||
User = config.services.httpd.user;
|
User = cfg.webUser;
|
||||||
WorkingDirectory = "/var/lib/mailman-web";
|
WorkingDirectory = "/var/lib/mailman-web";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,8 @@ with lib;
|
|||||||
let
|
let
|
||||||
cfg = config.services.roundcube;
|
cfg = config.services.roundcube;
|
||||||
fpm = config.services.phpfpm.pools.roundcube;
|
fpm = config.services.phpfpm.pools.roundcube;
|
||||||
|
localDB = cfg.database.host == "localhost";
|
||||||
|
user = cfg.database.username;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.services.roundcube = {
|
options.services.roundcube = {
|
||||||
@ -44,7 +46,10 @@ in
|
|||||||
username = mkOption {
|
username = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "roundcube";
|
default = "roundcube";
|
||||||
description = "Username for the postgresql connection";
|
description = ''
|
||||||
|
Username for the postgresql connection.
|
||||||
|
If <literal>database.host</literal> is set to <literal>localhost</literal>, a unix user and group of the same name will be created as well.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
host = mkOption {
|
host = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
@ -58,7 +63,12 @@ in
|
|||||||
};
|
};
|
||||||
password = mkOption {
|
password = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
description = "Password for the postgresql connection";
|
description = "Password for the postgresql connection. Do not use: the password will be stored world readable in the store; use <literal>passwordFile</literal> instead.";
|
||||||
|
default = "";
|
||||||
|
};
|
||||||
|
passwordFile = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
description = "Password file for the postgresql connection. Must be readable by user <literal>nginx</literal>. Ignored if <literal>database.host</literal> is set to <literal>localhost</literal>, as peer authentication will be used.";
|
||||||
};
|
};
|
||||||
dbname = mkOption {
|
dbname = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
@ -83,14 +93,22 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
# backward compatibility: if password is set but not passwordFile, make one.
|
||||||
|
services.roundcube.database.passwordFile = mkIf (!localDB && cfg.database.password != "") (mkDefault ("${pkgs.writeText "roundcube-password" cfg.database.password}"));
|
||||||
|
warnings = lib.optional (!localDB && cfg.database.password != "") "services.roundcube.database.password is deprecated and insecure; use services.roundcube.database.passwordFile instead";
|
||||||
|
|
||||||
environment.etc."roundcube/config.inc.php".text = ''
|
environment.etc."roundcube/config.inc.php".text = ''
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
${lib.optionalString (!localDB) "$password = file_get_contents('${cfg.database.passwordFile}');"}
|
||||||
|
|
||||||
$config = array();
|
$config = array();
|
||||||
$config['db_dsnw'] = 'pgsql://${cfg.database.username}:${cfg.database.password}@${cfg.database.host}/${cfg.database.dbname}';
|
$config['db_dsnw'] = 'pgsql://${cfg.database.username}${lib.optionalString (!localDB) ":' . $password . '"}@${if localDB then "unix(/run/postgresql)" else cfg.database.host}/${cfg.database.dbname}';
|
||||||
$config['log_driver'] = 'syslog';
|
$config['log_driver'] = 'syslog';
|
||||||
$config['max_message_size'] = '25M';
|
$config['max_message_size'] = '25M';
|
||||||
$config['plugins'] = [${concatMapStringsSep "," (p: "'${p}'") cfg.plugins}];
|
$config['plugins'] = [${concatMapStringsSep "," (p: "'${p}'") cfg.plugins}];
|
||||||
|
$config['des_key'] = file_get_contents('/var/lib/roundcube/des_key');
|
||||||
|
$config['mime_types'] = '${pkgs.nginx}/conf/mime.types';
|
||||||
${cfg.extraConfig}
|
${cfg.extraConfig}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
@ -116,12 +134,26 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.postgresql = mkIf (cfg.database.host == "localhost") {
|
services.postgresql = mkIf localDB {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
ensureDatabases = [ cfg.database.dbname ];
|
||||||
|
ensureUsers = [ {
|
||||||
|
name = cfg.database.username;
|
||||||
|
ensurePermissions = {
|
||||||
|
"DATABASE ${cfg.database.username}" = "ALL PRIVILEGES";
|
||||||
|
};
|
||||||
|
} ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
users.users.${user} = mkIf localDB {
|
||||||
|
group = user;
|
||||||
|
isSystemUser = true;
|
||||||
|
createHome = false;
|
||||||
|
};
|
||||||
|
users.groups.${user} = mkIf localDB {};
|
||||||
|
|
||||||
services.phpfpm.pools.roundcube = {
|
services.phpfpm.pools.roundcube = {
|
||||||
user = "nginx";
|
user = if localDB then user else "nginx";
|
||||||
phpOptions = ''
|
phpOptions = ''
|
||||||
error_log = 'stderr'
|
error_log = 'stderr'
|
||||||
log_errors = on
|
log_errors = on
|
||||||
@ -143,9 +175,7 @@ in
|
|||||||
};
|
};
|
||||||
systemd.services.phpfpm-roundcube.after = [ "roundcube-setup.service" ];
|
systemd.services.phpfpm-roundcube.after = [ "roundcube-setup.service" ];
|
||||||
|
|
||||||
systemd.services.roundcube-setup = let
|
systemd.services.roundcube-setup = mkMerge [
|
||||||
pgSuperUser = config.services.postgresql.superUser;
|
|
||||||
in mkMerge [
|
|
||||||
(mkIf (cfg.database.host == "localhost") {
|
(mkIf (cfg.database.host == "localhost") {
|
||||||
requires = [ "postgresql.service" ];
|
requires = [ "postgresql.service" ];
|
||||||
after = [ "postgresql.service" ];
|
after = [ "postgresql.service" ];
|
||||||
@ -153,22 +183,31 @@ in
|
|||||||
})
|
})
|
||||||
{
|
{
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
script = ''
|
script = let
|
||||||
mkdir -p /var/lib/roundcube
|
psql = "${lib.optionalString (!localDB) "PGPASSFILE=${cfg.database.passwordFile}"} ${pkgs.postgresql}/bin/psql ${lib.optionalString (!localDB) "-h ${cfg.database.host} -U ${cfg.database.username} "} ${cfg.database.dbname}";
|
||||||
if [ ! -f /var/lib/roundcube/db-created ]; then
|
in
|
||||||
if [ "${cfg.database.host}" = "localhost" ]; then
|
''
|
||||||
${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create role ${cfg.database.username} with login password '${cfg.database.password}'";
|
version="$(${psql} -t <<< "select value from system where name = 'roundcube-version';" || true)"
|
||||||
${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "create database ${cfg.database.dbname} with owner ${cfg.database.username}";
|
if ! (grep -E '[a-zA-Z0-9]' <<< "$version"); then
|
||||||
|
${psql} -f ${cfg.package}/SQL/postgres.initial.sql
|
||||||
fi
|
fi
|
||||||
PGPASSWORD="${cfg.database.password}" ${pkgs.postgresql}/bin/psql -U ${cfg.database.username} \
|
|
||||||
-f ${cfg.package}/SQL/postgres.initial.sql \
|
if [ ! -f /var/lib/roundcube/des_key ]; then
|
||||||
-h ${cfg.database.host} ${cfg.database.dbname}
|
base64 /dev/urandom | head -c 24 > /var/lib/roundcube/des_key;
|
||||||
touch /var/lib/roundcube/db-created
|
# we need to log out everyone in case change the des_key
|
||||||
|
# from the default when upgrading from nixos 19.09
|
||||||
|
${psql} <<< 'TRUNCATE TABLE session;'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${pkgs.php}/bin/php ${cfg.package}/bin/update.sh
|
${pkgs.php}/bin/php ${cfg.package}/bin/update.sh
|
||||||
'';
|
'';
|
||||||
serviceConfig.Type = "oneshot";
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
StateDirectory = "roundcube";
|
||||||
|
User = if localDB then user else "nginx";
|
||||||
|
# so that the des_key is not world readable
|
||||||
|
StateDirectoryMode = "0700";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
@ -6,15 +6,6 @@ let
|
|||||||
cfg = config.services.spamassassin;
|
cfg = config.services.spamassassin;
|
||||||
spamassassin-local-cf = pkgs.writeText "local.cf" cfg.config;
|
spamassassin-local-cf = pkgs.writeText "local.cf" cfg.config;
|
||||||
|
|
||||||
spamdEnv = pkgs.buildEnv {
|
|
||||||
name = "spamd-env";
|
|
||||||
paths = [];
|
|
||||||
postBuild = ''
|
|
||||||
ln -sf ${spamassassin-init-pre} $out/init.pre
|
|
||||||
ln -sf ${spamassassin-local-cf} $out/local.cf
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -120,13 +111,11 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
environment.etc."mail/spamassassin/init.pre".source = cfg.initPreConf;
|
||||||
|
environment.etc."mail/spamassassin/local.cf".source = spamassassin-local-cf;
|
||||||
|
|
||||||
# Allow users to run 'spamc'.
|
# Allow users to run 'spamc'.
|
||||||
|
environment.systemPackages = [ pkgs.spamassassin ];
|
||||||
environment = {
|
|
||||||
etc.spamassassin.source = spamdEnv;
|
|
||||||
systemPackages = [ pkgs.spamassassin ];
|
|
||||||
};
|
|
||||||
|
|
||||||
users.users.spamd = {
|
users.users.spamd = {
|
||||||
description = "Spam Assassin Daemon";
|
description = "Spam Assassin Daemon";
|
||||||
@ -141,7 +130,7 @@ in
|
|||||||
systemd.services.sa-update = {
|
systemd.services.sa-update = {
|
||||||
script = ''
|
script = ''
|
||||||
set +e
|
set +e
|
||||||
${pkgs.su}/bin/su -s "${pkgs.bash}/bin/bash" -c "${pkgs.spamassassin}/bin/sa-update --gpghomedir=/var/lib/spamassassin/sa-update-keys/ --siteconfigpath=${spamdEnv}/" spamd
|
${pkgs.su}/bin/su -s "${pkgs.bash}/bin/bash" -c "${pkgs.spamassassin}/bin/sa-update --gpghomedir=/var/lib/spamassassin/sa-update-keys/" spamd
|
||||||
|
|
||||||
v=$?
|
v=$?
|
||||||
set -e
|
set -e
|
||||||
@ -172,7 +161,7 @@ in
|
|||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = "${pkgs.spamassassin}/bin/spamd ${optionalString cfg.debug "-D"} --username=spamd --groupname=spamd --siteconfigpath=${spamdEnv} --virtual-config-dir=/var/lib/spamassassin/user-%u --allow-tell --pidfile=/run/spamd.pid";
|
ExecStart = "${pkgs.spamassassin}/bin/spamd ${optionalString cfg.debug "-D"} --username=spamd --groupname=spamd --virtual-config-dir=/var/lib/spamassassin/user-%u --allow-tell --pidfile=/run/spamd.pid";
|
||||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -183,7 +172,7 @@ in
|
|||||||
mkdir -p /var/lib/spamassassin
|
mkdir -p /var/lib/spamassassin
|
||||||
chown spamd:spamd /var/lib/spamassassin -R
|
chown spamd:spamd /var/lib/spamassassin -R
|
||||||
set +e
|
set +e
|
||||||
${pkgs.su}/bin/su -s "${pkgs.bash}/bin/bash" -c "${pkgs.spamassassin}/bin/sa-update --gpghomedir=/var/lib/spamassassin/sa-update-keys/ --siteconfigpath=${spamdEnv}/" spamd
|
${pkgs.su}/bin/su -s "${pkgs.bash}/bin/bash" -c "${pkgs.spamassassin}/bin/sa-update --gpghomedir=/var/lib/spamassassin/sa-update-keys/" spamd
|
||||||
v=$?
|
v=$?
|
||||||
set -e
|
set -e
|
||||||
if [ $v -gt 1 ]; then
|
if [ $v -gt 1 ]; then
|
||||||
|
103
nixos/modules/services/misc/freeswitch.nix
Normal file
103
nixos/modules/services/misc/freeswitch.nix
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
{ config, lib, pkgs, ...}:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.freeswitch;
|
||||||
|
pkg = cfg.package;
|
||||||
|
configDirectory = pkgs.runCommand "freeswitch-config-d" { } ''
|
||||||
|
mkdir -p $out
|
||||||
|
cp -rT ${cfg.configTemplate} $out
|
||||||
|
chmod -R +w $out
|
||||||
|
${concatStringsSep "\n" (mapAttrsToList (fileName: filePath: ''
|
||||||
|
mkdir -p $out/$(dirname ${fileName})
|
||||||
|
cp ${filePath} $out/${fileName}
|
||||||
|
'') cfg.configDir)}
|
||||||
|
'';
|
||||||
|
configPath = if cfg.enableReload
|
||||||
|
then "/etc/freeswitch"
|
||||||
|
else configDirectory;
|
||||||
|
in {
|
||||||
|
options = {
|
||||||
|
services.freeswitch = {
|
||||||
|
enable = mkEnableOption "FreeSWITCH";
|
||||||
|
enableReload = mkOption {
|
||||||
|
default = false;
|
||||||
|
type = types.bool;
|
||||||
|
description = ''
|
||||||
|
Issue the <literal>reloadxml</literal> command to FreeSWITCH when configuration directory changes (instead of restart).
|
||||||
|
See <link xlink:href="https://freeswitch.org/confluence/display/FREESWITCH/Reloading">FreeSWITCH documentation</link> for more info.
|
||||||
|
The configuration directory is exposed at <filename>/etc/freeswitch</filename>.
|
||||||
|
See also <literal>systemd.services.*.restartIfChanged</literal>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
configTemplate = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = "${config.services.freeswitch.package}/share/freeswitch/conf/vanilla";
|
||||||
|
defaultText = literalExample "\${config.services.freeswitch.package}/share/freeswitch/conf/vanilla";
|
||||||
|
example = literalExample "\${config.services.freeswitch.package}/share/freeswitch/conf/minimal";
|
||||||
|
description = ''
|
||||||
|
Configuration template to use.
|
||||||
|
See available templates in <link xlink:href="https://github.com/signalwire/freeswitch/tree/master/conf">FreeSWITCH repository</link>.
|
||||||
|
You can also set your own configuration directory.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
configDir = mkOption {
|
||||||
|
type = with types; attrsOf path;
|
||||||
|
default = { };
|
||||||
|
example = literalExample ''
|
||||||
|
{
|
||||||
|
"freeswitch.xml" = ./freeswitch.xml;
|
||||||
|
"dialplan/default.xml" = pkgs.writeText "dialplan-default.xml" '''
|
||||||
|
[xml lines]
|
||||||
|
''';
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
Override file in FreeSWITCH config template directory.
|
||||||
|
Each top-level attribute denotes a file path in the configuration directory, its value is the file path.
|
||||||
|
See <link xlink:href="https://freeswitch.org/confluence/display/FREESWITCH/Default+Configuration">FreeSWITCH documentation</link> for more info.
|
||||||
|
Also check available templates in <link xlink:href="https://github.com/signalwire/freeswitch/tree/master/conf">FreeSWITCH repository</link>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.freeswitch;
|
||||||
|
defaultText = literalExample "pkgs.freeswitch";
|
||||||
|
example = literalExample "pkgs.freeswitch";
|
||||||
|
description = ''
|
||||||
|
FreeSWITCH package.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
environment.etc.freeswitch = mkIf cfg.enableReload {
|
||||||
|
source = configDirectory;
|
||||||
|
};
|
||||||
|
systemd.services.freeswitch-config-reload = mkIf cfg.enableReload {
|
||||||
|
before = [ "freeswitch.service" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
restartTriggers = [ configDirectory ];
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.systemd}/bin/systemctl try-reload-or-restart freeswitch.service";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
Type = "oneshot";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
systemd.services.freeswitch = {
|
||||||
|
description = "Free and open-source application server for real-time communication";
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
DynamicUser = true;
|
||||||
|
StateDirectory = "freeswitch";
|
||||||
|
ExecStart = "${pkg}/bin/freeswitch -nf \\
|
||||||
|
-mod ${pkg}/lib/freeswitch/mod \\
|
||||||
|
-conf ${configPath} \\
|
||||||
|
-base /var/lib/freeswitch";
|
||||||
|
ExecReload = "${pkg}/bin/fs_cli -x reloadxml";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = "5s";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -364,7 +364,7 @@ in
|
|||||||
''}
|
''}
|
||||||
sed -e "s,#secretkey#,$KEY,g" \
|
sed -e "s,#secretkey#,$KEY,g" \
|
||||||
-e "s,#dbpass#,$DBPASS,g" \
|
-e "s,#dbpass#,$DBPASS,g" \
|
||||||
-e "s,#jwtsecet#,$JWTSECET,g" \
|
-e "s,#jwtsecret#,$JWTSECRET,g" \
|
||||||
-e "s,#mailerpass#,$MAILERPASSWORD,g" \
|
-e "s,#mailerpass#,$MAILERPASSWORD,g" \
|
||||||
-i ${runConfig}
|
-i ${runConfig}
|
||||||
chmod 640 ${runConfig} ${secretKey} ${jwtSecret}
|
chmod 640 ${runConfig} ${secretKey} ${jwtSecret}
|
||||||
|
@ -251,6 +251,7 @@ in {
|
|||||||
home = cfg.configDir;
|
home = cfg.configDir;
|
||||||
createHome = true;
|
createHome = true;
|
||||||
group = "hass";
|
group = "hass";
|
||||||
|
extraGroups = [ "dialout" ];
|
||||||
uid = config.ids.uids.hass;
|
uid = config.ids.uids.hass;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -123,9 +123,9 @@ in
|
|||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
"d '${cfg.dataDir}' - ${cfg.user} ${cfg.user} - -"
|
"d '${cfg.dataDir}' - ${cfg.user} ${config.users.users.${cfg.user}.group} - -"
|
||||||
] ++ (optional cfg.consumptionDirIsPublic
|
] ++ (optional cfg.consumptionDirIsPublic
|
||||||
"d '${cfg.consumptionDir}' 777 ${cfg.user} ${cfg.user} - -"
|
"d '${cfg.consumptionDir}' 777 - - - -"
|
||||||
# If the consumption dir is not created here, it's automatically created by
|
# If the consumption dir is not created here, it's automatically created by
|
||||||
# 'manage' with the default permissions.
|
# 'manage' with the default permissions.
|
||||||
);
|
);
|
||||||
@ -169,17 +169,15 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
users = optionalAttrs (cfg.user == defaultUser) {
|
users = optionalAttrs (cfg.user == defaultUser) {
|
||||||
users = [{
|
users.${defaultUser} = {
|
||||||
name = defaultUser;
|
|
||||||
group = defaultUser;
|
group = defaultUser;
|
||||||
uid = config.ids.uids.paperless;
|
uid = config.ids.uids.paperless;
|
||||||
home = cfg.dataDir;
|
home = cfg.dataDir;
|
||||||
}];
|
};
|
||||||
|
|
||||||
groups = [{
|
groups.${defaultUser} = {
|
||||||
name = defaultUser;
|
|
||||||
gid = config.ids.gids.paperless;
|
gid = config.ids.gids.paperless;
|
||||||
}];
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
virtualHost = mkOption {
|
virtualHost = mkOption {
|
||||||
type = types.submodule (import ../web-servers/apache-httpd/per-server-options.nix);
|
type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
|
||||||
example = literalExample ''
|
example = literalExample ''
|
||||||
{ hostName = "example.org";
|
{ hostName = "example.org";
|
||||||
adminAddr = "webmaster@example.org";
|
adminAddr = "webmaster@example.org";
|
||||||
|
@ -18,7 +18,7 @@ let
|
|||||||
in checkedConfig yml;
|
in checkedConfig yml;
|
||||||
|
|
||||||
cmdlineArgs = cfg.extraFlags ++ [
|
cmdlineArgs = cfg.extraFlags ++ [
|
||||||
"--config.file ${alertmanagerYml}"
|
"--config.file /tmp/alert-manager-substituted.yaml"
|
||||||
"--web.listen-address ${cfg.listenAddress}:${toString cfg.port}"
|
"--web.listen-address ${cfg.listenAddress}:${toString cfg.port}"
|
||||||
"--log.level ${cfg.logLevel}"
|
"--log.level ${cfg.logLevel}"
|
||||||
] ++ (optional (cfg.webExternalUrl != null)
|
] ++ (optional (cfg.webExternalUrl != null)
|
||||||
@ -127,6 +127,18 @@ in {
|
|||||||
Extra commandline options when launching the Alertmanager.
|
Extra commandline options when launching the Alertmanager.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
environmentFile = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
example = "/root/alertmanager.env";
|
||||||
|
description = ''
|
||||||
|
File to load as environment file. Environment variables
|
||||||
|
from this file will be interpolated into the config file
|
||||||
|
using envsubst with this syntax:
|
||||||
|
<literal>$ENVIRONMENT ''${VARIABLE}</literal>
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -144,9 +156,14 @@ in {
|
|||||||
systemd.services.alertmanager = {
|
systemd.services.alertmanager = {
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
after = [ "network.target" ];
|
after = [ "network.target" ];
|
||||||
|
preStart = ''
|
||||||
|
${lib.getBin pkgs.envsubst}/bin/envsubst -o "/tmp/alert-manager-substituted.yaml" \
|
||||||
|
-i "${alertmanagerYml}"
|
||||||
|
'';
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
DynamicUser = true;
|
DynamicUser = true; # implies PrivateTmp
|
||||||
|
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
|
||||||
WorkingDirectory = "/tmp";
|
WorkingDirectory = "/tmp";
|
||||||
ExecStart = "${cfg.package}/bin/alertmanager" +
|
ExecStart = "${cfg.package}/bin/alertmanager" +
|
||||||
optionalString (length cmdlineArgs != 0) (" \\\n " +
|
optionalString (length cmdlineArgs != 0) (" \\\n " +
|
||||||
|
@ -74,7 +74,7 @@ in
|
|||||||
then "--systemd.slice ${cfg.systemd.slice}"
|
then "--systemd.slice ${cfg.systemd.slice}"
|
||||||
else "--systemd.unit ${cfg.systemd.unit}")
|
else "--systemd.unit ${cfg.systemd.unit}")
|
||||||
++ optional (cfg.systemd.enable && (cfg.systemd.journalPath != null))
|
++ optional (cfg.systemd.enable && (cfg.systemd.journalPath != null))
|
||||||
"--systemd.jounal_path ${cfg.systemd.journalPath}"
|
"--systemd.journal_path ${cfg.systemd.journalPath}"
|
||||||
++ optional (!cfg.systemd.enable) "--postfix.logfile_path ${cfg.logfilePath}")}
|
++ optional (!cfg.systemd.enable) "--postfix.logfile_path ${cfg.logfilePath}")}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
47
nixos/modules/services/monitoring/prometheus/xmpp-alerts.nix
Normal file
47
nixos/modules/services/monitoring/prometheus/xmpp-alerts.nix
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.prometheus.xmpp-alerts;
|
||||||
|
|
||||||
|
configFile = pkgs.writeText "prometheus-xmpp-alerts.yml" (builtins.toJSON cfg.configuration);
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
options.services.prometheus.xmpp-alerts = {
|
||||||
|
|
||||||
|
enable = mkEnableOption "XMPP Web hook service for Alertmanager";
|
||||||
|
|
||||||
|
configuration = mkOption {
|
||||||
|
type = types.attrs;
|
||||||
|
description = "Configuration as attribute set which will be converted to YAML";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
systemd.services.prometheus-xmpp-alerts = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.prometheus-xmpp-alerts}/bin/prometheus-xmpp-alerts --config ${configFile}";
|
||||||
|
Restart = "on-failure";
|
||||||
|
DynamicUser = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
ProtectHome = true;
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
|
||||||
|
SystemCallFilter = [ "@system-service" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
|
inherit (config.security) wrapperDir;
|
||||||
cfg = config.services.kbfs;
|
cfg = config.services.kbfs;
|
||||||
|
|
||||||
in {
|
in {
|
||||||
@ -17,6 +18,16 @@ in {
|
|||||||
description = "Whether to mount the Keybase filesystem.";
|
description = "Whether to mount the Keybase filesystem.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enableRedirector = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Whether to enable the Keybase root redirector service, allowing
|
||||||
|
any user to access KBFS files via <literal>/keybase</literal>,
|
||||||
|
which will show different contents depending on the requester.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
mountPoint = mkOption {
|
mountPoint = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "%h/keybase";
|
default = "%h/keybase";
|
||||||
@ -41,18 +52,32 @@ in {
|
|||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable (mkMerge [
|
||||||
|
{
|
||||||
|
# Upstream: https://github.com/keybase/client/blob/master/packaging/linux/systemd/kbfs.service
|
||||||
systemd.user.services.kbfs = {
|
systemd.user.services.kbfs = {
|
||||||
description = "Keybase File System";
|
description = "Keybase File System";
|
||||||
requires = [ "keybase.service" ];
|
|
||||||
after = [ "keybase.service" ];
|
# Note that the "Requires" directive will cause a unit to be restarted whenever its dependency is restarted.
|
||||||
|
# Do not issue a hard dependency on keybase, because kbfs can reconnect to a restarted service.
|
||||||
|
# Do not issue a hard dependency on keybase-redirector, because it's ok if it fails (e.g., if it is disabled).
|
||||||
|
wants = [ "keybase.service" ] ++ optional cfg.enableRedirector "keybase-redirector.service";
|
||||||
path = [ "/run/wrappers" ];
|
path = [ "/run/wrappers" ];
|
||||||
unitConfig.ConditionUser = "!@system";
|
unitConfig.ConditionUser = "!@system";
|
||||||
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${cfg.mountPoint}";
|
Type = "notify";
|
||||||
ExecStart = "${pkgs.kbfs}/bin/kbfsfuse ${toString cfg.extraFlags} ${cfg.mountPoint}";
|
# Keybase notifies from a forked process
|
||||||
ExecStopPost = "/run/wrappers/bin/fusermount -u ${cfg.mountPoint}";
|
EnvironmentFile = [
|
||||||
|
"-%E/keybase/keybase.autogen.env"
|
||||||
|
"-%E/keybase/keybase.env"
|
||||||
|
];
|
||||||
|
ExecStartPre = [
|
||||||
|
"${pkgs.coreutils}/bin/mkdir -p \"${cfg.mountPoint}\""
|
||||||
|
"-${wrapperDir}/fusermount -uz \"${cfg.mountPoint}\""
|
||||||
|
];
|
||||||
|
ExecStart = "${pkgs.kbfs}/bin/kbfsfuse ${toString cfg.extraFlags} \"${cfg.mountPoint}\"";
|
||||||
|
ExecStop = "${wrapperDir}/fusermount -uz \"${cfg.mountPoint}\"";
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
PrivateTmp = true;
|
PrivateTmp = true;
|
||||||
};
|
};
|
||||||
@ -62,5 +87,32 @@ in {
|
|||||||
services.keybase.enable = true;
|
services.keybase.enable = true;
|
||||||
|
|
||||||
environment.systemPackages = [ pkgs.kbfs ];
|
environment.systemPackages = [ pkgs.kbfs ];
|
||||||
|
}
|
||||||
|
|
||||||
|
(mkIf cfg.enableRedirector {
|
||||||
|
security.wrappers."keybase-redirector".source = "${pkgs.kbfs}/bin/redirector";
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [ "d /keybase 0755 root root 0" ];
|
||||||
|
|
||||||
|
# Upstream: https://github.com/keybase/client/blob/master/packaging/linux/systemd/keybase-redirector.service
|
||||||
|
systemd.user.services.keybase-redirector = {
|
||||||
|
description = "Keybase Root Redirector for KBFS";
|
||||||
|
wants = [ "keybase.service" ];
|
||||||
|
unitConfig.ConditionUser = "!@system";
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
EnvironmentFile = [
|
||||||
|
"-%E/keybase/keybase.autogen.env"
|
||||||
|
"-%E/keybase/keybase.env"
|
||||||
|
];
|
||||||
|
# Note: The /keybase mount point is not currently configurable upstream.
|
||||||
|
ExecStart = "${wrapperDir}/keybase-redirector /keybase";
|
||||||
|
Restart = "on-failure";
|
||||||
|
PrivateTmp = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
wantedBy = [ "default.target" ];
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
@ -168,8 +168,7 @@ in
|
|||||||
createHome = true;
|
createHome = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
users.groups = singleton {
|
users.groups.bitlbee = {
|
||||||
name = "bitlbee";
|
|
||||||
gid = config.ids.gids.bitlbee;
|
gid = config.ids.gids.bitlbee;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
46
nixos/modules/services/networking/corerad.nix
Normal file
46
nixos/modules/services/networking/corerad.nix
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.corerad;
|
||||||
|
in {
|
||||||
|
meta = {
|
||||||
|
maintainers = with maintainers; [ mdlayher ];
|
||||||
|
};
|
||||||
|
|
||||||
|
options.services.corerad = {
|
||||||
|
enable = mkEnableOption "CoreRAD IPv6 NDP RA daemon";
|
||||||
|
|
||||||
|
configFile = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
example = literalExample "\"\${pkgs.corerad}/etc/corerad/corerad.toml\"";
|
||||||
|
description = "Path to CoreRAD TOML configuration file.";
|
||||||
|
};
|
||||||
|
|
||||||
|
package = mkOption {
|
||||||
|
default = pkgs.corerad;
|
||||||
|
defaultText = literalExample "pkgs.corerad";
|
||||||
|
type = types.package;
|
||||||
|
description = "CoreRAD package to use.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
systemd.services.corerad = {
|
||||||
|
description = "CoreRAD IPv6 NDP RA daemon";
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
LimitNPROC = 512;
|
||||||
|
LimitNOFILE = 1048576;
|
||||||
|
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW";
|
||||||
|
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_RAW";
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
DynamicUser = true;
|
||||||
|
ExecStart = "${getBin cfg.package}/bin/corerad -c=${cfg.configFile}";
|
||||||
|
Restart = "on-failure";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -59,6 +59,16 @@ let
|
|||||||
# Use the list of allowed interfaces if specified
|
# Use the list of allowed interfaces if specified
|
||||||
${optionalString (allowInterfaces != null) "allowinterfaces ${toString allowInterfaces}"}
|
${optionalString (allowInterfaces != null) "allowinterfaces ${toString allowInterfaces}"}
|
||||||
|
|
||||||
|
# Immediately fork to background if specified, otherwise wait for IP address to be assigned
|
||||||
|
${{
|
||||||
|
background = "background";
|
||||||
|
any = "waitip";
|
||||||
|
ipv4 = "waitip 4";
|
||||||
|
ipv6 = "waitip 6";
|
||||||
|
both = "waitip 4\nwaitip 6";
|
||||||
|
if-carrier-up = "";
|
||||||
|
}.${cfg.wait}}
|
||||||
|
|
||||||
${cfg.extraConfig}
|
${cfg.extraConfig}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
@ -146,6 +156,21 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
networking.dhcpcd.wait = mkOption {
|
||||||
|
type = types.enum [ "background" "any" "ipv4" "ipv6" "both" "if-carrier-up" ];
|
||||||
|
default = "any";
|
||||||
|
description = ''
|
||||||
|
This option specifies when the dhcpcd service will fork to background.
|
||||||
|
If set to "background", dhcpcd will fork to background immediately.
|
||||||
|
If set to "ipv4" or "ipv6", dhcpcd will wait for the corresponding IP
|
||||||
|
address to be assigned. If set to "any", dhcpcd will wait for any type
|
||||||
|
(IPv4 or IPv6) to be assigned. If set to "both", dhcpcd will wait for
|
||||||
|
both an IPv4 and an IPv6 address before forking.
|
||||||
|
The option "if-carrier-up" is equivalent to "any" if either ethernet
|
||||||
|
is plugged nor WiFi is powered, and to "background" otherwise.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -165,6 +190,8 @@ in
|
|||||||
before = [ "network-online.target" ];
|
before = [ "network-online.target" ];
|
||||||
after = [ "systemd-udev-settle.service" ];
|
after = [ "systemd-udev-settle.service" ];
|
||||||
|
|
||||||
|
restartTriggers = [ exitHook ];
|
||||||
|
|
||||||
# Stopping dhcpcd during a reconfiguration is undesirable
|
# Stopping dhcpcd during a reconfiguration is undesirable
|
||||||
# because it brings down the network interfaces configured by
|
# because it brings down the network interfaces configured by
|
||||||
# dhcpcd. So do a "systemctl restart" instead.
|
# dhcpcd. So do a "systemctl restart" instead.
|
||||||
@ -177,7 +204,7 @@ in
|
|||||||
serviceConfig =
|
serviceConfig =
|
||||||
{ Type = "forking";
|
{ Type = "forking";
|
||||||
PIDFile = "/run/dhcpcd.pid";
|
PIDFile = "/run/dhcpcd.pid";
|
||||||
ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd -w --quiet ${optionalString cfg.persistent "--persistent"} --config ${dhcpcdConf}";
|
ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd --quiet ${optionalString cfg.persistent "--persistent"} --config ${dhcpcdConf}";
|
||||||
ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind";
|
ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind";
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
};
|
};
|
||||||
|
@ -1,328 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
with lib;
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.services.dnscrypt-proxy;
|
|
||||||
|
|
||||||
stateDirectory = "/var/lib/dnscrypt-proxy";
|
|
||||||
|
|
||||||
# The minisign public key used to sign the upstream resolver list.
|
|
||||||
# This is somewhat more flexible than preloading the key as an
|
|
||||||
# embedded string.
|
|
||||||
upstreamResolverListPubKey = pkgs.fetchurl {
|
|
||||||
url = https://raw.githubusercontent.com/dyne/dnscrypt-proxy/master/minisign.pub;
|
|
||||||
sha256 = "18lnp8qr6ghfc2sd46nn1rhcpr324fqlvgsp4zaigw396cd7vnnh";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Internal flag indicating whether the upstream resolver list is used.
|
|
||||||
useUpstreamResolverList = cfg.customResolver == null;
|
|
||||||
|
|
||||||
# The final local address.
|
|
||||||
localAddress = "${cfg.localAddress}:${toString cfg.localPort}";
|
|
||||||
|
|
||||||
# The final resolvers list path.
|
|
||||||
resolverList = "${stateDirectory}/dnscrypt-resolvers.csv";
|
|
||||||
|
|
||||||
# Build daemon command line
|
|
||||||
|
|
||||||
resolverArgs =
|
|
||||||
if (cfg.customResolver == null)
|
|
||||||
then
|
|
||||||
[ "-L ${resolverList}"
|
|
||||||
"-R ${cfg.resolverName}"
|
|
||||||
]
|
|
||||||
else with cfg.customResolver;
|
|
||||||
[ "-N ${name}"
|
|
||||||
"-k ${key}"
|
|
||||||
"-r ${address}:${toString port}"
|
|
||||||
];
|
|
||||||
|
|
||||||
daemonArgs =
|
|
||||||
[ "-a ${localAddress}" ]
|
|
||||||
++ resolverArgs
|
|
||||||
++ cfg.extraArgs;
|
|
||||||
in
|
|
||||||
|
|
||||||
{
|
|
||||||
meta = {
|
|
||||||
maintainers = with maintainers; [ joachifm ];
|
|
||||||
doc = ./dnscrypt-proxy.xml;
|
|
||||||
};
|
|
||||||
|
|
||||||
options = {
|
|
||||||
# Before adding another option, consider whether it could
|
|
||||||
# equally well be passed via extraArgs.
|
|
||||||
|
|
||||||
services.dnscrypt-proxy = {
|
|
||||||
enable = mkOption {
|
|
||||||
default = false;
|
|
||||||
type = types.bool;
|
|
||||||
description = "Whether to enable the DNSCrypt client proxy";
|
|
||||||
};
|
|
||||||
|
|
||||||
localAddress = mkOption {
|
|
||||||
default = "127.0.0.1";
|
|
||||||
type = types.str;
|
|
||||||
description = ''
|
|
||||||
Listen for DNS queries to relay on this address. The only reason to
|
|
||||||
change this from its default value is to proxy queries on behalf
|
|
||||||
of other machines (typically on the local network).
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
localPort = mkOption {
|
|
||||||
default = 53;
|
|
||||||
type = types.int;
|
|
||||||
description = ''
|
|
||||||
Listen for DNS queries to relay on this port. The default value
|
|
||||||
assumes that the DNSCrypt proxy should relay DNS queries directly.
|
|
||||||
When running as a forwarder for another DNS client, set this option
|
|
||||||
to a different value; otherwise leave the default.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
resolverName = mkOption {
|
|
||||||
default = "random";
|
|
||||||
example = "dnscrypt.eu-nl";
|
|
||||||
type = types.nullOr types.str;
|
|
||||||
description = ''
|
|
||||||
The name of the DNSCrypt resolver to use, taken from
|
|
||||||
<filename>${resolverList}</filename>. The default is to
|
|
||||||
pick a random non-logging resolver that supports DNSSEC.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
customResolver = mkOption {
|
|
||||||
default = null;
|
|
||||||
description = ''
|
|
||||||
Use an unlisted resolver (e.g., a private DNSCrypt provider). For
|
|
||||||
advanced users only. If specified, this option takes precedence.
|
|
||||||
'';
|
|
||||||
type = types.nullOr (types.submodule ({ ... }: { options = {
|
|
||||||
address = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "IP address";
|
|
||||||
example = "208.67.220.220";
|
|
||||||
};
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = types.int;
|
|
||||||
description = "Port";
|
|
||||||
default = 443;
|
|
||||||
};
|
|
||||||
|
|
||||||
name = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "Fully qualified domain name";
|
|
||||||
example = "2.dnscrypt-cert.example.com";
|
|
||||||
};
|
|
||||||
|
|
||||||
key = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "Public key";
|
|
||||||
example = "B735:1140:206F:225D:3E2B:D822:D7FD:691E:A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79";
|
|
||||||
};
|
|
||||||
}; }));
|
|
||||||
};
|
|
||||||
|
|
||||||
extraArgs = mkOption {
|
|
||||||
default = [];
|
|
||||||
type = types.listOf types.str;
|
|
||||||
description = ''
|
|
||||||
Additional command-line arguments passed verbatim to the daemon.
|
|
||||||
See <citerefentry><refentrytitle>dnscrypt-proxy</refentrytitle>
|
|
||||||
<manvolnum>8</manvolnum></citerefentry> for details.
|
|
||||||
'';
|
|
||||||
example = [ "-X libdcplugin_example_cache.so,--min-ttl=60" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable (mkMerge [{
|
|
||||||
assertions = [
|
|
||||||
{ assertion = (cfg.customResolver != null) || (cfg.resolverName != null);
|
|
||||||
message = "please configure upstream DNSCrypt resolver";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
# make man 8 dnscrypt-proxy work
|
|
||||||
environment.systemPackages = [ pkgs.dnscrypt-proxy ];
|
|
||||||
|
|
||||||
users.users.dnscrypt-proxy = {
|
|
||||||
description = "dnscrypt-proxy daemon user";
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "dnscrypt-proxy";
|
|
||||||
};
|
|
||||||
users.groups.dnscrypt-proxy = {};
|
|
||||||
|
|
||||||
systemd.sockets.dnscrypt-proxy = {
|
|
||||||
description = "dnscrypt-proxy listening socket";
|
|
||||||
documentation = [ "man:dnscrypt-proxy(8)" ];
|
|
||||||
|
|
||||||
wantedBy = [ "sockets.target" ];
|
|
||||||
|
|
||||||
socketConfig = {
|
|
||||||
ListenStream = localAddress;
|
|
||||||
ListenDatagram = localAddress;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.dnscrypt-proxy = {
|
|
||||||
description = "dnscrypt-proxy daemon";
|
|
||||||
documentation = [ "man:dnscrypt-proxy(8)" ];
|
|
||||||
|
|
||||||
before = [ "nss-lookup.target" ];
|
|
||||||
after = [ "network.target" ];
|
|
||||||
requires = [ "dnscrypt-proxy.socket "];
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
NonBlocking = "true";
|
|
||||||
ExecStart = "${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy ${toString daemonArgs}";
|
|
||||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
|
||||||
|
|
||||||
User = "dnscrypt-proxy";
|
|
||||||
|
|
||||||
PrivateTmp = true;
|
|
||||||
PrivateDevices = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
(mkIf config.security.apparmor.enable {
|
|
||||||
systemd.services.dnscrypt-proxy.after = [ "apparmor.service" ];
|
|
||||||
|
|
||||||
security.apparmor.profiles = singleton (pkgs.writeText "apparmor-dnscrypt-proxy" ''
|
|
||||||
${pkgs.dnscrypt-proxy}/bin/dnscrypt-proxy {
|
|
||||||
/dev/null rw,
|
|
||||||
/dev/random r,
|
|
||||||
/dev/urandom r,
|
|
||||||
|
|
||||||
/etc/passwd r,
|
|
||||||
/etc/group r,
|
|
||||||
${config.environment.etc."nsswitch.conf".source} r,
|
|
||||||
|
|
||||||
${getLib pkgs.glibc}/lib/*.so mr,
|
|
||||||
${pkgs.tzdata}/share/zoneinfo/** r,
|
|
||||||
|
|
||||||
network inet stream,
|
|
||||||
network inet6 stream,
|
|
||||||
network inet dgram,
|
|
||||||
network inet6 dgram,
|
|
||||||
|
|
||||||
${getLib pkgs.dnscrypt-proxy}/lib/dnscrypt-proxy/libdcplugin*.so mr,
|
|
||||||
|
|
||||||
${getLib pkgs.gcc.cc}/lib/libssp.so.* mr,
|
|
||||||
${getLib pkgs.libsodium}/lib/libsodium.so.* mr,
|
|
||||||
${getLib pkgs.systemd}/lib/libsystemd.so.* mr,
|
|
||||||
${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so.* mr,
|
|
||||||
${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so.* mr,
|
|
||||||
${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so.* mr,
|
|
||||||
${getLib pkgs.xz}/lib/liblzma.so.* mr,
|
|
||||||
${getLib pkgs.libgcrypt}/lib/libgcrypt.so.* mr,
|
|
||||||
${getLib pkgs.libgpgerror}/lib/libgpg-error.so.* mr,
|
|
||||||
${getLib pkgs.libcap}/lib/libcap.so.* mr,
|
|
||||||
${getLib pkgs.lz4}/lib/liblz4.so.* mr,
|
|
||||||
${getLib pkgs.attr}/lib/libattr.so.* mr, # */
|
|
||||||
|
|
||||||
${resolverList} r,
|
|
||||||
|
|
||||||
/run/systemd/notify rw,
|
|
||||||
}
|
|
||||||
'');
|
|
||||||
})
|
|
||||||
|
|
||||||
(mkIf useUpstreamResolverList {
|
|
||||||
systemd.services.init-dnscrypt-proxy-statedir = {
|
|
||||||
description = "Initialize dnscrypt-proxy state directory";
|
|
||||||
|
|
||||||
wantedBy = [ "dnscrypt-proxy.service" ];
|
|
||||||
before = [ "dnscrypt-proxy.service" ];
|
|
||||||
|
|
||||||
script = ''
|
|
||||||
mkdir -pv ${stateDirectory}
|
|
||||||
chown -c dnscrypt-proxy:dnscrypt-proxy ${stateDirectory}
|
|
||||||
cp -uv \
|
|
||||||
${pkgs.dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv \
|
|
||||||
${stateDirectory}
|
|
||||||
'';
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
RemainAfterExit = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.update-dnscrypt-resolvers = {
|
|
||||||
description = "Update list of DNSCrypt resolvers";
|
|
||||||
|
|
||||||
requires = [ "init-dnscrypt-proxy-statedir.service" ];
|
|
||||||
after = [ "init-dnscrypt-proxy-statedir.service" ];
|
|
||||||
|
|
||||||
path = with pkgs; [ curl diffutils dnscrypt-proxy minisign ];
|
|
||||||
script = ''
|
|
||||||
cd ${stateDirectory}
|
|
||||||
domain=raw.githubusercontent.com
|
|
||||||
get="curl -fSs --resolve $domain:443:$(hostip -r 8.8.8.8 $domain | head -1)"
|
|
||||||
$get -o dnscrypt-resolvers.csv.tmp \
|
|
||||||
https://$domain/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv
|
|
||||||
$get -o dnscrypt-resolvers.csv.minisig.tmp \
|
|
||||||
https://$domain/dyne/dnscrypt-proxy/master/dnscrypt-resolvers.csv.minisig
|
|
||||||
mv dnscrypt-resolvers.csv.minisig{.tmp,}
|
|
||||||
if ! minisign -q -V -p ${upstreamResolverListPubKey} \
|
|
||||||
-m dnscrypt-resolvers.csv.tmp -x dnscrypt-resolvers.csv.minisig ; then
|
|
||||||
echo "failed to verify resolver list!" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
[[ -f dnscrypt-resolvers.csv ]] && mv dnscrypt-resolvers.csv{,.old}
|
|
||||||
mv dnscrypt-resolvers.csv{.tmp,}
|
|
||||||
if cmp dnscrypt-resolvers.csv{,.old} ; then
|
|
||||||
echo "no change"
|
|
||||||
else
|
|
||||||
echo "resolver list updated"
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
PrivateTmp = true;
|
|
||||||
PrivateDevices = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
ReadWritePaths = "${dirOf stateDirectory} ${stateDirectory}";
|
|
||||||
SystemCallFilter = "~@mount";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.timers.update-dnscrypt-resolvers = {
|
|
||||||
wantedBy = [ "timers.target" ];
|
|
||||||
timerConfig = {
|
|
||||||
OnBootSec = "5min";
|
|
||||||
OnUnitActiveSec = "6h";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
|
|
||||||
imports = [
|
|
||||||
(mkRenamedOptionModule [ "services" "dnscrypt-proxy" "port" ] [ "services" "dnscrypt-proxy" "localPort" ])
|
|
||||||
|
|
||||||
(mkChangedOptionModule
|
|
||||||
[ "services" "dnscrypt-proxy" "tcpOnly" ]
|
|
||||||
[ "services" "dnscrypt-proxy" "extraArgs" ]
|
|
||||||
(config:
|
|
||||||
let val = getAttrFromPath [ "services" "dnscrypt-proxy" "tcpOnly" ] config; in
|
|
||||||
optional val "-T"))
|
|
||||||
|
|
||||||
(mkChangedOptionModule
|
|
||||||
[ "services" "dnscrypt-proxy" "ephemeralKeys" ]
|
|
||||||
[ "services" "dnscrypt-proxy" "extraArgs" ]
|
|
||||||
(config:
|
|
||||||
let val = getAttrFromPath [ "services" "dnscrypt-proxy" "ephemeralKeys" ] config; in
|
|
||||||
optional val "-E"))
|
|
||||||
|
|
||||||
(mkRemovedOptionModule [ "services" "dnscrypt-proxy" "resolverList" ] ''
|
|
||||||
The current resolver listing from upstream is always used
|
|
||||||
unless a custom resolver is specified.
|
|
||||||
'')
|
|
||||||
];
|
|
||||||
}
|
|
@ -1,66 +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"
|
|
||||||
version="5.0"
|
|
||||||
xml:id="sec-dnscrypt-proxy">
|
|
||||||
<title>DNSCrypt client proxy</title>
|
|
||||||
<para>
|
|
||||||
The DNSCrypt client proxy relays DNS queries to a DNSCrypt enabled upstream
|
|
||||||
resolver. The traffic between the client and the upstream resolver is
|
|
||||||
encrypted and authenticated, mitigating the risk of MITM attacks, DNS
|
|
||||||
poisoning attacks, and third-party snooping (assuming the upstream is
|
|
||||||
trustworthy).
|
|
||||||
</para>
|
|
||||||
<sect1 xml:id="sec-dnscrypt-proxy-configuration">
|
|
||||||
<title>Basic configuration</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
To enable the client proxy, set
|
|
||||||
<programlisting>
|
|
||||||
<xref linkend="opt-services.dnscrypt-proxy.enable"/> = true;
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Enabling the client proxy does not alter the system nameserver; to relay
|
|
||||||
local queries, prepend <literal>127.0.0.1</literal> to
|
|
||||||
<option>networking.nameservers</option>.
|
|
||||||
</para>
|
|
||||||
</sect1>
|
|
||||||
<sect1 xml:id="sec-dnscrypt-proxy-forwarder">
|
|
||||||
<title>As a forwarder for another DNS client</title>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
To run the DNSCrypt proxy client as a forwarder for another DNS client,
|
|
||||||
change the default proxy listening port to a non-standard value and point
|
|
||||||
the other client to it:
|
|
||||||
<programlisting>
|
|
||||||
<xref linkend="opt-services.dnscrypt-proxy.localPort"/> = 43;
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<sect2 xml:id="sec-dnscrypt-proxy-forwarder-dsnmasq">
|
|
||||||
<title>dnsmasq</title>
|
|
||||||
<para>
|
|
||||||
<programlisting>
|
|
||||||
{
|
|
||||||
<xref linkend="opt-services.dnsmasq.enable"/> = true;
|
|
||||||
<xref linkend="opt-services.dnsmasq.servers"/> = [ "127.0.0.1#43" ];
|
|
||||||
}
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
|
|
||||||
<sect2 xml:id="sec-dnscrypt-proxy-forwarder-unbound">
|
|
||||||
<title>unbound</title>
|
|
||||||
<para>
|
|
||||||
<programlisting>
|
|
||||||
{
|
|
||||||
<xref linkend="opt-services.unbound.enable"/> = true;
|
|
||||||
<xref linkend="opt-services.unbound.forwardAddresses"/> = [ "127.0.0.1@43" ];
|
|
||||||
}
|
|
||||||
</programlisting>
|
|
||||||
</para>
|
|
||||||
</sect2>
|
|
||||||
</sect1>
|
|
||||||
</chapter>
|
|
61
nixos/modules/services/networking/dnscrypt-proxy2.nix
Normal file
61
nixos/modules/services/networking/dnscrypt-proxy2.nix
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
{ config, lib, pkgs, ... }: with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.dnscrypt-proxy2;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
options.services.dnscrypt-proxy2 = {
|
||||||
|
enable = mkEnableOption "dnscrypt-proxy2";
|
||||||
|
|
||||||
|
settings = mkOption {
|
||||||
|
description = ''
|
||||||
|
Attrset that is converted and passed as TOML config file.
|
||||||
|
For available params, see: <link xlink:href="https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml"/>
|
||||||
|
'';
|
||||||
|
example = literalExample ''
|
||||||
|
{
|
||||||
|
sources.public-resolvers = {
|
||||||
|
urls = [ "https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md" ];
|
||||||
|
cache_file = "public-resolvers.md";
|
||||||
|
minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
|
||||||
|
refresh_delay = 72;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
type = types.attrs;
|
||||||
|
default = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
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"/>
|
||||||
|
If this option is set, it will override any configuration done in options.services.dnscrypt-proxy2.settings.
|
||||||
|
'';
|
||||||
|
example = "/etc/dnscrypt-proxy/dnscrypt-proxy.toml";
|
||||||
|
type = types.path;
|
||||||
|
default = pkgs.runCommand "dnscrypt-proxy.toml" {
|
||||||
|
json = builtins.toJSON cfg.settings;
|
||||||
|
passAsFile = [ "json" ];
|
||||||
|
} ''
|
||||||
|
${pkgs.remarshal}/bin/json2toml < $jsonPath > $out
|
||||||
|
'';
|
||||||
|
defaultText = literalExample "TOML file generated from services.dnscrypt-proxy2.settings";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
|
networking.nameservers = lib.mkDefault [ "127.0.0.1" ];
|
||||||
|
|
||||||
|
systemd.services.dnscrypt-proxy2 = {
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
AmbientCapabilities = "CAP_NET_BIND_SERVICE";
|
||||||
|
DynamicUser = true;
|
||||||
|
ExecStart = "${pkgs.dnscrypt-proxy2}/bin/dnscrypt-proxy -config ${cfg.configFile}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -24,13 +24,18 @@ in {
|
|||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
|
# Upstream: https://github.com/keybase/client/blob/master/packaging/linux/systemd/keybase.service
|
||||||
systemd.user.services.keybase = {
|
systemd.user.services.keybase = {
|
||||||
description = "Keybase service";
|
description = "Keybase service";
|
||||||
unitConfig.ConditionUser = "!@system";
|
unitConfig.ConditionUser = "!@system";
|
||||||
|
environment.KEYBASE_SERVICE_TYPE = "systemd";
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
ExecStart = ''
|
Type = "notify";
|
||||||
${pkgs.keybase}/bin/keybase service --auto-forked
|
EnvironmentFile = [
|
||||||
'';
|
"-%E/keybase/keybase.autogen.env"
|
||||||
|
"-%E/keybase/keybase.env"
|
||||||
|
];
|
||||||
|
ExecStart = "${pkgs.keybase}/bin/keybase service";
|
||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
PrivateTmp = true;
|
PrivateTmp = true;
|
||||||
};
|
};
|
||||||
|
@ -56,6 +56,7 @@ in {
|
|||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.knot-dns;
|
default = pkgs.knot-dns;
|
||||||
|
defaultText = "pkgs.knot-dns";
|
||||||
description = ''
|
description = ''
|
||||||
Which Knot DNS package to use
|
Which Knot DNS package to use
|
||||||
'';
|
'';
|
||||||
@ -92,4 +93,3 @@ in {
|
|||||||
environment.systemPackages = [ knot-cli-wrappers ];
|
environment.systemPackages = [ knot-cli-wrappers ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,14 +3,39 @@
|
|||||||
with lib;
|
with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
cfg = config.services.kresd;
|
cfg = config.services.kresd;
|
||||||
package = pkgs.knot-resolver;
|
|
||||||
|
|
||||||
configFile = pkgs.writeText "kresd.conf" cfg.extraConfig;
|
# Convert systemd-style address specification to kresd config line(s).
|
||||||
in
|
# On Nix level we don't attempt to precisely validate the address specifications.
|
||||||
|
mkListen = kind: addr: let
|
||||||
|
al_v4 = builtins.match "([0-9.]\+):([0-9]\+)" addr;
|
||||||
|
al_v6 = builtins.match "\\[(.\+)]:([0-9]\+)" addr;
|
||||||
|
al_portOnly = builtins.match "()([0-9]\+)" addr;
|
||||||
|
al = findFirst (a: a != null)
|
||||||
|
(throw "services.kresd.*: incorrect address specification '${addr}'")
|
||||||
|
[ al_v4 al_v6 al_portOnly ];
|
||||||
|
port = last al;
|
||||||
|
addrSpec = if al_portOnly == null then "'${head al}'" else "{'::', '127.0.0.1'}";
|
||||||
|
in # freebind is set for compatibility with earlier kresd services;
|
||||||
|
# it could be configurable, for example.
|
||||||
|
''
|
||||||
|
net.listen(${addrSpec}, ${port}, { kind = '${kind}', freebind = true })
|
||||||
|
'';
|
||||||
|
|
||||||
{
|
configFile = pkgs.writeText "kresd.conf" (
|
||||||
|
optionalString (cfg.listenDoH != []) ''
|
||||||
|
modules.load('http')
|
||||||
|
''
|
||||||
|
+ concatMapStrings (mkListen "dns") cfg.listenPlain
|
||||||
|
+ concatMapStrings (mkListen "tls") cfg.listenTLS
|
||||||
|
+ concatMapStrings (mkListen "doh") cfg.listenDoH
|
||||||
|
+ cfg.extraConfig
|
||||||
|
);
|
||||||
|
|
||||||
|
package = pkgs.knot-resolver.override {
|
||||||
|
extraFeatures = cfg.listenDoH != [];
|
||||||
|
};
|
||||||
|
in {
|
||||||
meta.maintainers = [ maintainers.vcunat /* upstream developer */ ];
|
meta.maintainers = [ maintainers.vcunat /* upstream developer */ ];
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
@ -22,6 +47,7 @@ in
|
|||||||
value
|
value
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
(mkRemovedOptionModule [ "services" "kresd" "cacheDir" ] "Please use (bind-)mounting instead.")
|
||||||
];
|
];
|
||||||
|
|
||||||
###### interface
|
###### interface
|
||||||
@ -32,8 +58,8 @@ in
|
|||||||
description = ''
|
description = ''
|
||||||
Whether to enable knot-resolver domain name server.
|
Whether to enable knot-resolver domain name server.
|
||||||
DNSSEC validation is turned on by default.
|
DNSSEC validation is turned on by default.
|
||||||
You can run <literal>sudo nc -U /run/kresd/control</literal>
|
You can run <literal>sudo nc -U /run/knot-resolver/control/1</literal>
|
||||||
and give commands interactively to kresd.
|
and give commands interactively to kresd@1.service.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
extraConfig = mkOption {
|
extraConfig = mkOption {
|
||||||
@ -43,16 +69,10 @@ in
|
|||||||
Extra lines to be added verbatim to the generated configuration file.
|
Extra lines to be added verbatim to the generated configuration file.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
cacheDir = mkOption {
|
|
||||||
type = types.path;
|
|
||||||
default = "/var/cache/kresd";
|
|
||||||
description = ''
|
|
||||||
Directory for caches. They are intended to survive reboots.
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
listenPlain = mkOption {
|
listenPlain = mkOption {
|
||||||
type = with types; listOf str;
|
type = with types; listOf str;
|
||||||
default = [ "[::1]:53" "127.0.0.1:53" ];
|
default = [ "[::1]:53" "127.0.0.1:53" ];
|
||||||
|
example = [ "53" ];
|
||||||
description = ''
|
description = ''
|
||||||
What addresses and ports the server should listen on.
|
What addresses and ports the server should listen on.
|
||||||
For detailed syntax see ListenStream in man systemd.socket.
|
For detailed syntax see ListenStream in man systemd.socket.
|
||||||
@ -67,75 +87,59 @@ in
|
|||||||
For detailed syntax see ListenStream in man systemd.socket.
|
For detailed syntax see ListenStream in man systemd.socket.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
listenDoH = mkOption {
|
||||||
|
type = with types; listOf str;
|
||||||
|
default = [];
|
||||||
|
example = [ "198.51.100.1:443" "[2001:db8::1]:443" "443" ];
|
||||||
|
description = ''
|
||||||
|
Addresses and ports on which kresd should provide DNS over HTTPS (see RFC 8484).
|
||||||
|
For detailed syntax see ListenStream in man systemd.socket.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
instances = mkOption {
|
||||||
|
type = types.ints.unsigned;
|
||||||
|
default = 1;
|
||||||
|
description = ''
|
||||||
|
The number of instances to start. They will be called kresd@{1,2,...}.service.
|
||||||
|
Knot Resolver uses no threads, so this is the way to scale.
|
||||||
|
You can dynamically start/stop them at will, so this is just system default.
|
||||||
|
'';
|
||||||
|
};
|
||||||
# TODO: perhaps options for more common stuff like cache size or forwarding
|
# TODO: perhaps options for more common stuff like cache size or forwarding
|
||||||
};
|
};
|
||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
environment.etc."kresd.conf".source = configFile; # not required
|
environment.etc."knot-resolver/kresd.conf".source = configFile; # not required
|
||||||
|
|
||||||
users.users.kresd =
|
users.users.knot-resolver =
|
||||||
{ uid = config.ids.uids.kresd;
|
{ isSystemUser = true;
|
||||||
group = "kresd";
|
group = "knot-resolver";
|
||||||
description = "Knot-resolver daemon user";
|
description = "Knot-resolver daemon user";
|
||||||
};
|
};
|
||||||
users.groups.kresd.gid = config.ids.gids.kresd;
|
users.groups.knot-resolver.gid = null;
|
||||||
|
|
||||||
systemd.sockets.kresd = rec {
|
systemd.packages = [ package ]; # the units are patched inside the package a bit
|
||||||
wantedBy = [ "sockets.target" ];
|
|
||||||
before = wantedBy;
|
systemd.targets.kresd = { # configure units started by default
|
||||||
listenStreams = cfg.listenPlain;
|
wantedBy = [ "multi-user.target" ];
|
||||||
socketConfig = {
|
wants = [ "kres-cache-gc.service" ]
|
||||||
ListenDatagram = listenStreams;
|
++ map (i: "kresd@${toString i}.service") (range 1 cfg.instances);
|
||||||
FreeBind = true;
|
|
||||||
FileDescriptorName = "dns";
|
|
||||||
};
|
};
|
||||||
|
systemd.services."kresd@".serviceConfig = {
|
||||||
|
ExecStart = "${package}/bin/kresd --noninteractive "
|
||||||
|
+ "-c ${package}/lib/knot-resolver/distro-preconfig.lua -c ${configFile}";
|
||||||
|
# Ensure correct ownership in case UID or GID changes.
|
||||||
|
CacheDirectory = "knot-resolver";
|
||||||
|
CacheDirectoryMode = "0750";
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.sockets.kresd-tls = mkIf (cfg.listenTLS != []) rec {
|
environment.etc."tmpfiles.d/knot-resolver.conf".source =
|
||||||
wantedBy = [ "sockets.target" ];
|
"${package}/lib/tmpfiles.d/knot-resolver.conf";
|
||||||
before = wantedBy;
|
|
||||||
partOf = [ "kresd.socket" ];
|
|
||||||
listenStreams = cfg.listenTLS;
|
|
||||||
socketConfig = {
|
|
||||||
FileDescriptorName = "tls";
|
|
||||||
FreeBind = true;
|
|
||||||
Service = "kresd.service";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.sockets.kresd-control = rec {
|
# Try cleaning up the previously default location of cache file.
|
||||||
wantedBy = [ "sockets.target" ];
|
# Note that /var/cache/* should always be safe to remove.
|
||||||
before = wantedBy;
|
# TODO: remove later, probably between 20.09 and 21.03
|
||||||
partOf = [ "kresd.socket" ];
|
systemd.tmpfiles.rules = [ "R /var/cache/kresd" ];
|
||||||
listenStreams = [ "/run/kresd/control" ];
|
|
||||||
socketConfig = {
|
|
||||||
FileDescriptorName = "control";
|
|
||||||
Service = "kresd.service";
|
|
||||||
SocketMode = "0660"; # only root user/group may connect and control kresd
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [ "d '${cfg.cacheDir}' 0770 kresd kresd - -" ];
|
|
||||||
|
|
||||||
systemd.services.kresd = {
|
|
||||||
description = "Knot-resolver daemon";
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
User = "kresd";
|
|
||||||
Type = "notify";
|
|
||||||
WorkingDirectory = cfg.cacheDir;
|
|
||||||
Restart = "on-failure";
|
|
||||||
Sockets = [ "kresd.socket" "kresd-control.socket" ]
|
|
||||||
++ optional (cfg.listenTLS != []) "kresd-tls.socket";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Trust anchor goes from dns-root-data by default.
|
|
||||||
script = ''
|
|
||||||
exec '${package}/bin/kresd' --config '${configFile}' --forks=1
|
|
||||||
'';
|
|
||||||
|
|
||||||
requires = [ "kresd.socket" ];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ in
|
|||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
User = cfg.user;
|
User = cfg.user;
|
||||||
Group = cfg.group;
|
Group = cfg.group;
|
||||||
ExecStart = "${pkgs.matterbridge.bin}/bin/matterbridge -conf ${matterbridgeConfToml}";
|
ExecStart = "${pkgs.matterbridge}/bin/matterbridge -conf ${matterbridgeConfToml}";
|
||||||
Restart = "always";
|
Restart = "always";
|
||||||
RestartSec = "10";
|
RestartSec = "10";
|
||||||
};
|
};
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user