Compare commits

..

4 Commits

Author SHA1 Message Date
Raito Bezarius
9a3760926a nixos/tests/systemd-credentials-tpm2: adopt newest TPM support in test infra 2023-04-30 04:25:45 +02:00
Raito Bezarius
c3e3968544 nixos/lib/test-driver: wire up TPMs into the test driver 2023-04-30 04:25:44 +02:00
Raito Bezarius
685da3c995 nixos/qemu-vm: add virtualisation.tpm for running TPM in QEMU infrastructure 2023-04-30 04:25:43 +02:00
Raito Bezarius
975b5d3152 nixos/lib/test-driver: add Tpm driver 2023-04-30 04:25:42 +02:00
1569 changed files with 41388 additions and 80667 deletions

View File

@@ -101,7 +101,3 @@ end_of_line = unset
insert_final_newline = unset
trim_trailing_whitespace = unset
charset = unset
[lib/tests/*.plist]
indent_style = tab
insert_final_newline = unset

View File

@@ -1,7 +1,7 @@
{ pkgs ? import ../../.. {} }:
let
inherit (pkgs) lib;
manpageURLs = lib.importJSON (pkgs.path + "/doc/manpage-urls.json");
manpageURLs = builtins.fromJSON (builtins.readFile (pkgs.path + "/doc/manpage-urls.json"));
in pkgs.writeText "link-manpages.lua" ''
--[[
Adds links to known man pages that aren't already in a link.

View File

@@ -45,10 +45,7 @@ let
# NB: This file describes the Nixpkgs manual, which happens to use module
# docs infra originally developed for NixOS.
optionsDoc = pkgs.nixosOptionsDoc {
inherit (pkgs.lib.evalModules {
modules = [ ../../pkgs/top-level/config.nix ];
class = "nixpkgsConfig";
}) options;
inherit (pkgs.lib.evalModules { modules = [ ../../pkgs/top-level/config.nix ]; }) options;
documentType = "none";
transformOptions = opt:
opt // {

View File

@@ -38,12 +38,12 @@ Here is a simple package example.
- It uses the `fetchFromGitHub` fetcher to get its source.
- It also accept `duneVersion` parameter (valid value are `"1"`, `"2"`, and
`"3"`). The recommended practice it to set only if you don't want the default
value and/or it depends on something else like package version. You might see
a not-supported argument `useDune2`. The behavior was `useDune2 = true;` =>
`duneVersion = "2";` and `useDune2 = false;` => `duneVersion = "1";`. It was
used at the time when dune3 didn't existed.
- `duneVersion = "2"` ensures that Dune version 2 is used for the
build (this is the default; valid values are `"1"`, `"2"`, and `"3"`);
note that there is also a legacy `useDune2` boolean attribute:
set to `false` it corresponds to `duneVersion = "1"`; set to `true` it
corresponds to `duneVersion = "2"`. If both arguments (`duneVersion` and
`useDune2`) are given, the second one (`useDune2`) is silently ignored.
- It sets the optional `doCheck` attribute such that tests will be run with
`dune runtest -p angstrom` after the build (`dune build -p angstrom`) is
@@ -71,6 +71,7 @@ Here is a simple package example.
buildDunePackage rec {
pname = "angstrom";
version = "0.15.0";
duneVersion = "2";
minimalOCamlVersion = "4.04";
@@ -103,6 +104,8 @@ buildDunePackage rec {
pname = "wtf8";
version = "1.0.2";
useDune2 = true;
minimalOCamlVersion = "4.02";
src = fetchurl {

View File

@@ -12,11 +12,7 @@
<xi:include href="using/configuration.chapter.xml" />
<xi:include href="using/overlays.chapter.xml" />
<xi:include href="using/overrides.chapter.xml" />
</part>
<part>
<title>Nixpkgs <code>lib</code></title>
<xi:include href="functions.xml" />
<xi:include href="module-system/module-system.chapter.xml" />
</part>
<part xml:id="part-stdenv">
<title>Standard environment</title>

View File

@@ -1,105 +0,0 @@
# Module System {#module-system}
## Introduction {#module-system-introduction}
The module system is a language for handling configuration, implemented as a Nix library.
Compared to plain Nix, it adds documentation, type checking and composition or extensibility.
::: {.note}
This chapter is new and not complete yet. For a gentle introduction to the module system, in the context of NixOS, see [Writing NixOS Modules](https://nixos.org/manual/nixos/unstable/index.html#sec-writing-modules) in the NixOS manual.
:::
## `lib.evalModules` {#module-system-lib-evalModules}
Evaluate a set of modules. This function is typically only used once per application (e.g. once in NixOS, once in Home Manager, ...).
### Parameters {#module-system-lib-evalModules-parameters}
#### `modules` {#module-system-lib-evalModules-param-modules}
A list of modules. These are merged together to form the final configuration.
<!-- TODO link to section about merging, TBD -->
#### `specialArgs` {#module-system-lib-evalModules-param-specialArgs}
An attribute set of module arguments that can be used in `imports`.
This is in contrast to `config._module.args`, which is only available after all `imports` have been resolved.
#### `class` {#module-system-lib-evalModules-param-class}
If the `class` attribute is set and non-`null`, the module system will reject `imports` with a different `_class` declaration.
The `class` value should be a string in lower [camel case](https://en.wikipedia.org/wiki/Camel_case).
If applicable, the `class` should match the "prefix" of the attributes used in (experimental) [flakes](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-flake.html#description). Some examples are:
- `nixos` as in `flake.nixosModules`
- `nixosTest`: modules that constitute a [NixOS VM test](https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests)
<!-- We've only just started with `class`. You're invited to add a few more. -->
#### `prefix` {#module-system-lib-evalModules-param-prefix}
A list of strings representing the location at or below which all options are evaluated. This is used by `types.submodule` to improve error reporting and find the implicit `name` module argument.
### Return value {#module-system-lib-evalModules-return-value}
The result is an attribute set with the following attributes:
#### `options` {#module-system-lib-evalModules-return-value-options}
The nested attribute set of all option declarations.
#### `config` {#module-system-lib-evalModules-return-value-config}
The nested attribute set of all option values.
#### `type` {#module-system-lib-evalModules-return-value-type}
A module system type. This type is an instance of `types.submoduleWith` containing the current [`modules`](#module-system-lib-evalModules-param-modules).
The option definitions that are typed with this type will extend the current set of modules, like [`extendModules`](#module-system-lib-evalModules-return-value-extendModules).
However, the value returned from the type is just the [`config`](#module-system-lib-evalModules-return-value-config), like any submodule.
If you're familiar with prototype inheritance, you can think of this `evalModules` invocation as the prototype, and usages of this type as the instances.
This type is also available to the [`modules`](#module-system-lib-evalModules-param-modules) as the module argument `moduleType`.
<!-- TODO: document the module arguments. Using moduleType is like saying: suppose this configuration was extended. -->
#### `extendModules` {#module-system-lib-evalModules-return-value-extendModules}
A function similar to `evalModules` but building on top of the already passed [`modules`](#module-system-lib-evalModules-param-modules). Its arguments, `modules` and `specialArgs` are added to the existing values.
If you're familiar with prototype inheritance, you can think of the current, actual `evalModules` invocation as the prototype, and the return value of `extendModules` as the instance.
This functionality is also available to modules as the `extendModules` module argument.
::: {.note}
**Evaluation Performance**
`extendModules` returns a configuration that shares very little with the original `evalModules` invocation, because the module arguments may be different.
So if you have a configuration that has been (or will be) largely evaluated, almost none of the computation is shared with the configuration returned by `extendModules`.
The real work of module evaluation happens while computing the values in `config` and `options`, so multiple invocations of `extendModules` have a particularly small cost, as long as only the final `config` and `options` are evaluated.
If you do reference multiple `config` (or `options`) from before and after `extendModules`, evaluation performance is the same as with multiple `evalModules` invocations, because the new modules' ability to override existing configuration fundamentally requires constructing a new `config` and `options` fixpoint.
:::
#### `_module` {#module-system-lib-evalModules-return-value-_module}
A portion of the configuration tree which is elided from `config`.
<!-- TODO: when markdown migration is complete, make _module docs visible again and reference _module docs. Maybe move those docs into this chapter? -->
#### `_type` {#module-system-lib-evalModules-return-value-_type}
A nominal type marker, always `"configuration"`.
#### `class` {#module-system-lib-evalModules-return-value-_configurationClass}
The [`class` argument](#module-system-lib-evalModules-param-class).

View File

@@ -57,19 +57,6 @@
nixosModules = {
notDetected = ./nixos/modules/installer/scan/not-detected.nix;
/*
Make the `nixpkgs.*` configuration read-only. Guarantees that `pkgs`
is the way you initialize it.
Example:
{
imports = [ nixpkgs.nixosModules.readOnlyPkgs ];
nixpkgs.pkgs = nixpkgs.legacyPackages.x86_64-linux;
}
*/
readOnlyPkgs = ./nixos/modules/misc/nixpkgs/read-only.nix;
};
};
}

View File

@@ -355,7 +355,6 @@ rec {
# PLIST handling
toPlist = {}: v: let
isFloat = builtins.isFloat or (x: false);
isPath = x: builtins.typeOf x == "path";
expr = ind: x: with builtins;
if x == null then "" else
if isBool x then bool ind x else
@@ -363,7 +362,6 @@ rec {
if isString x then str ind x else
if isList x then list ind x else
if isAttrs x then attrs ind x else
if isPath x then str ind (toString x) else
if isFloat x then float ind x else
abort "generators.toPlist: should never happen (v = ${v})";
@@ -436,7 +434,6 @@ ${expr "" v}
Configuration:
* multiline - by default is true which results in indented block-like view.
* indent - initial indent.
* asBindings - by default generate single value, but with this use attrset to set global vars.
Attention:
Regardless of multiline parameter there is no trailing newline.
@@ -467,35 +464,18 @@ ${expr "" v}
/* If this option is true, the output is indented with newlines for attribute sets and lists */
multiline ? true,
/* Initial indentation level */
indent ? "",
/* Interpret as variable bindings */
asBindings ? false,
indent ? ""
}@args: v:
with builtins;
let
innerIndent = "${indent} ";
introSpace = if multiline then "\n${innerIndent}" else " ";
outroSpace = if multiline then "\n${indent}" else " ";
innerArgs = args // {
indent = if asBindings then indent else innerIndent;
asBindings = false;
};
innerArgs = args // { indent = innerIndent; };
concatItems = concatStringsSep ",${introSpace}";
isLuaInline = { _type ? null, ... }: _type == "lua-inline";
generatedBindings =
assert lib.assertMsg (badVarNames == []) "Bad Lua var names: ${toPretty {} badVarNames}";
libStr.concatStrings (
lib.attrsets.mapAttrsToList (key: value: "${indent}${key} = ${toLua innerArgs value}\n") v
);
# https://en.wikibooks.org/wiki/Lua_Programming/variable#Variable_names
matchVarName = match "[[:alpha:]_][[:alnum:]_]*(\\.[[:alpha:]_][[:alnum:]_]*)*";
badVarNames = filter (name: matchVarName name == null) (attrNames v);
in
if asBindings then
generatedBindings
else if v == null then
if v == null then
"nil"
else if isInt v || isFloat v || isString v || isBool v then
builtins.toJSON v

View File

@@ -8,10 +8,9 @@ with lib;
option = x:
x // { optional = true; };
yes = { tristate = "y"; optional = false; };
no = { tristate = "n"; optional = false; };
module = { tristate = "m"; optional = false; };
unset = { tristate = null; optional = false; };
yes = { tristate = "y"; optional = false; };
no = { tristate = "n"; optional = false; };
module = { tristate = "m"; optional = false; };
freeform = x: { freeform = x; optional = false; };
/*

View File

@@ -63,8 +63,39 @@ let
decls
));
/* See https://nixos.org/manual/nixpkgs/unstable/#module-system-lib-evalModules
or file://./../doc/module-system/module-system.chapter.md
in
rec {
/*
Evaluate a set of modules. The result is a set with the attributes:
options: The nested set of all option declarations,
config: The nested set of all option values.
type: A module system type representing the module set as a submodule,
to be extended by configuration from the containing module set.
This is also available as the module argument moduleType.
extendModules: A function similar to evalModules but building on top
of the module set. Its arguments, modules and specialArgs are
added to the existing values.
Using extendModules a few times has no performance impact as long
as you only reference the final options and config.
If you do reference multiple config (or options) from before and
after extendModules, performance is the same as with multiple
evalModules invocations, because the new modules' ability to
override existing configuration fundamentally requires a new
fixpoint to be constructed.
This is also available as a module argument.
_module: A portion of the configuration tree which is elided from
config. It contains some values that are mostly internal to the
module system implementation.
!!! Please think twice before adding to this argument list! The more
that is specified here instead of in the modules themselves the harder
@@ -79,12 +110,8 @@ let
# there's _module.args. If specialArgs.modulesPath is defined it will be
# used as the base path for disabledModules.
specialArgs ? {}
, # `class`:
# A nominal type for modules. When set and non-null, this adds a check to
# make sure that only compatible modules are imported.
# This would be remove in the future, Prefer _module.args option instead.
class ? null
, args ? {}
, # This would be remove in the future, Prefer _module.args option instead.
args ? {}
, # This would be remove in the future, Prefer _module.check option instead.
check ? true
}:
@@ -233,7 +260,6 @@ let
merged =
let collected = collectModules
class
(specialArgs.modulesPath or "")
(regularModules ++ [ internalModule ])
({ inherit lib options config specialArgs; } // specialArgs);
@@ -310,64 +336,38 @@ let
prefix ? [],
}:
evalModules (evalModulesArgs // {
inherit class;
modules = regularModules ++ modules;
specialArgs = evalModulesArgs.specialArgs or {} // specialArgs;
prefix = extendArgs.prefix or evalModulesArgs.prefix or [];
});
type = lib.types.submoduleWith {
inherit modules specialArgs class;
inherit modules specialArgs;
};
result = withWarnings {
_type = "configuration";
options = checked options;
config = checked (removeAttrs config [ "_module" ]);
_module = checked (config._module);
inherit extendModules type;
class = class;
};
in result;
# collectModules :: (class: String) -> (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
# collectModules :: (modulesPath: String) -> (modules: [ Module ]) -> (args: Attrs) -> [ Module ]
#
# Collects all modules recursively through `import` statements, filtering out
# all modules in disabledModules.
collectModules = class: let
collectModules = let
# Like unifyModuleSyntax, but also imports paths and calls functions if necessary
loadModule = args: fallbackFile: fallbackKey: m:
if isFunction m then
unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgs fallbackKey m args)
else if isAttrs m then
if m._type or "module" == "module" then
unifyModuleSyntax fallbackFile fallbackKey m
else if m._type == "if" || m._type == "override" then
loadModule args fallbackFile fallbackKey { config = m; }
else
throw (
"Could not load a value as a module, because it is of type ${lib.strings.escapeNixString m._type}"
+ lib.optionalString (fallbackFile != unknownModule) ", in file ${toString fallbackFile}."
+ lib.optionalString (m._type == "configuration") " If you do intend to import this configuration, please only import the modules that make up the configuration. You may have to create a `let` binding, file or attribute to give yourself access to the relevant modules.\nWhile loading a configuration into the module system is a very sensible idea, it can not be done cleanly in practice."
# Extended explanation: That's because a finalized configuration is more than just a set of modules. For instance, it has its own `specialArgs` that, by the nature of `specialArgs` can't be loaded through `imports` or the the `modules` argument. So instead, we have to ask you to extract the relevant modules and use those instead. This way, we keep the module system comparatively simple, and hopefully avoid a bad surprise down the line.
)
if isFunction m || isAttrs m then
unifyModuleSyntax fallbackFile fallbackKey (applyModuleArgsIfFunction fallbackKey m args)
else if isList m then
let defs = [{ file = fallbackFile; value = m; }]; in
throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}"
else unifyModuleSyntax (toString m) (toString m) (applyModuleArgsIfFunction (toString m) (import m) args);
checkModule =
if class != null
then
m:
if m._class != null -> m._class == class
then m
else
throw "The module ${m._file or m.key} was imported into ${class} instead of ${m._class}."
else
m: m;
/*
Collects all modules recursively into the form
@@ -401,7 +401,7 @@ let
};
in parentFile: parentKey: initialModules: args: collectResults (imap1 (n: x:
let
module = checkModule (loadModule args parentFile "${parentKey}:anon-${toString n}" x);
module = loadModule args parentFile "${parentKey}:anon-${toString n}" x;
collectedImports = collectStructuredModules module._file module.key module.imports args;
in {
key = module.key;
@@ -465,12 +465,11 @@ let
else config;
in
if m ? config || m ? options then
let badAttrs = removeAttrs m ["_class" "_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; in
let badAttrs = removeAttrs m ["_file" "key" "disabledModules" "imports" "options" "config" "meta" "freeformType"]; in
if badAttrs != {} then
throw "Module `${key}' has an unsupported attribute `${head (attrNames badAttrs)}'. This is caused by introducing a top-level `config' or `options' attribute. Add configuration attributes immediately on the top level instead, or move all of them (namely: ${toString (attrNames badAttrs)}) into the explicit `config' attribute."
else
{ _file = toString m._file or file;
_class = m._class or null;
key = toString m.key or key;
disabledModules = m.disabledModules or [];
imports = m.imports or [];
@@ -481,18 +480,14 @@ let
# shorthand syntax
lib.throwIfNot (isAttrs m) "module ${file} (${key}) does not look like a module."
{ _file = toString m._file or file;
_class = m._class or null;
key = toString m.key or key;
disabledModules = m.disabledModules or [];
imports = m.require or [] ++ m.imports or [];
options = {};
config = addFreeformType (removeAttrs m ["_class" "_file" "key" "disabledModules" "require" "imports" "freeformType"]);
config = addFreeformType (removeAttrs m ["_file" "key" "disabledModules" "require" "imports" "freeformType"]);
};
applyModuleArgsIfFunction = key: f: args@{ config, options, lib, ... }:
if isFunction f then applyModuleArgs key f args else f;
applyModuleArgs = key: f: args@{ config, options, lib, ... }:
applyModuleArgsIfFunction = key: f: args@{ config, options, lib, ... }: if isFunction f then
let
# Module arguments are resolved in a strict manner when attribute set
# deconstruction is used. As the arguments are now defined with the
@@ -516,7 +511,9 @@ let
# context on the explicit arguments of "args" too. This update
# operator is used to make the "args@{ ... }: with args.lib;" notation
# works.
in f (args // extraArgs);
in f (args // extraArgs)
else
f;
/* Merge a list of modules. This will recurse over the option
declarations in all modules, combining them into a single set.
@@ -1221,67 +1218,4 @@ let
_file = file;
config = lib.importTOML file;
};
private = lib.mapAttrs
(k: lib.warn "External use of `lib.modules.${k}` is deprecated. If your use case isn't covered by non-deprecated functions, we'd like to know more and perhaps support your use case well, instead of providing access to these low level functions. In this case please open an issue in https://github.com/nixos/nixpkgs/issues/.")
{
inherit
applyModuleArgsIfFunction
dischargeProperties
evalOptionValue
mergeModules
mergeModules'
pushDownProperties
unifyModuleSyntax
;
collectModules = collectModules null;
};
in
private //
{
# NOTE: not all of these functions are necessarily public interfaces; some
# are just needed by types.nix, but are not meant to be consumed
# externally.
inherit
defaultOrderPriority
defaultOverridePriority
defaultPriority
doRename
evalModules
filterOverrides
filterOverrides'
fixMergeModules
fixupOptionType # should be private?
importJSON
importTOML
mergeDefinitions
mergeOptionDecls # should be private?
mkAfter
mkAliasAndWrapDefinitions
mkAliasAndWrapDefsWithPriority
mkAliasDefinitions
mkAliasIfDef
mkAliasOptionModule
mkAliasOptionModuleMD
mkAssert
mkBefore
mkChangedOptionModule
mkDefault
mkDerivedConfig
mkFixStrictness
mkForce
mkIf
mkImageMediaOverride
mkMerge
mkMergedOptionModule
mkOptionDefault
mkOrder
mkOverride
mkRemovedOptionModule
mkRenamedOptionModule
mkRenamedOptionModuleWith
mkVMOverride
setDefaultModuleLocation
sortProperties;
}

View File

@@ -90,6 +90,10 @@ rec {
config = "mipsel-unknown-linux-gnu";
} // platforms.fuloong2f_n32;
loongarch64-linux = {
config = "loongarch64-unknown-linux-gnu";
};
# can execute on 32bit chip
mips-linux-gnu = { config = "mips-unknown-linux-gnu"; } // platforms.gcc_mips32r2_o32;
mipsel-linux-gnu = { config = "mipsel-unknown-linux-gnu"; } // platforms.gcc_mips32r2_o32;
@@ -135,10 +139,6 @@ rec {
libc = "newlib";
};
loongarch64-linux = {
config = "loongarch64-unknown-linux-gnu";
};
mmix = {
config = "mmix-unknown-mmixware";
libc = "newlib";

View File

@@ -4,11 +4,6 @@
with import ../default.nix;
let
testingThrow = expr: {
expr = (builtins.tryEval (builtins.seq expr "didn't throw"));
expected = { success = false; value = false; };
};
testingDeepThrow = expr: testingThrow (builtins.deepSeq expr expr);
testSanitizeDerivationName = { name, expected }:
let
@@ -919,30 +914,6 @@ runTests {
expected = "«foo»";
};
testToPlist =
let
deriv = derivation { name = "test"; builder = "/bin/sh"; system = "aarch64-linux"; };
in {
expr = mapAttrs (const (generators.toPlist { })) {
value = {
nested.values = rec {
int = 42;
float = 0.1337;
bool = true;
emptystring = "";
string = "fn\${o}\"r\\d";
newlinestring = "\n";
path = /. + "/foo";
null_ = null;
list = [ 3 4 "test" ];
emptylist = [];
attrs = { foo = null; "foo b/ar" = "baz"; };
emptyattrs = {};
};
};
};
expected = { value = builtins.readFile ./test-to-plist-expected.plist; };
};
testToLuaEmptyAttrSet = {
expr = generators.toLua {} {};
@@ -991,41 +962,6 @@ runTests {
expected = ''{ 41, 43 }'';
};
testToLuaEmptyBindings = {
expr = generators.toLua { asBindings = true; } {};
expected = "";
};
testToLuaBindings = {
expr = generators.toLua { asBindings = true; } { x1 = 41; _y = { a = 43; }; };
expected = ''
_y = {
["a"] = 43
}
x1 = 41
'';
};
testToLuaPartialTableBindings = {
expr = generators.toLua { asBindings = true; } { "x.y" = 42; };
expected = ''
x.y = 42
'';
};
testToLuaIndentedBindings = {
expr = generators.toLua { asBindings = true; indent = " "; } { x = { y = 42; }; };
expected = " x = {\n [\"y\"] = 42\n }\n";
};
testToLuaBindingsWithSpace = testingThrow (
generators.toLua { asBindings = true; } { "with space" = 42; }
);
testToLuaBindingsWithLeadingDigit = testingThrow (
generators.toLua { asBindings = true; } { "11eleven" = 42; }
);
testToLuaBasicExample = {
expr = generators.toLua {} {
cmd = [ "typescript-language-server" "--stdio" ];

View File

@@ -166,7 +166,6 @@ checkConfigError 'The option .* does not exist. Definition values:\n\s*- In .*'
checkConfigOutput '^true$' "$@" ./define-module-check.nix
# Check coerced value.
set --
checkConfigOutput '^"42"$' config.value ./declare-coerced-value.nix
checkConfigOutput '^"24"$' config.value ./declare-coerced-value.nix ./define-value-string.nix
checkConfigError 'A definition for option .* is not.*string or signed integer convertible to it.*. Definition values:\n\s*- In .*: \[ \]' config.value ./declare-coerced-value.nix ./define-value-list.nix
@@ -255,8 +254,6 @@ checkConfigError 'A definition for option .* is not of type .*' \
## Freeform modules
# Assigning without a declared option should work
checkConfigOutput '^"24"$' config.value ./freeform-attrsOf.nix ./define-value-string.nix
# Shorthand modules interpret `meta` and `class` as config items
checkConfigOutput '^true$' options._module.args.value.result ./freeform-attrsOf.nix ./define-freeform-keywords-shorthand.nix
# No freeform assignments shouldn't make it error
checkConfigOutput '^{ }$' config ./freeform-attrsOf.nix
# but only if the type matches
@@ -362,24 +359,6 @@ checkConfigOutput 'ok' config.freeformItems.foo.bar ./adhoc-freeformType-survive
# because of an `extendModules` bug, issue 168767.
checkConfigOutput '^1$' config.sub.specialisation.value ./extendModules-168767-imports.nix
# Class checks, evalModules
checkConfigOutput '^{ }$' config.ok.config ./class-check.nix
checkConfigOutput '"nixos"' config.ok.class ./class-check.nix
checkConfigError 'The module .*/module-class-is-darwin.nix was imported into nixos instead of darwin.' config.fail.config ./class-check.nix
checkConfigError 'The module foo.nix#darwinModules.default was imported into nixos instead of darwin.' config.fail-anon.config ./class-check.nix
# Class checks, submoduleWith
checkConfigOutput '^{ }$' config.sub.nixosOk ./class-check.nix
checkConfigError 'The module .*/module-class-is-darwin.nix was imported into nixos instead of darwin.' config.sub.nixosFail.config ./class-check.nix
# submoduleWith type merge with different class
checkConfigError 'error: A submoduleWith option is declared multiple times with conflicting class values "darwin" and "nixos".' config.sub.mergeFail.config ./class-check.nix
# _type check
checkConfigError 'Could not load a value as a module, because it is of type "flake", in file .*/module-imports-_type-check.nix' config.ok.config ./module-imports-_type-check.nix
checkConfigOutput '^true$' "$@" config.enable ./declare-enable.nix ./define-enable-with-top-level-mkIf.nix
checkConfigError 'Could not load a value as a module, because it is of type "configuration", in file .*/import-configuration.nix.*please only import the modules that make up the configuration.*' config ./import-configuration.nix
# doRename works when `warnings` does not exist.
checkConfigOutput '^1234$' config.c.d.e ./doRename-basic.nix
# doRename adds a warning.

View File

@@ -1,76 +0,0 @@
{ lib, ... }: {
options = {
sub = {
nixosOk = lib.mkOption {
type = lib.types.submoduleWith {
class = "nixos";
modules = [ ];
};
};
# Same but will have bad definition
nixosFail = lib.mkOption {
type = lib.types.submoduleWith {
class = "nixos";
modules = [ ];
};
};
mergeFail = lib.mkOption {
type = lib.types.submoduleWith {
class = "nixos";
modules = [ ];
};
default = { };
};
};
};
imports = [
{
options = {
sub = {
mergeFail = lib.mkOption {
type = lib.types.submoduleWith {
class = "darwin";
modules = [ ];
};
};
};
};
}
];
config = {
_module.freeformType = lib.types.anything;
ok =
lib.evalModules {
class = "nixos";
modules = [
./module-class-is-nixos.nix
];
};
fail =
lib.evalModules {
class = "nixos";
modules = [
./module-class-is-nixos.nix
./module-class-is-darwin.nix
];
};
fail-anon =
lib.evalModules {
class = "nixos";
modules = [
./module-class-is-nixos.nix
{ _file = "foo.nix#darwinModules.default";
_class = "darwin";
config = {};
imports = [];
}
];
};
sub.nixosOk = { _class = "nixos"; };
sub.nixosFail = { imports = [ ./module-class-is-darwin.nix ]; };
};
}

View File

@@ -1,5 +0,0 @@
{ lib, ... }:
# I think this might occur more realistically in a submodule
{
imports = [ (lib.mkIf true { enable = true; }) ];
}

View File

@@ -1,15 +0,0 @@
{ config, ... }: {
class = { "just" = "data"; };
a = "one";
b = "two";
meta = "meta";
_module.args.result =
let r = builtins.removeAttrs config [ "_module" ];
in builtins.trace (builtins.deepSeq r r) (r == {
a = "one";
b = "two";
class = { "just" = "data"; };
meta = "meta";
});
}

View File

@@ -1,12 +0,0 @@
{ lib, ... }:
let
myconf = lib.evalModules { modules = [ { } ]; };
in
{
imports = [
# We can't do this. A configuration is not equal to its set of a modules.
# Equating those would lead to a mess, as specialArgs, anonymous modules
# that can't be deduplicated, and possibly more come into play.
myconf
];
}

View File

@@ -1,4 +0,0 @@
{
_class = "darwin";
config = {};
}

View File

@@ -1,4 +0,0 @@
{
_class = "nixos";
config = {};
}

View File

@@ -1,3 +0,0 @@
{
imports = [ { _type = "flake"; } ];
}

View File

@@ -1,46 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>nested</key>
<dict>
<key>values</key>
<dict>
<key>attrs</key>
<dict>
<key>foo b/ar</key>
<string>baz</string>
</dict>
<key>bool</key>
<true/>
<key>emptyattrs</key>
<dict>
</dict>
<key>emptylist</key>
<array>
</array>
<key>emptystring</key>
<string></string>
<key>float</key>
<real>0.133700</real>
<key>int</key>
<integer>42</integer>
<key>list</key>
<array>
<integer>3</integer>
<integer>4</integer>
<string>test</string>
</array>
<key>newlinestring</key>
<string>
</string>
<key>path</key>
<string>/foo</string>
<key>string</key>
<string>fn${o}"r\d</string>
</dict>
</dict>
</dict>
</plist>

View File

@@ -476,14 +476,6 @@ rec {
check = x: isDerivation x && hasAttr "shellPath" x;
};
pkgs = addCheck
(unique { message = "A Nixpkgs pkgs set can not be merged with another pkgs set."; } attrs // {
name = "pkgs";
descriptionClass = "noun";
description = "Nixpkgs package set";
})
(x: (x._type or null) == "pkgs");
path = mkOptionType {
name = "path";
descriptionClass = "noun";
@@ -704,7 +696,6 @@ rec {
, specialArgs ? {}
, shorthandOnlyDefinesConfig ? false
, description ? null
, class ? null
}@attrs:
let
inherit (lib.modules) evalModules;
@@ -716,7 +707,7 @@ rec {
) defs;
base = evalModules {
inherit class specialArgs;
inherit specialArgs;
modules = [{
# This is a work-around for the fact that some sub-modules,
# such as the one included in an attribute set, expects an "args"
@@ -771,14 +762,9 @@ rec {
functor = defaultFunctor name // {
type = types.submoduleWith;
payload = {
inherit modules class specialArgs shorthandOnlyDefinesConfig description;
inherit modules specialArgs shorthandOnlyDefinesConfig description;
};
binOp = lhs: rhs: {
class =
if lhs.class == null then rhs.class
else if rhs.class == null then lhs.class
else if lhs.class == rhs.class then lhs.class
else throw "A submoduleWith option is declared multiple times with conflicting class values \"${toString lhs.class}\" and \"${toString rhs.class}\".";
modules = lhs.modules ++ rhs.modules;
specialArgs =
let intersecting = builtins.intersectAttrs lhs.specialArgs rhs.specialArgs;

View File

@@ -1654,16 +1654,6 @@
githubId = 1017537;
name = "Bruno Bieth";
};
badele = {
name = "Bruno Adelé";
email = "brunoadele@gmail.com";
matrix = "@badele:matrix.org";
github = "badele";
githubId = 2806307;
keys = [{
fingerprint = "00F4 21C4 C537 7BA3 9820 E13F 6B95 E13D E469 CC5D";
}];
};
badmutex = {
email = "github@badi.sh";
github = "badmutex";
@@ -5705,12 +5695,6 @@
githubId = 1713676;
name = "Luis G. Torres";
};
giorgiga = {
email = "giorgio.gallo@bitnic.it";
github = "giorgiga";
githubId = 471835;
name = "Giorgio Gallo";
};
GKasparov = {
email = "mizozahr@gmail.com";
github = "GKasparov";
@@ -5882,12 +5866,6 @@
fingerprint = "7FC7 98AB 390E 1646 ED4D 8F1F 797F 6238 68CD 00C2";
}];
};
greg = {
email = "greg.hellings@gmail.com";
github = "greg-hellings";
githubId = 273582;
name = "greg";
};
greizgh = {
email = "greizgh@ephax.org";
github = "greizgh";
@@ -8682,12 +8660,6 @@
githubId = 621759;
name = "Lassulus";
};
laurent-f1z1 = {
email = "laurent.nixpkgs@fainsin.bzh";
github = "Laurent2916";
githubId = 21087104;
name = "Laurent Fainsin";
};
layus = {
email = "layus.on@gmail.com";
github = "layus";
@@ -8792,12 +8764,6 @@
githubId = 567634;
name = "Daniel Kuehn";
};
lelgenio = {
email = "lelgenio@disroot.org";
github = "lelgenio";
githubId = 31388299;
name = "Leonardo Eugênio";
};
leo60228 = {
email = "leo@60228.dev";
matrix = "@leo60228:matrix.org";
@@ -12208,16 +12174,6 @@
githubId = 581269;
name = "Philip Potter";
};
philclifford = {
email = "philip.clifford@gmail.com";
matrix = "@phil8o:matrix.org";
github = "philclifford";
githubId = 8797027;
keys = [{
fingerprint = "FC15 E59F 0CFA 9329 101B 71D9 92F7 A790 E9BA F1F7";
}];
name = "Phil Clifford";
};
phile314 = {
email = "nix@314.ch";
github = "phile314";
@@ -13455,12 +13411,6 @@
githubId = 710906;
name = "Roel van Dijk";
};
rogarb = {
email = "rogarb@rgarbage.fr";
github = "rogarb";
githubId = 69053978;
name = "rogarb";
};
roman = {
email = "open-source@roman-gonzalez.info";
github = "roman";
@@ -14484,15 +14434,6 @@
githubId = 12828415;
name = "Michel Weitbrecht";
};
slwst = {
email = "email@slw.st";
github = "slwst";
githubId = 11047377;
name = "slwst";
keys = [{
fingerprint = "6CEB 4A2F E6DC C345 1B2B 4733 AD52 C5FB 3EFE CC7A";
}];
};
smakarov = {
email = "setser200018@gmail.com";
github = "SeTSeR";
@@ -14689,6 +14630,12 @@
githubId = 6391601;
name = "Roger Mason";
};
spwhitt = {
email = "sw@swhitt.me";
github = "spwhitt";
githubId = 1414088;
name = "Spencer Whitt";
};
squalus = {
email = "squalus@squalus.net";
github = "squalus";
@@ -15298,12 +15245,6 @@
}];
name = "David Tchekachev";
};
tcheronneau = {
email = "nix@mcth.fr";
github = "tcheronneau";
githubId = 7914437;
name = "Thomas Cheronneau";
};
tckmn = {
email = "andy@tck.mn";
github = "tckmn";
@@ -15691,11 +15632,10 @@
githubId = 18621411;
};
tilpner = {
name = "Till Höppner";
email = "nixpkgs@tilpner.com";
matrix = "@tilpner:tx0.co";
email = "till@hoeppner.ws";
github = "tilpner";
githubId = 4322055;
name = "Till Höppner";
};
timbertson = {
email = "tim@gfxmonk.net";
@@ -17532,12 +17472,6 @@
githubId = 393108;
name = "Damien Diederen";
};
zumorica = {
name = "Vera Aguilera Puerto";
email = "gradientvera+nix@outlook.com";
github = "Zumorica";
githubId = 6766154;
};
zupo = {
name = "Nejc Zupan";
email = "nejczupan+nix@gmail.com";

View File

@@ -100,12 +100,11 @@ def convert_to_throw(date_older_list: list[str]) -> list[tuple[str, str]]:
date_older_list.remove(line)
continue
alias = before_equal
alias_unquoted = before_equal.strip('"')
alias = before_equal.strip()
after_equal_list = [x.strip(";:") for x in after_equal.split()]
converted = (
f"{indent}{alias} = throw \"'{alias_unquoted}' has been renamed to/replaced by"
f"{indent}{alias} = throw \"'{alias}' has been renamed to/replaced by"
f" '{after_equal_list.pop(0)}'\";"
f' # Converted to throw {datetime.today().strftime("%Y-%m-%d")}'
)

View File

@@ -149,15 +149,6 @@ with lib.maintainers; {
enableFeatureFreezePing = true;
};
cuda = {
members = [
SomeoneSerge
];
scope = "Maintain CUDA-enabled packages";
shortName = "Cuda";
githubTeams = [ "cuda-maintainers" ];
};
darwin = {
members = [
toonn

View File

@@ -25,8 +25,6 @@ These include `pkgs.nixosTest`, `testing-python.nix` and `make-test-python.nix`.
## Testing changes to the test framework {#sec-test-the-test-framework}
We currently have limited unit tests for the framework itself. You may run these with `nix-build -A nixosTests.nixos-test-driver`.
When making significant changes to the test framework, we run the tests on Hydra, to avoid disrupting the larger NixOS project.
For this, we use the `python-test-refactoring` branch in the `NixOS/nixpkgs` repository, and its [corresponding Hydra jobset](https://hydra.nixos.org/jobset/nixos/python-test-refactoring).

View File

@@ -13,7 +13,7 @@ checking for entire option trees, it is only recommended for use in
submodules.
::: {#ex-freeform-module .example}
### Freeform submodule
**Example: Freeform submodule**
The following shows a submodule assigning a freeform type that allows
arbitrary attributes with `str` values below `settings`, but also

View File

@@ -77,7 +77,6 @@ The option's description is "Whether to enable \<name\>.".
For example:
::: {#ex-options-declarations-util-mkEnableOption-magic .example}
### `mkEnableOption` usage
```nix
lib.mkEnableOption (lib.mdDoc "magic")
# is like
@@ -127,7 +126,6 @@ During the transition to CommonMark documentation `mkPackageOption` creates an o
Examples:
::: {#ex-options-declarations-util-mkPackageOption-hello .example}
### Simple `mkPackageOption` usage
```nix
lib.mkPackageOptionMD pkgs "hello" { }
# is like
@@ -141,7 +139,6 @@ lib.mkOption {
:::
::: {#ex-options-declarations-util-mkPackageOption-ghc .example}
### `mkPackageOption` with explicit default and example
```nix
lib.mkPackageOptionMD pkgs "GHC" {
default = [ "ghc" ];
@@ -159,7 +156,6 @@ lib.mkOption {
:::
::: {#ex-options-declarations-util-mkPackageOption-extraDescription .example}
### `mkPackageOption` with additional description text
```nix
mkPackageOption pkgs [ "python39Packages" "pytorch" ] {
extraDescription = "This is an example and doesn't actually do anything.";
@@ -221,7 +217,7 @@ changing the main service module file and the type system automatically
enforces that there can only be a single display manager enabled.
::: {#ex-option-declaration-eot-service .example}
### Extensible type placeholder in the service module
**Example: Extensible type placeholder in the service module**
```nix
services.xserver.displayManager.enable = mkOption {
description = "Display manager to use";
@@ -231,7 +227,7 @@ services.xserver.displayManager.enable = mkOption {
:::
::: {#ex-option-declaration-eot-backend-gdm .example}
### Extending `services.xserver.displayManager.enable` in the `gdm` module
**Example: Extending `services.xserver.displayManager.enable` in the `gdm` module**
```nix
services.xserver.displayManager.enable = mkOption {
type = with types; nullOr (enum [ "gdm" ]);
@@ -240,7 +236,7 @@ services.xserver.displayManager.enable = mkOption {
:::
::: {#ex-option-declaration-eot-backend-sddm .example}
### Extending `services.xserver.displayManager.enable` in the `sddm` module
**Example: Extending `services.xserver.displayManager.enable` in the `sddm` module**
```nix
services.xserver.displayManager.enable = mkOption {
type = with types; nullOr (enum [ "sddm" ]);

View File

@@ -36,7 +36,7 @@ merging is handled.
together. This type is recommended when the option type is unknown.
::: {#ex-types-anything .example}
### `types.anything`
**Example: `types.anything` Example**
Two definitions of this type like
@@ -99,10 +99,6 @@ merging is handled.
problems.
:::
`types.pkgs`
: A type for the top level Nixpkgs package set.
### Numeric types {#sec-option-types-numeric}
`types.int`
@@ -360,7 +356,7 @@ you will still need to provide a default value (e.g. an empty attribute set)
if you want to allow users to leave it undefined.
::: {#ex-submodule-direct .example}
### Directly defined submodule
**Example: Directly defined submodule**
```nix
options.mod = mkOption {
description = "submodule example";
@@ -379,7 +375,7 @@ options.mod = mkOption {
:::
::: {#ex-submodule-reference .example}
### Submodule defined as a reference
**Example: Submodule defined as a reference**
```nix
let
modOptions = {
@@ -407,7 +403,7 @@ multiple definitions of the submodule option set
([Example: Definition of a list of submodules](#ex-submodule-listof-definition)).
::: {#ex-submodule-listof-declaration .example}
### Declaration of a list of submodules
**Example: Declaration of a list of submodules**
```nix
options.mod = mkOption {
description = "submodule example";
@@ -426,7 +422,7 @@ options.mod = mkOption {
:::
::: {#ex-submodule-listof-definition .example}
### Definition of a list of submodules
**Example: Definition of a list of submodules**
```nix
config.mod = [
{ foo = 1; bar = "one"; }
@@ -441,7 +437,7 @@ multiple named definitions of the submodule option set
([Example: Definition of attribute sets of submodules](#ex-submodule-attrsof-definition)).
::: {#ex-submodule-attrsof-declaration .example}
### Declaration of attribute sets of submodules
**Example: Declaration of attribute sets of submodules**
```nix
options.mod = mkOption {
description = "submodule example";
@@ -460,7 +456,7 @@ options.mod = mkOption {
:::
::: {#ex-submodule-attrsof-definition .example}
### Definition of attribute sets of submodules
**Example: Definition of attribute sets of submodules**
```nix
config.mod.one = { foo = 1; bar = "one"; };
config.mod.two = { foo = 2; bar = "two"; };
@@ -480,7 +476,7 @@ Types are mainly characterized by their `check` and `merge` functions.
([Example: Overriding a type check](#ex-extending-type-check-2)).
::: {#ex-extending-type-check-1 .example}
### Adding a type check
**Example: Adding a type check**
```nix
byte = mkOption {
@@ -491,7 +487,7 @@ Types are mainly characterized by their `check` and `merge` functions.
:::
::: {#ex-extending-type-check-2 .example}
### Overriding a type check
**Example: Overriding a type check**
```nix
nixThings = mkOption {

View File

@@ -143,7 +143,7 @@ These functions all return an attribute set with these values:
:::
::: {#ex-settings-nix-representable .example}
### Module with conventional `settings` option
**Example: Module with conventional `settings` option**
The following shows a module for an example program that uses a JSON
configuration file. It demonstrates how above values can be used, along
@@ -218,7 +218,7 @@ the port, which will enforce it to be a valid integer and make it show
up in the manual.
::: {#ex-settings-typed-attrs .example}
### Declaring a type-checked `settings` attribute
**Example: Declaring a type-checked `settings` attribute**
```nix
settings = lib.mkOption {
type = lib.types.submodule {

View File

@@ -37,7 +37,7 @@ options, but does not declare any. The structure of full NixOS modules
is shown in [Example: Structure of NixOS Modules](#ex-module-syntax).
::: {#ex-module-syntax .example}
### Structure of NixOS Modules
**Example: Structure of NixOS Modules**
```nix
{ config, pkgs, ... }:
@@ -100,7 +100,7 @@ Exec directives](#exec-escaping-example) for an example. When using these
functions system environment substitution should *not* be disabled explicitly.
::: {#locate-example .example}
### NixOS Module for the "locate" Service
**Example: NixOS Module for the "locate" Service**
```nix
{ config, lib, pkgs, ... }:
@@ -161,7 +161,7 @@ in {
:::
::: {#exec-escaping-example .example}
### Escaping in Exec directives
**Example: Escaping in Exec directives**
```nix
{ config, lib, pkgs, utils, ... }:

View File

@@ -130,11 +130,6 @@ starting them in parallel:
start_all()
```
If the hostname of a node contains characters that can't be used in a
Python variable name, those characters will be replaced with
underscores in the variable name, so `nodes.machine-a` will be exposed
to Python as `machine_a`.
## Machine objects {#ssec-machine-objects}
The following methods are available on machine objects:

View File

@@ -538,7 +538,7 @@ drive (here `/dev/sda`). [Example: NixOS Configuration](#ex-config) shows a
corresponding configuration Nix expression.
::: {#ex-partition-scheme-MBR .example}
### Example partition schemes for NixOS on `/dev/sda` (MBR)
**Example: Example partition schemes for NixOS on `/dev/sda` (MBR)**
```ShellSession
# parted /dev/sda -- mklabel msdos
# parted /dev/sda -- mkpart primary 1MB -8GB
@@ -547,7 +547,7 @@ corresponding configuration Nix expression.
:::
::: {#ex-partition-scheme-UEFI .example}
### Example partition schemes for NixOS on `/dev/sda` (UEFI)
**Example: Example partition schemes for NixOS on `/dev/sda` (UEFI)**
```ShellSession
# parted /dev/sda -- mklabel gpt
# parted /dev/sda -- mkpart primary 512MB -8GB
@@ -558,7 +558,7 @@ corresponding configuration Nix expression.
:::
::: {#ex-install-sequence .example}
### Commands for Installing NixOS on `/dev/sda`
**Example: Commands for Installing NixOS on `/dev/sda`**
With a partitioned disk.
@@ -578,7 +578,7 @@ With a partitioned disk.
:::
::: {#ex-config .example}
### Example: NixOS Configuration
**Example: NixOS Configuration**
```ShellSession
{ config, pkgs, ... }: {
imports = [

View File

@@ -46,12 +46,7 @@ In addition to numerous new and upgraded packages, this release has the followin
- [Cloudlog](https://www.magicbug.co.uk/cloudlog/), a web-based Amateur Radio logging application. Available as [services.cloudlog](#opt-services.cloudlog.enable).
- [Deepin Desktop Environment](https://github.com/linuxdeepin/dde), an elegant, easy to use and reliable desktop environment. Available as [services.xserver.desktopManager.deepin](options.html#opt-services.xserver.desktopManager.deepin).
- [system-repart](https://www.freedesktop.org/software/systemd/man/systemd-repart.service.html), grow and add partitions to a partition table. Available as [systemd.repart](options.html#opt-systemd.repart) and [boot.initrd.systemd.repart](options.html#opt-boot.initrd.systemd.repart)
- [fzf](https://github.com/junegunn/fzf), a command line fuzzyfinder. Available as [programs.fzf](#opt-programs.fzf.fuzzyCompletion).
- [readarr](https://github.com/Readarr/Readarr), Book Manager and Automation (Sonarr for Ebooks). Available as [services.readarr](options.html#opt-services.readarr.enable).
- [gemstash](https://github.com/rubygems/gemstash), a RubyGems.org cache and private gem server. Available as [services.gemstash](#opt-services.gemstash.enable).
@@ -70,8 +65,6 @@ In addition to numerous new and upgraded packages, this release has the followin
- [opensearch](https://opensearch.org), a search server alternative to Elasticsearch. Available as [services.opensearch](options.html#opt-services.opensearch.enable).
- [kavita](https://kavitareader.com), a self-hosted digital library. Available as [services.kavita](options.html#opt-services.kavita.enable).
- [monica](https://www.monicahq.com), an open source personal CRM. Available as [services.monica](options.html#opt-services.monica.enable).
- [authelia](https://www.authelia.com/), is an open-source authentication and authorization server. Available under [services.authelia](options.html#opt-services.authelia.enable).
@@ -94,10 +87,6 @@ In addition to numerous new and upgraded packages, this release has the followin
- [keyd](https://github.com/rvaiya/keyd), a key remapping daemon for linux. Available as [services.keyd](#opt-services.keyd.enable).
- [consul-template](https://github.com/hashicorp/consul-template/), a template rendering, notifier, and supervisor for HashiCorp Consul and Vault data. Available as [services.consul-template](#opt-services.consul-template.instances).
- [vault-agent](https://developer.hashicorp.com/vault/docs/agent), a template rendering and API auth proxy for HashiCorp Vault, similar to `consul-template`. Available as [services.vault-agent](#opt-services.vault-agent.instances).
- [v2rayA](https://v2raya.org), a Linux web GUI client of Project V which supports V2Ray, Xray, SS, SSR, Trojan and Pingtunnel. Available as [services.v2raya](options.html#opt-services.v2raya.enable).
- [wstunnel](https://github.com/erebe/wstunnel), a proxy tunnelling arbitrary TCP or UDP traffic through a WebSocket connection. Instances may be configured via [services.wstunnel](options.html#opt-services.wstunnel.enable).
@@ -144,8 +133,6 @@ In addition to numerous new and upgraded packages, this release has the followin
- `carnix` and `cratesIO` has been removed due to being unmaintained, use alternatives such as [naersk](https://github.com/nix-community/naersk) and [crate2nix](https://github.com/kolloch/crate2nix) instead.
- `services.asusd` configuration now uses strings instead of structured configuration, as upstream switched to the [RON](https://github.com/ron-rs/ron) configuration format. Support for structured configuration may return when [RON](https://github.com/ron-rs/ron) generation is implemented in nixpkgs.
- `checkInputs` have been renamed to `nativeCheckInputs`, because they behave the same as `nativeBuildInputs` when `doCheck` is set. `checkInputs` now denote a new type of dependencies, added to `buildInputs` when `doCheck` is set. As a rule of thumb, `nativeCheckInputs` are tools on `$PATH` used during the tests, and `checkInputs` are libraries which are linked to executables built as part of the tests. Similarly, `installCheckInputs` are renamed to `nativeInstallCheckInputs`, corresponding to `nativeBuildInputs`, and `installCheckInputs` are a new type of dependencies added to `buildInputs` when `doInstallCheck` is set. (Note that this change will not cause breakage to derivations with `strictDeps` unset, which are most packages except python, rust, ocaml and go packages).
- `buildDunePackage` now defaults to `strictDeps = true` which means that any library should go into `buildInputs` or `checkInputs`. Any executable that is run on the building machine should go into `nativeBuildInputs` or `nativeCheckInputs` respectively. Example of executables are `ocaml`, `findlib` and `menhir`. PPXs are libraries which are built by dune and should therefore not go into `nativeBuildInputs`.
@@ -185,8 +172,6 @@ In addition to numerous new and upgraded packages, this release has the followin
- The option `i18n.inputMethod.fcitx5.enableRimeData` has been removed. Default RIME data is now included in `fcitx5-rime` by default, and can be customized using `fcitx5-rime.override { rimeDataPkgs = [ pkgs.rime-data, package2, ... ]; }`
- The udev hwdb.bin file is now built with systemd-hwdb rather than the [deprecated "udevadm hwdb"](https://github.com/systemd/systemd/pull/25714). This may impact mappings where the same key is defined in multiple matching entries. The updated behavior will select the latest definition in case of conflict. In general, this should be a positive change, as the hwdb source files are designed with this ordering in mind. As an example, the mapping of the HP Dev One keyboard scan code for "mute mic" is corrected by this update. This change may impact users who have worked-around previously incorrect mappings.
- Kime has been updated from 2.5.6 to 3.0.2 and the `i18n.inputMethod.kime.config` option has been removed. Users should use `daemonModules`, `iconColor`, and `extraConfig` options under `i18n.inputMethod.kime` instead.
- `tut` has been updated from 1.0.34 to 2.0.0, and now uses the TOML format for the configuration file instead of INI. Additional information can be found [here](https://github.com/RasmusLindroth/tut/releases/tag/2.0.0).
@@ -223,11 +208,6 @@ In addition to numerous new and upgraded packages, this release has the followin
- The [services.wordpress.sites.&lt;name&gt;.plugins](#opt-services.wordpress.sites._name_.plugins) and [services.wordpress.sites.&lt;name&gt;.themes](#opt-services.wordpress.sites._name_.themes) options have been converted from sets to attribute sets to allow for consumers to specify explicit install paths via attribute name.
- [`services.nextcloud.database.createLocally`](#opt-services.nextcloud.database.createLocally) now uses socket authentication and is no longer compatible with password authentication.
- If you want the module to manage the database for you, unset [`services.nextcloud.config.dbpassFile`](#opt-services.nextcloud.config.dbpassFile) (and [`services.nextcloud.config.dbhost`](#opt-services.nextcloud.config.dbhost), if it's set).
- If your database is external, simply set [`services.nextcloud.database.createLocally`](#opt-services.nextcloud.database.createLocally) to `false`.
- If you want to use password authentication **and** create the database locally, you will have to use [`services.mysql`](#opt-services.mysql.enable) to set it up.
- `protonmail-bridge` package has been updated to major version 3.
- Nebula now runs as a system user and group created for each nebula network, using the `CAP_NET_ADMIN` ambient capability on launch rather than starting as root. Ensure that any files each Nebula instance needs to access are owned by the correct user and group, by default `nebula-${networkName}`.
@@ -255,14 +235,10 @@ In addition to numerous new and upgraded packages, this release has the followin
[upstream's release notes](https://github.com/iputils/iputils/releases/tag/20221126)
for more details and available replacements.
- The ppp plugin `rp-pppoe.so` has been renamed to `pppoe.so` in ppp 2.4.9. Starting from ppp 2.5.0, there is no longer a alias for backwards compatiblity. Configurations that use this plugin must be updated accordingly from `plugin rp-pppoe.so` to `plugin pppoe.so`. See [upstream change](https://github.com/ppp-project/ppp/commit/610a7bd76eb1f99f22317541b35001b1e24877ed).
- [services.xserver.videoDrivers](options.html#opt-services.xserver.videoDrivers) now defaults to the `modesetting` driver over device-specific ones. The `radeon`, `amdgpu` and `nouveau` drivers are still available, but effectively unmaintained and not recommended for use.
- To enable the HTTP3 (QUIC) protocol for a nginx virtual host, set the `quic` attribute on it to true, e.g. `services.nginx.virtualHosts.<name>.quic = true;`.
- In `services.fail2ban`, `bantime-increment.<name>` options now default to `null` (except `bantime-increment.enable`) and are used to set the corresponding option in `jail.local` only if not `null`. Also, enforce that `bantime-increment.formula` and `bantime-increment.multipliers` are not both specified.
- The default Asterisk package was changed to v20 from v19. Asterisk versions 16 and 19 have been dropped due to being EOL. You may need to update /var/lib/asterisk to match the template files in `${asterisk-20}/var/lib/asterisk`.
- conntrack helper autodetection has been removed from kernels 6.0 and up upstream, and an assertion was added to ensure things don't silently stop working. Migrate your configuration to assign helpers explicitly or use an older LTS kernel branch as a temporary workaround.
@@ -279,8 +255,6 @@ In addition to numerous new and upgraded packages, this release has the followin
- The `baget` package and module was removed due to being unmaintained.
- The `qlandkartegt` and `garmindev` packages were removed due to being unmaintained and insecure.
- `go-ethereum` package has been updated to v1.11.5 and the `puppeth` command is no longer available as of v1.11.0.
- The `pnpm` package has be updated to from version 7.29.1 to version 8.1.1 and Node.js 14 support has been discontinued (though, there are workarounds if Node.js 14 is still required)
@@ -332,9 +306,7 @@ In addition to numerous new and upgraded packages, this release has the followin
replacement. It stores backups as volume dump files and thus better integrates
into contemporary backup solutions.
- `services.maddy` got several updates:
- Configuration of users and their credentials using `services.maddy.ensureCredentials`.
- Configuration of TLS key and certificate files using `services.maddy.tls`.
- `services.maddy` now allows to configure users and their credentials using `services.maddy.ensureCredentials`.
- The `dnsmasq` service now takes configuration via the
`services.dnsmasq.settings` attribute set. The option

View File

@@ -33,7 +33,6 @@ let
];
specialArgs = {
inherit config pkgs utils;
class = "nixos";
};
};
docs = import "${nixosPath}/doc/manual" {

View File

@@ -38,7 +38,6 @@ let
# is experimental.
lib.evalModules {
inherit prefix modules;
class = "nixos";
specialArgs = {
modulesPath = builtins.toString ../modules;
} // specialArgs;

View File

@@ -38,8 +38,6 @@ let pkgs_ = pkgs;
in
let
inherit (lib) optional;
evalModulesMinimal = (import ./default.nix {
inherit lib;
# Implicit use of feature is noted in implementation.
@@ -49,19 +47,15 @@ let
pkgsModule = rec {
_file = ./eval-config.nix;
key = _file;
config = lib.mkMerge (
(optional (system != null) {
# Explicit `nixpkgs.system` or `nixpkgs.localSystem` should override
# this. Since the latter defaults to the former, the former should
# default to the argument. That way this new default could propagate all
# they way through, but has the last priority behind everything else.
nixpkgs.system = lib.mkDefault system;
})
++
(optional (pkgs_ != null) {
_module.args.pkgs = lib.mkForce pkgs_;
})
);
config = {
# Explicit `nixpkgs.system` or `nixpkgs.localSystem` should override
# this. Since the latter defaults to the former, the former should
# default to the argument. That way this new default could propagate all
# they way through, but has the last priority behind everything else.
nixpkgs.system = lib.mkIf (system != null) (lib.mkDefault system);
_module.args.pkgs = lib.mkIf (pkgs_ != null) (lib.mkForce pkgs_);
};
};
withWarnings = x:

View File

@@ -3,6 +3,7 @@ import argparse
import ptpython.repl
import os
import time
import json
from test_driver.logger import rootlog
from test_driver.driver import Driver
@@ -77,6 +78,13 @@ def main() -> None:
nargs="*",
help="vlans to span by the driver",
)
arg_parser.add_argument(
"--tpms",
metavar="TPMs",
action=EnvDefault,
envvar="tpms",
help="tpms blob to initialize by the driver (in JSON)",
)
arg_parser.add_argument(
"-o",
"--output_directory",
@@ -101,6 +109,7 @@ def main() -> None:
with Driver(
args.start_scripts,
args.vlans,
json.loads(args.tpms),
args.testscript.read_text(),
args.output_directory.resolve(),
args.keep_vm_state,
@@ -120,7 +129,7 @@ def generate_driver_symbols() -> None:
in user's test scripts. That list is then used by pyflakes to lint those
scripts.
"""
d = Driver([], [], "", Path())
d = Driver([], [], [], "", Path())
test_symbols = d.test_symbols()
with open("driver-symbols", "w") as fp:
fp.write(",".join(test_symbols.keys()))

View File

@@ -1,13 +1,23 @@
from contextlib import contextmanager
from pathlib import Path
from typing import Any, Dict, Iterator, List, Union, Optional, Callable, ContextManager
from typing import (
Any,
Dict,
Iterator,
List,
Union,
Optional,
Callable,
ContextManager,
Tuple,
)
import os
import re
import tempfile
from test_driver.logger import rootlog
from test_driver.machine import Machine, NixStartScript, retry
from test_driver.vlan import VLan
from test_driver.tpm import Tpm
from test_driver.polling_condition import PollingCondition
@@ -29,10 +39,6 @@ def get_tmp_dir() -> Path:
return tmp_dir
def pythonize_name(name: str) -> str:
return re.sub(r"^[^A-z_]|[^A-z0-9_]", "_", name)
class Driver:
"""A handle to the driver that sets up the environment
and runs the tests"""
@@ -40,18 +46,21 @@ class Driver:
tests: str
vlans: List[VLan]
machines: List[Machine]
tpms: Dict[str, Tpm]
polling_conditions: List[PollingCondition]
def __init__(
self,
start_scripts: List[str],
vlans: List[int],
tpms: List[Dict[str, str]],
tests: str,
out_dir: Path,
keep_vm_state: bool = False,
):
self.tests = tests
self.out_dir = out_dir
self.polling_conditions = []
tmp_dir = get_tmp_dir()
@@ -59,12 +68,22 @@ class Driver:
vlans = list(set(vlans))
self.vlans = [VLan(nr, tmp_dir) for nr in vlans]
with rootlog.nested("start all TPMs"):
self.tpms = {
tpm_data["machine_name"]: Tpm(
tpm_data["swtpm_binary_path"], tpm_data["socket_path"]
)
for tpm_data in tpms
}
for tpm in self.tpms.values():
tpm.start()
# Monitor TPMs for unexpected crashes.
self.polling_conditions.append(PollingCondition(tpm.check))
def cmd(scripts: List[str]) -> Iterator[NixStartScript]:
for s in scripts:
yield NixStartScript(s)
self.polling_conditions = []
self.machines = [
Machine(
start_command=cmd,
@@ -73,6 +92,7 @@ class Driver:
tmp_dir=tmp_dir,
callbacks=[self.check_polling_conditions],
out_dir=self.out_dir,
tpm=self.tpms.get(cmd.machine_name),
)
for cmd in cmd(start_scripts)
]
@@ -116,13 +136,17 @@ class Driver:
serial_stdout_off=self.serial_stdout_off,
serial_stdout_on=self.serial_stdout_on,
polling_condition=self.polling_condition,
Machine=Machine, # for typing
# for typing
Machine=Machine,
Tpm=Tpm,
)
machine_symbols = {pythonize_name(m.name): m for m in self.machines}
machine_symbols = {m.name: m for m in self.machines}
tpm_symbols = {f"tpm_{m.name}": m.tpm for m in self.machines}
# If there's exactly one machine, make it available under the name
# "machine", even if it's not called that.
if len(self.machines) == 1:
(machine_symbols["machine"],) = self.machines
(tpm_symbols["tpm_machine"],) = self.tpms.values()
vlan_symbols = {
f"vlan{v.nr}": self.vlans[idx] for idx, v in enumerate(self.vlans)
}
@@ -130,11 +154,13 @@ class Driver:
"additionally exposed symbols:\n "
+ ", ".join(map(lambda m: m.name, self.machines))
+ ",\n "
+ ", ".join(self.tpms.keys())
+ ",\n "
+ ", ".join(map(lambda v: f"vlan{v.nr}", self.vlans))
+ ",\n "
+ ", ".join(list(general_symbols.keys()))
)
return {**general_symbols, **machine_symbols, **vlan_symbols}
return {**general_symbols, **machine_symbols, **vlan_symbols, **tpm_symbols}
def test_script(self) -> None:
"""Run the test script"""

View File

@@ -17,6 +17,7 @@ import threading
import time
from test_driver.logger import rootlog
from test_driver.tpm import Tpm
CHAR_TO_KEY = {
"A": "shift-a",
@@ -318,6 +319,8 @@ class Machine:
shell: Optional[socket.socket]
serial_thread: Optional[threading.Thread]
tpm: Tpm | None
booted: bool
connected: bool
# Store last serial console lines for use
@@ -336,6 +339,7 @@ class Machine:
name: str = "machine",
keep_vm_state: bool = False,
callbacks: Optional[List[Callable]] = None,
tpm: Optional[Tpm] = None,
) -> None:
self.out_dir = out_dir
self.tmp_dir = tmp_dir
@@ -343,6 +347,7 @@ class Machine:
self.name = name
self.start_command = start_command
self.callbacks = callbacks if callbacks is not None else []
self.tpm = tpm
# set up directories
self.shared_dir = self.tmp_dir / "shared-xchg"

View File

@@ -0,0 +1,54 @@
import subprocess
from tempfile import TemporaryDirectory
class Tpm:
"""
This is a TPM driver for QEMU tests.
It gives you access to a TPM socket path on the host
you can access at `tpm_socket_path`.
"""
state_dir: TemporaryDirectory
swtpm_binary_path: str
tpm_socket_path: str
def __init__(self, swtpm_binary_path: str, tpm_socket_path: str):
self.state_dir = TemporaryDirectory()
self.swtpm_binary_path = swtpm_binary_path
self.tpm_socket_path = tpm_socket_path
self.start()
def start(self) -> None:
"""
Start swtpm binary and wait for its proper startup.
In case of failure, this will raise a runtime error.
"""
self.proc = subprocess.Popen(
[
self.swtpm_binary_path,
"socket",
"--tpmstate",
f"dir={self.state_dir.name}",
"--ctrl",
f"type=unixio,path={self.tpm_socket_path}",
"--tpm2",
]
)
# Check whether starting swtpm failed
try:
exit_code = self.proc.wait(timeout=0.2)
if exit_code is not None and exit_code != 0:
raise RuntimeError(f"failed to start swtpm, exit code: {exit_code}")
except subprocess.TimeoutExpired:
pass
def check(self) -> None:
"""
Check whether the swtpm process exited due to an error
Useful as a @polling_condition.
"""
exit_code = self.proc.poll()
if exit_code is not None and exit_code != 0:
raise RuntimeError("swtpm process died")

View File

@@ -3,6 +3,7 @@
from test_driver.driver import Driver
from test_driver.vlan import VLan
from test_driver.tpm import Tpm
from test_driver.machine import Machine
from test_driver.logger import Logger
from typing import Callable, Iterator, ContextManager, Optional, List, Dict, Any, Union

View File

@@ -1,10 +1,7 @@
{ lib }:
let
evalTest = module: lib.evalModules {
modules = testModules ++ [ module ];
class = "nixosTest";
};
evalTest = module: lib.evalModules { modules = testModules ++ [ module ]; };
runTest = module: (evalTest ({ config, ... }: { imports = [ module ]; result = config.test; })).config.result;
testModules = [

View File

@@ -14,6 +14,14 @@ let
vlans = map (m: m.virtualisation.vlans) (lib.attrValues config.nodes);
vms = map (m: m.system.build.vm) (lib.attrValues config.nodes);
tpms = map (n:
let m = config.nodes.${n};
in
{
swtpm_binary_path = "${lib.getExe m.virtualisation.tpm.package}";
socket_path = "${m.virtualisation.tpm.socketPath}";
machine_name = n;
}) (lib.attrNames config.nodes);
nodeHostNames =
let
@@ -21,20 +29,36 @@ let
in
nodesList ++ lib.optional (lib.length nodesList == 1 && !lib.elem "machine" nodesList) "machine";
pythonizeName = name:
let
head = lib.substring 0 1 name;
tail = lib.substring 1 (-1) name;
in
(if builtins.match "[A-z_]" head == null then "_" else head) +
lib.stringAsChars (c: if builtins.match "[A-z0-9_]" c == null then "_" else c) tail;
# TODO: This is an implementation error and needs fixing
# the testing famework cannot legitimately restrict hostnames further
# beyond RFC1035
invalidNodeNames = lib.filter
(node: builtins.match "^[A-z_]([A-z0-9_]+)?$" node == null)
nodeHostNames;
uniqueVlans = lib.unique (builtins.concatLists vlans);
vlanNames = map (i: "vlan${toString i}: VLan;") uniqueVlans;
pythonizedNames = map pythonizeName nodeHostNames;
machineNames = map (name: "${name}: Machine;") pythonizedNames;
machineNames = map (name: "${name}: Machine;") nodeHostNames;
tpmNames = map (name:
let
tpmConfig = config.nodes.${name}.virtualisation.tpm;
in
''tpm_${name}: Tpm = Tpm(\"${lib.getExe tpmConfig.package}\", \"${tpmConfig.socketPath}\")''
) (lib.attrNames config.nodes);
withChecks = lib.warnIf config.skipLint "Linting is disabled";
withChecks =
if lib.length invalidNodeNames > 0 then
throw ''
Cannot create machines out of (${lib.concatStringsSep ", " invalidNodeNames})!
All machines are referenced as python variables in the testing framework which will break the
script when special characters are used.
This is an IMPLEMENTATION ERROR and needs to be fixed. Meanwhile,
please stick to alphanumeric chars and underscores as separation.
''
else
lib.warnIf config.skipLint "Linting is disabled";
driver =
hostPkgs.runCommand "nixos-test-driver-${config.name}"
@@ -61,6 +85,7 @@ let
cat "${../test-script-prepend.py}" >> testScriptWithTypes
echo "${builtins.toString machineNames}" >> testScriptWithTypes
echo "${builtins.toString vlanNames}" >> testScriptWithTypes
echo "${builtins.toString tpmNames}" >> testScriptWithTypes
echo -n "$testScript" >> testScriptWithTypes
cat -n testScriptWithTypes
@@ -78,7 +103,7 @@ let
${testDriver}/bin/generate-driver-symbols
${lib.optionalString (!config.skipLint) ''
PYFLAKES_BUILTINS="$(
echo -n ${lib.escapeShellArg (lib.concatStringsSep "," pythonizedNames)},
echo -n ${lib.escapeShellArg (lib.concatStringsSep "," nodeHostNames)},
< ${lib.escapeShellArg "driver-symbols"}
)" ${hostPkgs.python3Packages.pyflakes}/bin/pyflakes $out/test-script
''}
@@ -89,6 +114,7 @@ let
--set startScripts "''${vmStartScripts[*]}" \
--set testScript "$out/test-script" \
--set vlans '${toString vlans}' \
--set tpms '${builtins.toJSON tpms}' \
${lib.escapeShellArgs (lib.concatMap (arg: ["--add-flags" arg]) config.extraDriverArgs)}
'';

View File

@@ -1,22 +1,13 @@
testModuleArgs@{ config, lib, hostPkgs, nodes, ... }:
let
inherit (lib)
literalExpression
literalMD
mapAttrs
mdDoc
mkDefault
mkIf
mkOption mkForce
optional
optionalAttrs
types
;
inherit (lib) mkOption mkForce optional types mapAttrs mkDefault mdDoc;
system = hostPkgs.stdenv.hostPlatform.system;
baseOS =
import ../eval-config.nix {
system = null; # use modularly defined system
inherit system;
inherit (config.node) specialArgs;
modules = [ config.defaults ];
baseModules = (import ../../modules/module-list.nix) ++
@@ -26,17 +17,11 @@ let
({ config, ... }:
{
virtualisation.qemu.package = testModuleArgs.config.qemu.package;
})
(optionalAttrs (!config.node.pkgsReadOnly) {
key = "nodes.nix-pkgs";
config = {
# Ensure we do not use aliases. Ideally this is only set
# when the test framework is used by Nixpkgs NixOS tests.
nixpkgs.config.allowAliases = false;
# TODO: switch to nixpkgs.hostPlatform and make sure containers-imperative test still evaluates.
nixpkgs.system = hostPkgs.stdenv.hostPlatform.system;
};
})
})
testModuleArgs.config.extraBaseModules
];
};
@@ -83,30 +68,6 @@ in
default = { };
};
node.pkgs = mkOption {
description = mdDoc ''
The Nixpkgs to use for the nodes.
Setting this will make the `nixpkgs.*` options read-only, to avoid mistakenly testing with a Nixpkgs configuration that diverges from regular use.
'';
type = types.nullOr types.pkgs;
default = null;
defaultText = literalMD ''
`null`, so construct `pkgs` according to the `nixpkgs.*` options as usual.
'';
};
node.pkgsReadOnly = mkOption {
description = mdDoc ''
Whether to make the `nixpkgs.*` options read-only. This is only relevant when [`node.pkgs`](#test-opt-node.pkgs) is set.
Set this to `false` when any of the [`nodes`](#test-opt-nodes) needs to configure any of the `nixpkgs.*` options. This will slow down evaluation of your test a bit.
'';
type = types.bool;
default = config.node.pkgs != null;
defaultText = literalExpression ''node.pkgs != null'';
};
node.specialArgs = mkOption {
type = types.lazyAttrsOf types.raw;
default = { };
@@ -139,11 +100,5 @@ in
config.nodes;
passthru.nodes = config.nodesCompat;
defaults = mkIf config.node.pkgsReadOnly {
nixpkgs.pkgs = config.node.pkgs;
imports = [ ../../modules/misc/nixpkgs/read-only.nix ];
};
};
}

View File

@@ -25,7 +25,6 @@ let
path = makeBinPath [
pkgs.jq
nixos-enter
pkgs.util-linuxMinimal
];
};
@@ -66,9 +65,6 @@ let
name = "nixos-enter";
src = ./nixos-enter.sh;
inherit (pkgs) runtimeShell;
path = makeBinPath [
pkgs.util-linuxMinimal
];
};
in
@@ -127,7 +123,7 @@ in
system.nixos-generate-config.configuration = mkDefault ''
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running `nixos-help`).
# and in the NixOS manual (accessible by running nixos-help).
{ config, pkgs, ... }:
@@ -218,7 +214,7 @@ in
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. It's perfectly fine and recommended to leave
# on your system were taken. Its perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).

View File

@@ -38,7 +38,6 @@ let
modules = [ {
_module.check = false;
} ] ++ docModules.eager;
class = "nixos";
specialArgs = specialArgs // {
pkgs = scrubDerivations "pkgs" pkgs;
# allow access to arbitrary options for eager modules, eg for getting

View File

@@ -49,10 +49,10 @@ let
merge = lib.mergeOneOption;
};
pkgsType = types.pkgs // {
# This type is only used by itself, so let's elaborate the description a bit
# for the purpose of documentation.
pkgsType = mkOptionType {
name = "nixpkgs";
description = "An evaluation of Nixpkgs; the top level attribute set of packages";
check = builtins.isAttrs;
};
# Whether `pkgs` was constructed by this module - not if nixpkgs.pkgs or

View File

@@ -1,74 +0,0 @@
# A replacement for the traditional nixpkgs module, such that none of the modules
# can add their own configuration. This ensures that the Nixpkgs configuration is
# exactly as the user intends.
# This may also be used as a performance optimization when evaluating multiple
# configurations at once, with a shared `pkgs`.
# This is a separate module, because merging this logic into the nixpkgs module
# is too burdensome, considering that it is already burdened with legacy.
# Moving this logic into a module does not lose any composition benefits, because
# its purpose is not something that composes anyway.
{ lib, config, ... }:
let
cfg = config.nixpkgs;
inherit (lib) mkOption types;
in
{
disabledModules = [
../nixpkgs.nix
];
options = {
nixpkgs = {
pkgs = mkOption {
type = lib.types.pkgs;
description = lib.mdDoc ''The pkgs module argument.'';
};
config = mkOption {
internal = true;
type = types.unique { message = "nixpkgs.config is set to read-only"; } types.anything;
description = lib.mdDoc ''
The Nixpkgs `config` that `pkgs` was initialized with.
'';
};
overlays = mkOption {
internal = true;
type = types.unique { message = "nixpkgs.overlays is set to read-only"; } types.anything;
description = lib.mdDoc ''
The Nixpkgs overlays that `pkgs` was initialized with.
'';
};
hostPlatform = mkOption {
internal = true;
readOnly = true;
description = lib.mdDoc ''
The platform of the machine that is running the NixOS configuration.
'';
};
buildPlatform = mkOption {
internal = true;
readOnly = true;
description = lib.mdDoc ''
The platform of the machine that built the NixOS configuration.
'';
};
# NOTE: do not add the legacy options such as localSystem here. Let's keep
# this module simple and let module authors upgrade their code instead.
};
};
config = {
_module.args.pkgs =
# find mistaken definitions
builtins.seq cfg.config
builtins.seq cfg.overlays
builtins.seq cfg.hostPlatform
builtins.seq cfg.buildPlatform
cfg.pkgs;
nixpkgs.config = cfg.pkgs.config;
nixpkgs.overlays = cfg.pkgs.overlays;
nixpkgs.hostPlatform = cfg.pkgs.stdenv.hostPlatform;
nixpkgs.buildPlatform = cfg.pkgs.stdenv.buildPlatform;
};
}

View File

@@ -1,5 +1,3 @@
# [nixpkgs]$ nix-build -A nixosTests.nixpkgs --show-trace
{ evalMinimalConfig, pkgs, lib, stdenv }:
let
eval = mod: evalMinimalConfig {
@@ -29,47 +27,6 @@ let
let
uncheckedEval = lib.evalModules { modules = [ ../nixpkgs.nix module ]; };
in map (ass: ass.message) (lib.filter (ass: !ass.assertion) uncheckedEval.config.assertions);
readOnlyUndefined = evalMinimalConfig {
imports = [ ./read-only.nix ];
};
readOnlyBad = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = { };
};
readOnly = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = pkgs;
};
readOnlyBadConfig = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = pkgs;
nixpkgs.config.allowUnfree = true; # do in pkgs instead!
};
readOnlyBadOverlays = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = pkgs;
nixpkgs.overlays = [ (_: _: {}) ]; # do in pkgs instead!
};
readOnlyBadHostPlatform = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = pkgs;
nixpkgs.hostPlatform = "foo-linux"; # do in pkgs instead!
};
readOnlyBadBuildPlatform = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = pkgs;
nixpkgs.buildPlatform = "foo-linux"; # do in pkgs instead!
};
throws = x: ! (builtins.tryEval x).success;
in
lib.recurseIntoAttrs {
invokeNixpkgsSimple =
@@ -108,21 +65,5 @@ lib.recurseIntoAttrs {
nixpkgs.pkgs = pkgs;
} == [];
# Tests for the read-only.nix module
assert readOnly._module.args.pkgs.stdenv.hostPlatform.system == pkgs.stdenv.hostPlatform.system;
assert throws readOnlyBad._module.args.pkgs.stdenv;
assert throws readOnlyUndefined._module.args.pkgs.stdenv;
assert throws readOnlyBadConfig._module.args.pkgs.stdenv;
assert throws readOnlyBadOverlays._module.args.pkgs.stdenv;
assert throws readOnlyBadHostPlatform._module.args.pkgs.stdenv;
assert throws readOnlyBadBuildPlatform._module.args.pkgs.stdenv;
# read-only.nix does not provide legacy options, for the sake of simplicity
# If you're bothered by this, upgrade your configs to use the new *Platform
# options.
assert !readOnly.options.nixpkgs?system;
assert !readOnly.options.nixpkgs?localSystem;
assert !readOnly.options.nixpkgs?crossSystem;
pkgs.emptyFile;
}

View File

@@ -413,9 +413,6 @@
./services/desktops/bamf.nix
./services/desktops/blueman.nix
./services/desktops/cpupower-gui.nix
./services/desktops/deepin/dde-api.nix
./services/desktops/deepin/app-services.nix
./services/desktops/deepin/dde-daemon.nix
./services/desktops/dleyna-renderer.nix
./services/desktops/dleyna-server.nix
./services/desktops/espanso.nix
@@ -444,7 +441,6 @@
./services/desktops/pipewire/wireplumber.nix
./services/desktops/profile-sync-daemon.nix
./services/desktops/system-config-printer.nix
./services/desktops/system76-scheduler.nix
./services/desktops/telepathy.nix
./services/desktops/tumbler.nix
./services/desktops/zeitgeist.nix
@@ -1113,7 +1109,6 @@
./services/security/torsocks.nix
./services/security/usbguard.nix
./services/security/vault.nix
./services/security/vault-agent.nix
./services/security/vaultwarden/default.nix
./services/security/yubikey-agent.nix
./services/system/automatic-timezoned.nix
@@ -1184,7 +1179,6 @@
./services/web-apps/jirafeau.nix
./services/web-apps/jitsi-meet.nix
./services/web-apps/kasmweb/default.nix
./services/web-apps/kavita.nix
./services/web-apps/keycloak.nix
./services/web-apps/komga.nix
./services/web-apps/lemmy.nix

View File

@@ -1,9 +1,8 @@
{ pkgs, config, lib, ... }:
{pkgs, config, lib, ...}:
with lib;
let
cfg = config.programs.fzf;
in
{
in {
options = {
programs.fzf = {
fuzzyCompletion = mkEnableOption (mdDoc "fuzzy completion with fzf");
@@ -12,21 +11,17 @@ in
};
config = {
environment.systemPackages = optional (cfg.keybindings || cfg.fuzzyCompletion) pkgs.fzf;
programs.bash.interactiveShellInit = optionalString cfg.fuzzyCompletion ''
source ${pkgs.fzf}/share/fzf/completion.bash
'' + optionalString cfg.keybindings ''
source ${pkgs.fzf}/share/fzf/key-bindings.bash
'';
programs.zsh.interactiveShellInit = optionalString (!config.programs.zsh.ohMyZsh.enable)
(optionalString cfg.fuzzyCompletion ''
source ${pkgs.fzf}/share/fzf/completion.zsh
'' + optionalString cfg.keybindings ''
source ${pkgs.fzf}/share/fzf/key-bindings.zsh
'');
programs.zsh.ohMyZsh.plugins = optional (cfg.keybindings || cfg.fuzzyCompletion) [ "fzf" ];
programs.zsh.interactiveShellInit = optionalString cfg.fuzzyCompletion ''
source ${pkgs.fzf}/share/fzf/completion.zsh
'' + optionalString cfg.keybindings ''
source ${pkgs.fzf}/share/fzf/key-bindings.zsh
'';
};
meta.maintainers = with maintainers; [ laalsaas ];
}

View File

@@ -57,14 +57,17 @@ in
};
config = mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
environment = {
systemPackages = [ cfg.package ];
};
fonts.enableDefaultFonts = mkDefault true;
hardware.opengl.enable = mkDefault true;
programs = {
dconf.enable = mkDefault true;
xwayland.enable = mkDefault cfg.xwayland.enable;
xwayland.enable = mkDefault true;
};
security.polkit.enable = true;

View File

@@ -11,8 +11,6 @@ in {
enable = mkEnableOption (lib.mdDoc "Navidrome music server");
package = mkPackageOptionMD pkgs "navidrome" { };
settings = mkOption rec {
type = settingsFormat.type;
apply = recursiveUpdate default;
@@ -38,7 +36,7 @@ in {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = ''
${cfg.package}/bin/navidrome --configfile ${settingsFormat.generate "navidrome.json" cfg.settings}
${pkgs.navidrome}/bin/navidrome --configfile ${settingsFormat.generate "navidrome.json" cfg.settings}
'';
DynamicUser = true;
StateDirectory = "navidrome";

View File

@@ -339,7 +339,6 @@ in
RuntimeDirectory = "restic-backups-${name}";
CacheDirectory = "restic-backups-${name}";
CacheDirectoryMode = "0700";
PrivateTmp = true;
} // optionalAttrs (backup.environmentFile != null) {
EnvironmentFile = backup.environmentFile;
};

View File

@@ -35,9 +35,6 @@ in
ExecStartPre = testCommand;
Restart = "on-failure";
RestartSec = 120;
LimitSTACK = 256 * 1024 * 1024;
OOMPolicy = "continue";
};
};

View File

@@ -1,36 +0,0 @@
{ config, pkgs, lib, ... }:
with lib;
{
meta = {
maintainers = teams.deepin.members;
};
###### interface
options = {
services.deepin.app-services = {
enable = mkEnableOption (lib.mdDoc "Service collection of DDE applications, including dconfig-center");
};
};
###### implementation
config = mkIf config.services.deepin.app-services.enable {
environment.systemPackages = [ pkgs.deepin.dde-app-services ];
services.dbus.packages = [ pkgs.deepin.dde-app-services ];
environment.pathsToLink = [ "/share/dsg" ];
};
}

View File

@@ -1,50 +0,0 @@
{ config, pkgs, lib, ... }:
with lib;
{
meta = {
maintainers = teams.deepin.members;
};
###### interface
options = {
services.deepin.dde-api = {
enable = mkEnableOption (lib.mdDoc ''
Provides some dbus interfaces that is used for screen zone detecting,
thumbnail generating, and sound playing in Deepin Desktop Enviroment.
'');
};
};
###### implementation
config = mkIf config.services.deepin.dde-api.enable {
environment.systemPackages = [ pkgs.deepin.dde-api ];
services.dbus.packages = [ pkgs.deepin.dde-api ];
systemd.packages = [ pkgs.deepin.dde-api ];
environment.pathsToLink = [ "/lib/deepin-api" ];
users.groups.deepin-sound-player = { };
users.users.deepin-sound-player = {
description = "Deepin sound player";
home = "/var/lib/deepin-sound-player";
createHome = true;
group = "deepin-sound-player";
isSystemUser = true;
};
};
}

View File

@@ -1,40 +0,0 @@
{ config, pkgs, lib, ... }:
with lib;
{
meta = {
maintainers = teams.deepin.members;
};
###### interface
options = {
services.deepin.dde-daemon = {
enable = mkEnableOption (lib.mdDoc "Daemon for handling the deepin session settings");
};
};
###### implementation
config = mkIf config.services.deepin.dde-daemon.enable {
environment.systemPackages = [ pkgs.deepin.dde-daemon ];
services.dbus.packages = [ pkgs.deepin.dde-daemon ];
services.udev.packages = [ pkgs.deepin.dde-daemon ];
systemd.packages = [ pkgs.deepin.dde-daemon ];
environment.pathsToLink = [ "/lib/deepin-daemon" ];
};
}

View File

@@ -1,296 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.system76-scheduler;
inherit (builtins) concatStringsSep map toString attrNames;
inherit (lib) boolToString types mkOption literalExpression mdDoc optional mkIf mkMerge;
inherit (types) nullOr listOf bool int ints float str enum;
withDefaults = optionSpecs: defaults:
lib.genAttrs (attrNames optionSpecs) (name:
mkOption (optionSpecs.${name} // {
default = optionSpecs.${name}.default or defaults.${name} or null;
}));
latencyProfile = withDefaults {
latency = {
type = int;
description = mdDoc "`sched_latency_ns`.";
};
nr-latency = {
type = int;
description = mdDoc "`sched_nr_latency`.";
};
wakeup-granularity = {
type = float;
description = mdDoc "`sched_wakeup_granularity_ns`.";
};
bandwidth-size = {
type = int;
description = mdDoc "`sched_cfs_bandwidth_slice_us`.";
};
preempt = {
type = enum [ "none" "voluntary" "full" ];
description = mdDoc "Preemption mode.";
};
};
schedulerProfile = withDefaults {
nice = {
type = nullOr (ints.between (-20) 19);
description = mdDoc "Niceness.";
};
class = {
type = nullOr (enum [ "idle" "batch" "other" "rr" "fifo" ]);
example = literalExpression "\"batch\"";
description = mdDoc "CPU scheduler class.";
};
prio = {
type = nullOr (ints.between 1 99);
example = literalExpression "49";
description = mdDoc "CPU scheduler priority.";
};
ioClass = {
type = nullOr (enum [ "idle" "best-effort" "realtime" ]);
example = literalExpression "\"best-effort\"";
description = mdDoc "IO scheduler class.";
};
ioPrio = {
type = nullOr (ints.between 0 7);
example = literalExpression "4";
description = mdDoc "IO scheduler priority.";
};
matchers = {
type = nullOr (listOf str);
default = [];
example = literalExpression ''
[
"include cgroup=\"/user.slice/*.service\" parent=\"systemd\""
"emacs"
]
'';
description = mdDoc "Process matchers.";
};
};
cfsProfileToString = name: let
p = cfg.settings.cfsProfiles.${name};
in
"${name} latency=${toString p.latency} nr-latency=${toString p.nr-latency} wakeup-granularity=${toString p.wakeup-granularity} bandwidth-size=${toString p.bandwidth-size} preempt=\"${p.preempt}\"";
prioToString = class: prio: if prio == null then "\"${class}\"" else "(${class})${toString prio}";
schedulerProfileToString = name: a: indent:
concatStringsSep " "
(["${indent}${name}"]
++ (optional (a.nice != null) "nice=${toString a.nice}")
++ (optional (a.class != null) "sched=${prioToString a.class a.prio}")
++ (optional (a.ioClass != null) "io=${prioToString a.ioClass a.ioPrio}")
++ (optional ((builtins.length a.matchers) != 0) ("{\n${concatStringsSep "\n" (map (m: " ${indent}${m}") a.matchers)}\n${indent}}")));
in {
options = {
services.system76-scheduler = {
enable = lib.mkEnableOption (lib.mdDoc "system76-scheduler");
package = mkOption {
type = types.package;
default = config.boot.kernelPackages.system76-scheduler;
defaultText = literalExpression "config.boot.kernelPackages.system76-scheduler";
description = mdDoc "Which System76-Scheduler package to use.";
};
useStockConfig = mkOption {
type = bool;
default = true;
description = mdDoc ''
Use the (reasonable and featureful) stock configuration.
When this option is `true`, `services.system76-scheduler.settings`
are ignored.
'';
};
settings = {
cfsProfiles = {
enable = mkOption {
type = bool;
default = true;
description = mdDoc "Tweak CFS latency parameters when going on/off battery";
};
default = latencyProfile {
latency = 6;
nr-latency = 8;
wakeup-granularity = 1.0;
bandwidth-size = 5;
preempt = "voluntary";
};
responsive = latencyProfile {
latency = 4;
nr-latency = 10;
wakeup-granularity = 0.5;
bandwidth-size = 3;
preempt = "full";
};
};
processScheduler = {
enable = mkOption {
type = bool;
default = true;
description = mdDoc "Tweak scheduling of individual processes in real time.";
};
useExecsnoop = mkOption {
type = bool;
default = true;
description = mdDoc "Use execsnoop (otherwise poll the precess list periodically).";
};
refreshInterval = mkOption {
type = int;
default = 60;
description = mdDoc "Process list poll interval, in seconds";
};
foregroundBoost = {
enable = mkOption {
type = bool;
default = true;
description = mdDoc ''
Boost foreground process priorities.
(And de-boost background ones). Note that this option needs cooperation
from the desktop environment to work. On Gnome the client side is
implemented by the "System76 Scheduler" shell extension.
'';
};
foreground = schedulerProfile {
nice = 0;
ioClass = "best-effort";
ioPrio = 0;
};
background = schedulerProfile {
nice = 6;
ioClass = "idle";
};
};
pipewireBoost = {
enable = mkOption {
type = bool;
default = true;
description = mdDoc "Boost Pipewire client priorities.";
};
profile = schedulerProfile {
nice = -6;
ioClass = "best-effort";
ioPrio = 0;
};
};
};
};
assignments = mkOption {
type = types.attrsOf (types.submodule {
options = schedulerProfile { };
});
default = {};
example = literalExpression ''
{
nix-builds = {
nice = 15;
class = "batch";
ioClass = "idle";
matchers = [
"nix-daemon"
];
};
}
'';
description = mdDoc "Process profile assignments.";
};
exceptions = mkOption {
type = types.listOf str;
default = [];
example = literalExpression ''
[
"include descends=\"schedtool\""
"schedtool"
]
'';
description = mdDoc "Processes that are left alone.";
};
};
};
config = mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
services.dbus.packages = [ cfg.package ];
systemd.services.system76-scheduler = {
description = "Manage process priorities and CFS scheduler latencies for improved responsiveness on the desktop";
wantedBy = [ "multi-user.target" ];
path = [
# execsnoop needs those to extract kernel headers:
pkgs.kmod
pkgs.gnutar
pkgs.xz
];
serviceConfig = {
Type = "dbus";
BusName= "com.system76.Scheduler";
ExecStart = "${cfg.package}/bin/system76-scheduler daemon";
ExecReload = "${cfg.package}/bin/system76-scheduler daemon reload";
};
};
environment.etc = mkMerge [
(mkIf cfg.useStockConfig {
# No custom settings: just use stock configuration with a fix for Pipewire
"system76-scheduler/config.kdl".source = "${cfg.package}/data/config.kdl";
"system76-scheduler/process-scheduler/00-dist.kdl".source = "${cfg.package}/data/pop_os.kdl";
"system76-scheduler/process-scheduler/01-fix-pipewire-paths.kdl".source = ../../../../pkgs/os-specific/linux/system76-scheduler/01-fix-pipewire-paths.kdl;
})
(let
settings = cfg.settings;
cfsp = settings.cfsProfiles;
ps = settings.processScheduler;
in mkIf (!cfg.useStockConfig) {
"system76-scheduler/config.kdl".text = ''
version "2.0"
autogroup-enabled false
cfs-profiles enable=${boolToString cfsp.enable} {
${cfsProfileToString "default"}
${cfsProfileToString "responsive"}
}
process-scheduler enable=${boolToString ps.enable} {
execsnoop ${boolToString ps.useExecsnoop}
refresh-rate ${toString ps.refreshInterval}
assignments {
${if ps.foregroundBoost.enable then (schedulerProfileToString "foreground" ps.foregroundBoost.foreground " ") else ""}
${if ps.foregroundBoost.enable then (schedulerProfileToString "background" ps.foregroundBoost.background " ") else ""}
${if ps.pipewireBoost.enable then (schedulerProfileToString "pipewire" ps.pipewireBoost.profile " ") else ""}
}
}
'';
})
{
"system76-scheduler/process-scheduler/02-config.kdl".text =
"exceptions {\n${concatStringsSep "\n" (map (e: " ${e}") cfg.exceptions)}\n}\n"
+ "assignments {\n"
+ (concatStringsSep "\n" (map (name: schedulerProfileToString name cfg.assignments.${name} " ")
(attrNames cfg.assignments)))
+ "\n}\n";
}
];
};
meta = {
maintainers = [ lib.maintainers.cmm ];
};
}

View File

@@ -80,8 +80,7 @@ The first step to declare the list of packages you want in your Emacs
installation is to create a dedicated derivation. This can be done in a
dedicated {file}`emacs.nix` file such as:
::: {.example #ex-emacsNix}
### Nix expression to build Emacs with packages (`emacs.nix`)
[]{#ex-emacsNix}
```nix
/*
@@ -137,7 +136,6 @@ in
pkgs.notmuch # From main packages set
])
```
:::
The result of this configuration will be an {command}`emacs`
command which launches Emacs with all of your chosen packages in the
@@ -160,24 +158,19 @@ and yasnippet.
The list of available packages in the various ELPA repositories can be seen
with the following commands:
::: {.example #module-services-emacs-querying-packages}
### Querying Emacs packages
[]{#module-services-emacs-querying-packages}
```
nix-env -f "<nixpkgs>" -qaP -A emacs.pkgs.elpaPackages
nix-env -f "<nixpkgs>" -qaP -A emacs.pkgs.melpaPackages
nix-env -f "<nixpkgs>" -qaP -A emacs.pkgs.melpaStablePackages
nix-env -f "<nixpkgs>" -qaP -A emacs.pkgs.orgPackages
```
:::
If you are on NixOS, you can install this particular Emacs for all users by
adding it to the list of system packages (see
[](#sec-declarative-package-mgmt)). Simply modify your file
{file}`configuration.nix` to make it contain:
::: {.example #module-services-emacs-configuration-nix}
### Custom Emacs in `configuration.nix`
[]{#module-services-emacs-configuration-nix}
```
{
environment.systemPackages = [
@@ -186,7 +179,6 @@ adding it to the list of system packages (see
];
}
```
:::
In this case, the next {command}`nixos-rebuild switch` will take
care of adding your {command}`emacs` to the {var}`PATH`
@@ -200,9 +192,7 @@ If you are not on NixOS or want to install this particular Emacs only for
yourself, you can do so by adding it to your
{file}`~/.config/nixpkgs/config.nix` (see
[Nixpkgs manual](https://nixos.org/nixpkgs/manual/#sec-modify-via-packageOverrides)):
::: {.example #module-services-emacs-config-nix}
### Custom Emacs in `~/.config/nixpkgs/config.nix`
[]{#module-services-emacs-config-nix}
```
{
packageOverrides = super: let self = super.pkgs; in {
@@ -210,7 +200,6 @@ yourself, you can do so by adding it to your
};
}
```
:::
In this case, the next `nix-env -f '<nixpkgs>' -iA
myemacs` will take care of adding your emacs to the
@@ -225,9 +214,7 @@ automatically generated {file}`emacs.desktop` (useful if you
only use {command}`emacsclient`), you can change your file
{file}`emacs.nix` in this way:
::: {.example #ex-emacsGtk3Nix}
### Custom Emacs build
[]{#ex-emacsGtk3Nix}
```
{ pkgs ? import <nixpkgs> {} }:
let
@@ -244,9 +231,8 @@ let
});
in [...]
```
:::
After building this file as shown in [](#ex-emacsNix), you
After building this file as shown in [the example above](#ex-emacsNix), you
will get an GTK 3-based Emacs binary pre-loaded with your favorite packages.
## Running Emacs as a Service {#module-services-emacs-running}
@@ -341,10 +327,7 @@ This will add the symlink
The Emacs init file should be changed to load the extension packages at
startup:
::: {.example #module-services-emacs-package-initialisation}
### Package initialization in `.emacs`
[]{#module-services-emacs-package-initialisation}
```
(require 'package)
@@ -354,7 +337,6 @@ startup:
(setq package-enable-at-startup nil)
(package-initialize)
```
:::
After the declarative emacs package configuration has been tested,
previously downloaded packages can be cleaned up by removing
@@ -395,9 +377,7 @@ To install the DocBook 5.0 schemas, either add
Then customize the variable {var}`rng-schema-locating-files` to
include {file}`~/.emacs.d/schemas.xml` and put the following
text into that file:
::: {.example #ex-emacs-docbook-xml}
### nXML Schema Configuration (`~/.emacs.d/schemas.xml`)
[]{#ex-emacs-docbook-xml}
```xml
<?xml version="1.0"?>
<!--
@@ -417,4 +397,3 @@ text into that file:
-->
</locatingRules>
```
:::

View File

@@ -2,6 +2,8 @@
let
cfg = config.services.asusd;
json = pkgs.formats.json { };
toml = pkgs.formats.toml { };
in
{
options = {
@@ -17,55 +19,55 @@ in
};
animeConfig = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
type = json.type;
default = { };
description = lib.mdDoc ''
The content of /etc/asusd/anime.ron.
The content of /etc/asusd/anime.conf.
See https://asus-linux.org/asusctl/#anime-control.
'';
};
asusdConfig = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
type = json.type;
default = { };
description = lib.mdDoc ''
The content of /etc/asusd/asusd.ron.
The content of /etc/asusd/asusd.conf.
See https://asus-linux.org/asusctl/.
'';
};
auraConfig = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
type = json.type;
default = { };
description = lib.mdDoc ''
The content of /etc/asusd/aura.ron.
The content of /etc/asusd/aura.conf.
See https://asus-linux.org/asusctl/#led-keyboard-control.
'';
};
profileConfig = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
default = "";
description = lib.mdDoc ''
The content of /etc/asusd/profile.ron.
The content of /etc/asusd/profile.conf.
See https://asus-linux.org/asusctl/#profiles.
'';
};
fanCurvesConfig = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = lib.mdDoc ''
The content of /etc/asusd/fan_curves.ron.
See https://asus-linux.org/asusctl/#fan-curves.
ledModesConfig = lib.mkOption {
type = lib.types.nullOr toml.type;
default = null;
description = lib.mdDoc ''
The content of /etc/asusd/asusd-ledmodes.toml. Leave `null` to use default settings.
See https://asus-linux.org/asusctl/#led-keyboard-control.
'';
};
userLedModesConfig = lib.mkOption {
type = lib.types.nullOr lib.types.str;
type = lib.types.nullOr toml.type;
default = null;
description = lib.mdDoc ''
The content of /etc/asusd/asusd-user-ledmodes.ron.
The content of /etc/asusd/asusd-user-ledmodes.toml.
See https://asus-linux.org/asusctl/#led-keyboard-control.
'';
};
@@ -77,18 +79,26 @@ in
environment.etc =
let
maybeConfig = name: cfg: lib.mkIf (cfg != null) {
source = pkgs.writeText name cfg;
maybeConfig = name: cfg: lib.mkIf (cfg != { }) {
source = json.generate name cfg;
mode = "0644";
};
in
{
"asusd/anime.ron" = maybeConfig "anime.ron" cfg.animeConfig;
"asusd/asusd.ron" = maybeConfig "asusd.ron" cfg.asusdConfig;
"asusd/aura.ron" = maybeConfig "aura.ron" cfg.auraConfig;
"asusd/profile.conf" = maybeConfig "profile.ron" cfg.profileConfig;
"asusd/fan_curves.ron" = maybeConfig "fan_curves.ron" cfg.fanCurvesConfig;
"asusd/asusd_user_ledmodes.ron" = maybeConfig "asusd_user_ledmodes.ron" cfg.userLedModesConfig;
"asusd/anime.conf" = maybeConfig "anime.conf" cfg.animeConfig;
"asusd/asusd.conf" = maybeConfig "asusd.conf" cfg.asusdConfig;
"asusd/aura.conf" = maybeConfig "aura.conf" cfg.auraConfig;
"asusd/profile.conf" = lib.mkIf (cfg.profileConfig != null) {
source = pkgs.writeText "profile.conf" cfg.profileConfig;
mode = "0644";
};
"asusd/asusd-ledmodes.toml" = {
source =
if cfg.ledModesConfig == null
then "${pkgs.asusctl}/share/asusd/data/asusd-ledmodes.toml"
else toml.generate "asusd-ledmodes.toml" cfg.ledModesConfig;
mode = "0644";
};
};
services.dbus.enable = true;

View File

@@ -160,7 +160,7 @@ let
echo "Generating hwdb database..."
# hwdb --update doesn't return error code even on errors!
res="$(${pkgs.buildPackages.systemd}/bin/systemd-hwdb --root=$(pwd) update 2>&1)"
res="$(${pkgs.buildPackages.udev}/bin/udevadm hwdb --update --root=$(pwd) 2>&1)"
echo "$res"
[ -z "$(echo "$res" | egrep '^Error')" ]
mv etc/udev/hwdb.bin $out

View File

@@ -461,7 +461,6 @@ in {
"mopeka"
"oralb"
"qingping"
"rapt_ble"
"ruuvi_gateway"
"ruuvitag_ble"
"sensirion_ble"

View File

@@ -13,6 +13,8 @@ let
# configuration here https://github.com/foxcpp/maddy/blob/master/maddy.conf
# Do not use this in production!
tls off
auth.pass_table local_authdb {
table sql_table {
driver sqlite3
@@ -33,7 +35,6 @@ let
}
optional_step file /etc/maddy/aliases
}
msgpipeline local_routing {
destination postmaster $(local_domains) {
modify {
@@ -214,63 +215,6 @@ in {
'';
};
tls = {
loader = mkOption {
type = with types; nullOr (enum [ "file" "off" ]);
default = "off";
description = lib.mdDoc ''
TLS certificates are obtained by modules called "certificate
loaders". Currently only the file loader is supported which reads
certificates from files specifying the options `keyPaths` and
`certPaths`.
'';
};
certificates = mkOption {
type = with types; listOf (submodule {
options = {
keyPath = mkOption {
type = types.path;
example = "/etc/ssl/mx1.example.org.key";
description = lib.mdDoc ''
Path to the private key used for TLS.
'';
};
certPath = mkOption {
type = types.path;
example = "/etc/ssl/mx1.example.org.crt";
description = lib.mdDoc ''
Path to the certificate used for TLS.
'';
};
};
});
default = [];
example = lib.literalExpression ''
[{
keyPath = "/etc/ssl/mx1.example.org.key";
certPath = "/etc/ssl/mx1.example.org.crt";
}]
'';
description = lib.mdDoc ''
A list of attribute sets containing paths to TLS certificates and
keys. Maddy will use SNI if multiple pairs are selected.
'';
};
extraConfig = mkOption {
type = with types; nullOr lines;
description = lib.mdDoc ''
Arguments for the specific certificate loader. Note that Maddy uses
secure defaults for the TLS configuration so there is no need to
change anything in most cases.
See [upstream manual](https://maddy.email/reference/tls/) for
available options.
'';
default = "";
};
};
openFirewall = mkOption {
type = types.bool;
default = false;
@@ -280,7 +224,7 @@ in {
};
ensureAccounts = mkOption {
type = with types; listOf str;
type = types.listOf types.str;
default = [];
description = lib.mdDoc ''
List of IMAP accounts which get automatically created. Note that for
@@ -326,16 +270,6 @@ in {
config = mkIf cfg.enable {
assertions = [{
assertion = cfg.tls.loader == "file" -> cfg.tls.certificates != [];
message = ''
If maddy is configured to use TLS, tls.certificates with attribute sets
of certPath and keyPath must be provided.
Read more about obtaining TLS certificates here:
https://maddy.email/tutorials/setting-up/#tls-certificates
'';
}];
systemd = {
packages = [ pkgs.maddy ];
@@ -384,17 +318,6 @@ in {
$(primary_domain) = ${cfg.primaryDomain}
$(local_domains) = ${toString cfg.localDomains}
hostname ${cfg.hostname}
${if (cfg.tls.loader == "file") then ''
tls file ${concatStringsSep " " (
map (x: x.certPath + " " + x.keyPath
) cfg.tls.certificates)} ${optionalString (cfg.tls.extraConfig != "") ''
{ ${cfg.tls.extraConfig} }
''}
'' else if (cfg.tls.loader == "off") then ''
tls off
'' else ""}
${cfg.config}
'';
};

View File

@@ -34,7 +34,7 @@ in {
systemd.timers.fstrim = {
timerConfig = {
OnCalendar = [ "" cfg.interval ];
OnCalendar = cfg.interval;
};
wantedBy = [ "timers.target" ];
};

View File

@@ -9,7 +9,6 @@ let
env = {
GUNICORN_CMD_ARGS = "--bind=${cfg.address}:${toString cfg.port}";
DEBUG = "0";
DEBUG_TOOLBAR = "0";
MEDIA_ROOT = "/var/lib/tandoor-recipes";
} // optionalAttrs (config.time.timeZone != null) {
TIMEZONE = config.time.timeZone;

View File

@@ -235,7 +235,7 @@ in {
systemd.services = let
makeService = attrs: recursiveUpdate {
path = [ datadogPkg pkgs.sysstat pkgs.procps pkgs.iproute2 ];
path = [ datadogPkg pkgs.python pkgs.sysstat pkgs.procps pkgs.iproute2 ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = "datadog";

View File

@@ -13,7 +13,12 @@ in
options.services.grafana-agent = {
enable = mkEnableOption (lib.mdDoc "grafana-agent");
package = mkPackageOptionMD pkgs "grafana-agent" { };
package = mkOption {
type = types.package;
default = pkgs.grafana-agent;
defaultText = lib.literalExpression "pkgs.grafana-agent";
description = lib.mdDoc "The grafana-agent package to use.";
};
credentials = mkOption {
description = lib.mdDoc ''
@@ -32,22 +37,11 @@ in
};
};
extraFlags = mkOption {
type = with types; listOf str;
default = [ ];
example = [ "-enable-features=integrations-next" "-disable-reporting" ];
description = lib.mdDoc ''
Extra command-line flags passed to {command}`grafana-agent`.
See <https://grafana.com/docs/agent/latest/static/configuration/flags/>
'';
};
settings = mkOption {
description = lib.mdDoc ''
Configuration for {command}`grafana-agent`.
Configuration for `grafana-agent`.
See <https://grafana.com/docs/agent/latest/configuration/>
See https://grafana.com/docs/agent/latest/configuration/
'';
type = types.submodule {
@@ -146,7 +140,7 @@ in
# We can't use Environment=HOSTNAME=%H, as it doesn't include the domain part.
export HOSTNAME=$(< /proc/sys/kernel/hostname)
exec ${lib.getExe cfg.package} -config.expand-env -config.file ${configFile} ${escapeShellArgs cfg.extraFlags}
exec ${lib.getExe cfg.package} -config.expand-env -config.file ${configFile}
'';
serviceConfig = {
Restart = "always";

View File

@@ -92,6 +92,17 @@ let
grafanaTypes.datasourceConfig = types.submodule {
freeformType = provisioningSettingsFormat.type;
imports = [
(mkRemovedOptionModule [ "password" ] ''
`services.grafana.provision.datasources.settings.datasources.<name>.password` has been removed
in Grafana 9. Use `secureJsonData` instead.
'')
(mkRemovedOptionModule [ "basicAuthPassword" ] ''
`services.grafana.provision.datasources.settings.datasources.<name>.basicAuthPassword` has been removed
in Grafana 9. Use `secureJsonData` instead.
'')
];
options = {
name = mkOption {
type = types.str;
@@ -592,6 +603,7 @@ in {
description = lib.mdDoc "List of datasources to insert/update.";
default = [];
type = types.listOf grafanaTypes.datasourceConfig;
apply = map (flip builtins.removeAttrs [ "password" "basicAuthPassword" ]);
};
deleteDatasources = mkOption {

View File

@@ -118,56 +118,56 @@ in
default = false;
type = types.bool;
description = lib.mdDoc ''
"bantime.increment" allows to use database for searching of previously banned ip's to increase
a default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32 ...
Allows to use database for searching of previously banned ip's to increase
a default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
'';
};
bantime-increment.rndtime = mkOption {
default = null;
type = types.nullOr types.str;
default = "4m";
type = types.str;
example = "8m";
description = lib.mdDoc ''
"bantime.rndtime" is the max number of seconds using for mixing with random time
"bantime-increment.rndtime" is the max number of seconds using for mixing with random time
to prevent "clever" botnets calculate exact time IP can be unbanned again
'';
};
bantime-increment.maxtime = mkOption {
default = null;
type = types.nullOr types.str;
default = "10h";
type = types.str;
example = "48h";
description = lib.mdDoc ''
"bantime.maxtime" is the max number of seconds using the ban time can reach (don't grows further)
"bantime-increment.maxtime" is the max number of seconds using the ban time can reach (don't grows further)
'';
};
bantime-increment.factor = mkOption {
default = null;
type = types.nullOr types.str;
default = "1";
type = types.str;
example = "4";
description = lib.mdDoc ''
"bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
"bantime-increment.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
default value of factor is 1 and with default value of formula, the ban time grows by 1, 2, 4, 8, 16 ...
'';
};
bantime-increment.formula = mkOption {
default = null;
type = types.nullOr types.str;
default = "ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor";
type = types.str;
example = "ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)";
description = lib.mdDoc ''
"bantime.formula" used by default to calculate next value of ban time, default value bellow,
the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32 ...
"bantime-increment.formula" used by default to calculate next value of ban time, default value bellow,
the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32...
'';
};
bantime-increment.multipliers = mkOption {
default = null;
type = types.nullOr types.str;
example = "1 2 4 8 16 32 64";
default = "1 2 4 8 16 32 64";
type = types.str;
example = "2 4 16 128";
description = lib.mdDoc ''
"bantime.multipliers" used to calculate next value of ban time instead of formula, corresponding
"bantime-increment.multipliers" used to calculate next value of ban time instead of formula, corresponding
previously ban count and given "bantime.factor" (for multipliers default is 1);
following example grows ban time by 1, 2, 4, 8, 16 ... and if last ban count greater as multipliers count,
always used last multiplier (64 in example), for factor '1' and original ban time 600 - 10.6 hours
@@ -175,11 +175,11 @@ in
};
bantime-increment.overalljails = mkOption {
default = null;
type = types.nullOr types.bool;
default = false;
type = types.bool;
example = true;
description = lib.mdDoc ''
"bantime.overalljails" (if true) specifies the search of IP in the database will be executed
"bantime-increment.overalljails" (if true) specifies the search of IP in the database will be executed
cross over all jails, if false (default), only current jail of the ban IP will be searched
'';
};
@@ -276,16 +276,8 @@ in
###### implementation
config = mkIf cfg.enable {
assertions = [
{
assertion = (cfg.bantime-increment.formula == null || cfg.bantime-increment.multipliers == null);
message = ''
Options `services.fail2ban.bantime-increment.formula` and `services.fail2ban.bantime-increment.multipliers` cannot be both specified.
'';
}
];
warnings = mkIf (!config.networking.firewall.enable && !config.networking.nftables.enable) [
warnings = mkIf (config.networking.firewall.enable == false && config.networking.nftables.enable == false) [
"fail2ban can not be used without a firewall"
];
@@ -338,14 +330,15 @@ in
# Add some reasonable default jails. The special "DEFAULT" jail
# sets default values for all other jails.
services.fail2ban.jails.DEFAULT = ''
# Bantime increment options
bantime.increment = ${boolToString cfg.bantime-increment.enable}
${optionalString (cfg.bantime-increment.rndtime != null) "bantime.rndtime = ${cfg.bantime-increment.rndtime}"}
${optionalString (cfg.bantime-increment.maxtime != null) "bantime.maxtime = ${cfg.bantime-increment.maxtime}"}
${optionalString (cfg.bantime-increment.factor != null) "bantime.factor = ${cfg.bantime-increment.factor}"}
${optionalString (cfg.bantime-increment.formula != null) "bantime.formula = ${cfg.bantime-increment.formula}"}
${optionalString (cfg.bantime-increment.multipliers != null) "bantime.multipliers = ${cfg.bantime-increment.multipliers}"}
${optionalString (cfg.bantime-increment.overalljails != null) "bantime.overalljails = ${boolToString cfg.bantime-increment.overalljails}"}
${optionalString cfg.bantime-increment.enable ''
# Bantime incremental
bantime.increment = ${boolToString cfg.bantime-increment.enable}
bantime.maxtime = ${cfg.bantime-increment.maxtime}
bantime.factor = ${cfg.bantime-increment.factor}
bantime.formula = ${cfg.bantime-increment.formula}
bantime.multipliers = ${cfg.bantime-increment.multipliers}
bantime.overalljails = ${boolToString cfg.bantime-increment.overalljails}
''}
# Miscellaneous options
ignoreip = 127.0.0.1/8 ${optionalString config.networking.enableIPv6 "::1"} ${concatStringsSep " " cfg.ignoreIP}
${optionalString (cfg.bantime != null) ''

View File

@@ -1,128 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
format = pkgs.formats.json { };
commonOptions = { pkgName, flavour ? pkgName }: mkOption {
default = { };
description = mdDoc ''
Attribute set of ${flavour} instances.
Creates independent `${flavour}-''${name}.service` systemd units for each instance defined here.
'';
type = with types; attrsOf (submodule ({ name, ... }: {
options = {
enable = mkEnableOption (mdDoc "this ${flavour} instance") // { default = true; };
package = mkPackageOptionMD pkgs pkgName { };
user = mkOption {
type = types.str;
default = "root";
description = mdDoc ''
User under which this instance runs.
'';
};
group = mkOption {
type = types.str;
default = "root";
description = mdDoc ''
Group under which this instance runs.
'';
};
settings = mkOption {
type = types.submodule {
freeformType = format.type;
options = {
pid_file = mkOption {
default = "/run/${flavour}/${name}.pid";
type = types.str;
description = mdDoc ''
Path to use for the pid file.
'';
};
template = mkOption {
default = [ ];
type = with types; listOf (attrsOf anything);
description =
let upstreamDocs =
if flavour == "vault-agent"
then "https://developer.hashicorp.com/vault/docs/agent/template"
else "https://github.com/hashicorp/consul-template/blob/main/docs/configuration.md#templates";
in
mdDoc ''
Template section of ${flavour}.
Refer to <${upstreamDocs}> for supported values.
'';
};
};
};
default = { };
description =
let upstreamDocs =
if flavour == "vault-agent"
then "https://developer.hashicorp.com/vault/docs/agent#configuration-file-options"
else "https://github.com/hashicorp/consul-template/blob/main/docs/configuration.md#configuration-file";
in
mdDoc ''
Free-form settings written directly to the `config.json` file.
Refer to <${upstreamDocs}> for supported values.
::: {.note}
Resulting format is JSON not HCL.
Refer to <https://www.hcl2json.com/> if you are unsure how to convert HCL options to JSON.
:::
'';
};
};
}));
};
createAgentInstance = { instance, name, flavour }:
let
configFile = format.generate "${name}.json" instance.settings;
in
mkIf (instance.enable) {
description = "${flavour} daemon - ${name}";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
path = [ pkgs.getent ];
startLimitIntervalSec = 60;
startLimitBurst = 3;
serviceConfig = {
User = instance.user;
Group = instance.group;
RuntimeDirectory = flavour;
ExecStart = "${getExe instance.package} ${optionalString ((getName instance.package) == "vault") "agent"} -config ${configFile}";
ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID";
KillSignal = "SIGINT";
TimeoutStopSec = "30s";
Restart = "on-failure";
};
};
in
{
options = {
services.consul-template.instances = commonOptions { pkgName = "consul-template"; };
services.vault-agent.instances = commonOptions { pkgName = "vault"; flavour = "vault-agent"; };
};
config = mkMerge (map
(flavour:
let cfg = config.services.${flavour}; in
mkIf (cfg.instances != { }) {
systemd.services = mapAttrs'
(name: instance: nameValuePair "${flavour}-${name}" (createAgentInstance { inherit name instance flavour; }))
cfg.instances;
})
[ "consul-template" "vault-agent" ]);
meta.maintainers = with maintainers; [ indeednotjames tcheronneau ];
}

View File

@@ -2,22 +2,18 @@
with lib;
let
cfg = config.services.cloud-init;
path = with pkgs; [
cloud-init
iproute2
nettools
openssh
shadow
util-linux
busybox
]
++ optional cfg.btrfs.enable btrfs-progs
++ optional cfg.ext4.enable e2fsprogs
;
settingsFormat = pkgs.formats.yaml { };
cfgfile = settingsFormat.generate "cloud.cfg" cfg.settings;
let cfg = config.services.cloud-init;
path = with pkgs; [
cloud-init
iproute2
nettools
openssh
shadow
util-linux
busybox
] ++ optional cfg.btrfs.enable btrfs-progs
++ optional cfg.ext4.enable e2fsprogs
;
in
{
options = {
@@ -25,7 +21,7 @@ in
enable = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
description = lib.mdDoc ''
Enable the cloud-init service. This services reads
configuration metadata in a cloud environment and configures
the machine according to this metadata.
@@ -44,7 +40,7 @@ in
btrfs.enable = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
description = lib.mdDoc ''
Allow the cloud-init service to operate `btrfs` filesystem.
'';
};
@@ -52,7 +48,7 @@ in
ext4.enable = mkOption {
type = types.bool;
default = true;
description = mdDoc ''
description = lib.mdDoc ''
Allow the cloud-init service to operate `ext4` filesystem.
'';
};
@@ -60,170 +56,141 @@ in
network.enable = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
description = lib.mdDoc ''
Allow the cloud-init service to configure network interfaces
through systemd-networkd.
'';
};
settings = mkOption {
description = mdDoc ''
Structured cloud-init configuration.
'';
type = types.submodule {
freeformType = settingsFormat.type;
};
default = { };
};
config = mkOption {
type = types.str;
default = "";
description = mdDoc ''
raw cloud-init configuration.
default = ''
system_info:
distro: nixos
network:
renderers: [ 'networkd' ]
users:
- root
Takes precedence over the `settings` option if set.
'';
disable_root: false
preserve_hostname: false
cloud_init_modules:
- migrator
- seed_random
- bootcmd
- write-files
- growpart
- resizefs
- update_hostname
- resolv_conf
- ca-certs
- rsyslog
- users-groups
cloud_config_modules:
- disk_setup
- mounts
- ssh-import-id
- set-passwords
- timezone
- disable-ec2-metadata
- runcmd
- ssh
cloud_final_modules:
- rightscale_userdata
- scripts-vendor
- scripts-per-once
- scripts-per-boot
- scripts-per-instance
- scripts-user
- ssh-authkey-fingerprints
- keys-to-console
- phone-home
- final-message
- power-state-change
'';
description = lib.mdDoc "cloud-init configuration.";
};
};
};
config = {
services.cloud-init.settings = {
system_info = mkDefault {
distro = "nixos";
network = {
renderers = [ "networkd" ];
};
};
config = mkIf cfg.enable {
users = mkDefault [ "root" ];
disable_root = mkDefault false;
preserve_hostname = mkDefault false;
cloud_init_modules = mkDefault [
"migrator"
"seed_random"
"bootcmd"
"write-files"
"growpart"
"resizefs"
"update_hostname"
"resolv_conf"
"ca-certs"
"rsyslog"
"users-groups"
];
cloud_config_modules = mkDefault [
"disk_setup"
"mounts"
"ssh-import-id"
"set-passwords"
"timezone"
"disable-ec2-metadata"
"runcmd"
"ssh"
];
cloud_final_modules = mkDefault [
"rightscale_userdata"
"scripts-vendor"
"scripts-per-once"
"scripts-per-boot"
"scripts-per-instance"
"scripts-user"
"ssh-authkey-fingerprints"
"keys-to-console"
"phone-home"
"final-message"
"power-state-change"
];
};
} // (mkIf cfg.enable {
environment.etc."cloud/cloud.cfg" =
if cfg.config == "" then
{ source = cfgfile; }
else
{ text = cfg.config; }
;
environment.etc."cloud/cloud.cfg".text = cfg.config;
systemd.network.enable = cfg.network.enable;
systemd.services.cloud-init-local = {
description = "Initial cloud-init job (pre-networking)";
wantedBy = [ "multi-user.target" ];
before = [ "systemd-networkd.service" ];
path = path;
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.cloud-init}/bin/cloud-init init --local";
RemainAfterExit = "yes";
TimeoutSec = "infinity";
StandardOutput = "journal+console";
systemd.services.cloud-init-local =
{ description = "Initial cloud-init job (pre-networking)";
wantedBy = [ "multi-user.target" ];
before = ["systemd-networkd.service"];
path = path;
serviceConfig =
{ Type = "oneshot";
ExecStart = "${pkgs.cloud-init}/bin/cloud-init init --local";
RemainAfterExit = "yes";
TimeoutSec = "infinity";
StandardOutput = "journal+console";
};
};
};
systemd.services.cloud-init = {
description = "Initial cloud-init job (metadata service crawler)";
wantedBy = [ "multi-user.target" ];
wants = [
"network-online.target"
"cloud-init-local.service"
"sshd.service"
"sshd-keygen.service"
];
after = [ "network-online.target" "cloud-init-local.service" ];
before = [ "sshd.service" "sshd-keygen.service" ];
requires = [ "network.target" ];
path = path;
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.cloud-init}/bin/cloud-init init";
RemainAfterExit = "yes";
TimeoutSec = "infinity";
StandardOutput = "journal+console";
systemd.services.cloud-init =
{ description = "Initial cloud-init job (metadata service crawler)";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" "cloud-init-local.service"
"sshd.service" "sshd-keygen.service" ];
after = [ "network-online.target" "cloud-init-local.service" ];
before = [ "sshd.service" "sshd-keygen.service" ];
requires = [ "network.target"];
path = path;
serviceConfig =
{ Type = "oneshot";
ExecStart = "${pkgs.cloud-init}/bin/cloud-init init";
RemainAfterExit = "yes";
TimeoutSec = "infinity";
StandardOutput = "journal+console";
};
};
};
systemd.services.cloud-config = {
description = "Apply the settings specified in cloud-config";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" "syslog.target" "cloud-config.target" ];
systemd.services.cloud-config =
{ description = "Apply the settings specified in cloud-config";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" "syslog.target" "cloud-config.target" ];
path = path;
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=config";
RemainAfterExit = "yes";
TimeoutSec = "infinity";
StandardOutput = "journal+console";
path = path;
serviceConfig =
{ Type = "oneshot";
ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=config";
RemainAfterExit = "yes";
TimeoutSec = "infinity";
StandardOutput = "journal+console";
};
};
};
systemd.services.cloud-final = {
description = "Execute cloud user/final scripts";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" "syslog.target" "cloud-config.service" "rc-local.service" ];
requires = [ "cloud-config.target" ];
path = path;
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=final";
RemainAfterExit = "yes";
TimeoutSec = "infinity";
StandardOutput = "journal+console";
systemd.services.cloud-final =
{ description = "Execute cloud user/final scripts";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" "syslog.target" "cloud-config.service" "rc-local.service" ];
requires = [ "cloud-config.target" ];
path = path;
serviceConfig =
{ Type = "oneshot";
ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=final";
RemainAfterExit = "yes";
TimeoutSec = "infinity";
StandardOutput = "journal+console";
};
};
};
systemd.targets.cloud-config = {
description = "Cloud-config availability";
requires = [ "cloud-init-local.service" "cloud-init.service" ];
};
});
systemd.targets.cloud-config =
{ description = "Cloud-config availability";
requires = [ "cloud-init-local.service" "cloud-init.service" ];
};
};
}

View File

@@ -1,83 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.kavita;
in {
options.services.kavita = {
enable = lib.mkEnableOption (lib.mdDoc "Kavita reading server");
user = lib.mkOption {
type = lib.types.str;
default = "kavita";
description = lib.mdDoc "User account under which Kavita runs.";
};
package = lib.mkPackageOptionMD pkgs "kavita" { };
dataDir = lib.mkOption {
default = "/var/lib/kavita";
type = lib.types.str;
description = lib.mdDoc "The directory where Kavita stores its state.";
};
tokenKeyFile = lib.mkOption {
type = lib.types.path;
description = lib.mdDoc ''
A file containing the TokenKey, a secret with at 128+ bits.
It can be generated with `head -c 32 /dev/urandom | base64`.
'';
};
port = lib.mkOption {
default = 5000;
type = lib.types.port;
description = lib.mdDoc "Port to bind to.";
};
ipAdresses = lib.mkOption {
default = ["0.0.0.0" "::"];
type = lib.types.listOf lib.types.str;
description = lib.mdDoc "IP Adresses to bind to. The default is to bind
to all IPv4 and IPv6 addresses.";
};
};
config = lib.mkIf cfg.enable {
systemd.services.kavita = {
description = "Kavita";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
preStart = ''
umask u=rwx,g=rx,o=
cat > "${cfg.dataDir}/config/appsettings.json" <<EOF
{
"TokenKey": "$(cat ${cfg.tokenKeyFile})",
"Port": ${toString cfg.port},
"IpAddresses": "${lib.concatStringsSep "," cfg.ipAdresses}"
}
EOF
'';
serviceConfig = {
WorkingDirectory = cfg.dataDir;
ExecStart = "${lib.getExe cfg.package}";
Restart = "always";
User = cfg.user;
};
};
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0750 ${cfg.user} ${cfg.user} - -"
"d '${cfg.dataDir}/config' 0750 ${cfg.user} ${cfg.user} - -"
];
users = {
users.${cfg.user} = {
description = "kavita service user";
isSystemUser = true;
group = cfg.user;
home = cfg.dataDir;
};
groups.${cfg.user} = { };
};
};
meta.maintainers = with lib.maintainers; [ misterio77 ];
}

View File

@@ -8,8 +8,7 @@ let
cfg = config.services.mediawiki;
fpm = config.services.phpfpm.pools.mediawiki;
user = "mediawiki";
group = if cfg.webserver == "apache" then "apache" else "mediawiki";
group = config.services.httpd.group;
cacheDir = "/var/cache/mediawiki";
stateDir = "/var/lib/mediawiki";
@@ -74,7 +73,7 @@ let
$wgScriptPath = "";
## The protocol and server name to use in fully-qualified URLs
$wgServer = "${cfg.url}";
$wgServer = "${if cfg.virtualHost.addSSL || cfg.virtualHost.forceSSL || cfg.virtualHost.onlySSL then "https" else "http"}://${cfg.virtualHost.hostName}";
## The URL path to static resources (images, scripts, etc.)
$wgResourceBasePath = $wgScriptPath;
@@ -88,7 +87,8 @@ let
$wgEnableEmail = true;
$wgEnableUserEmail = true; # UPO
$wgPasswordSender = "${cfg.passwordSender}";
$wgEmergencyContact = "${if cfg.virtualHost.adminAddr != null then cfg.virtualHost.adminAddr else config.services.httpd.adminAddr}";
$wgPasswordSender = $wgEmergencyContact;
$wgEnotifUserTalk = false; # UPO
$wgEnotifWatchlist = false; # UPO
@@ -190,16 +190,6 @@ in
description = lib.mdDoc "Which MediaWiki package to use.";
};
finalPackage = mkOption {
type = types.package;
readOnly = true;
default = pkg;
defaultText = literalExpression "pkg";
description = lib.mdDoc ''
The final package used by the module. This is the package that will have extensions and skins installed.
'';
};
name = mkOption {
type = types.str;
default = "MediaWiki";
@@ -207,22 +197,6 @@ in
description = lib.mdDoc "Name of the wiki.";
};
url = mkOption {
type = types.str;
default = if cfg.webserver == "apache" then
"${if cfg.httpd.virtualHost.addSSL || cfg.httpd.virtualHost.forceSSL || cfg.httpd.virtualHost.onlySSL then "https" else "http"}://${cfg.httpd.virtualHost.hostName}"
else
"http://localhost";
defaultText = literalExpression ''
if cfg.webserver == "apache" then
"''${if cfg.httpd.virtualHost.addSSL || cfg.httpd.virtualHost.forceSSL || cfg.httpd.virtualHost.onlySSL then "https" else "http"}://''${cfg.httpd.virtualHost.hostName}"
else
"http://localhost";
'';
example = "https://wiki.example.org";
description = lib.mdDoc "URL of the wiki.";
};
uploadsDir = mkOption {
type = types.nullOr types.path;
default = "${stateDir}/uploads";
@@ -238,24 +212,6 @@ in
example = "/run/keys/mediawiki-password";
};
passwordSender = mkOption {
type = types.str;
default =
if cfg.webserver == "apache" then
if cfg.httpd.virtualHost.adminAddr != null then
cfg.httpd.virtualHost.adminAddr
else
config.services.httpd.adminAddr else "root@localhost";
defaultText = literalExpression ''
if cfg.webserver == "apache" then
if cfg.httpd.virtualHost.adminAddr != null then
cfg.httpd.virtualHost.adminAddr
else
config.services.httpd.adminAddr else "root@localhost"
'';
description = lib.mdDoc "Contact address for password reset.";
};
skins = mkOption {
default = {};
type = types.attrsOf types.path;
@@ -285,12 +241,6 @@ in
'';
};
webserver = mkOption {
type = types.enum [ "apache" "none" ];
default = "apache";
description = lib.mdDoc "Webserver to use.";
};
database = {
type = mkOption {
type = types.enum [ "mysql" "postgres" "sqlite" "mssql" "oracle" ];
@@ -368,7 +318,7 @@ in
};
};
httpd.virtualHost = mkOption {
virtualHost = mkOption {
type = types.submodule (import ../web-servers/apache-httpd/vhost-options.nix);
example = literalExpression ''
{
@@ -416,10 +366,6 @@ in
};
};
imports = [
(lib.mkRenamedOptionModule [ "services" "mediawiki" "virtualHost" ] [ "services" "mediawiki" "httpd" "virtualHost" ])
];
# implementation
config = mkIf cfg.enable {
@@ -466,42 +412,36 @@ in
services.phpfpm.pools.mediawiki = {
inherit user group;
phpEnv.MEDIAWIKI_CONFIG = "${mediawikiConfig}";
settings = (if (cfg.webserver == "apache") then {
settings = {
"listen.owner" = config.services.httpd.user;
"listen.group" = config.services.httpd.group;
} else {
"listen.owner" = user;
"listen.group" = group;
}) // cfg.poolConfig;
} // cfg.poolConfig;
};
services.httpd = lib.mkIf (cfg.webserver == "apache") {
services.httpd = {
enable = true;
extraModules = [ "proxy_fcgi" ];
virtualHosts.${cfg.httpd.virtualHost.hostName} = mkMerge [
cfg.httpd.virtualHost
{
documentRoot = mkForce "${pkg}/share/mediawiki";
extraConfig = ''
<Directory "${pkg}/share/mediawiki">
<FilesMatch "\.php$">
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
</If>
</FilesMatch>
virtualHosts.${cfg.virtualHost.hostName} = mkMerge [ cfg.virtualHost {
documentRoot = mkForce "${pkg}/share/mediawiki";
extraConfig = ''
<Directory "${pkg}/share/mediawiki">
<FilesMatch "\.php$">
<If "-f %{REQUEST_FILENAME}">
SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
</If>
</FilesMatch>
Require all granted
DirectoryIndex index.php
AllowOverride All
</Directory>
'' + optionalString (cfg.uploadsDir != null) ''
Alias "/images" "${cfg.uploadsDir}"
<Directory "${cfg.uploadsDir}">
Require all granted
</Directory>
'';
}
];
Require all granted
DirectoryIndex index.php
AllowOverride All
</Directory>
'' + optionalString (cfg.uploadsDir != null) ''
Alias "/images" "${cfg.uploadsDir}"
<Directory "${cfg.uploadsDir}">
Require all granted
</Directory>
'';
} ];
};
systemd.tmpfiles.rules = [
@@ -549,14 +489,13 @@ in
};
};
systemd.services.httpd.after = optional (cfg.webserver == "apache" && cfg.database.createLocally && cfg.database.type == "mysql") "mysql.service"
++ optional (cfg.webserver == "apache" && cfg.database.createLocally && cfg.database.type == "postgres") "postgresql.service";
systemd.services.httpd.after = optional (cfg.database.createLocally && cfg.database.type == "mysql") "mysql.service"
++ optional (cfg.database.createLocally && cfg.database.type == "postgres") "postgresql.service";
users.users.${user} = {
group = group;
isSystemUser = true;
};
users.groups.${group} = {};
environment.systemPackages = [ mediawikiScripts ];
};

View File

@@ -76,7 +76,7 @@ in
export DATABASE_PASSWORD="$(<"${cfg.dbpassFile}")"
'' + ''
export DATABASE_URL="${dbUrl}"
${cfg.package}/bin/notify_push '${config.services.nextcloud.datadir}/config/config.php'
${cfg.package}/bin/notify_push --glob-config '${config.services.nextcloud.datadir}/config/config.php'
'';
serviceConfig = {
User = "nextcloud";

View File

@@ -12,16 +12,10 @@ major version available.
Nextcloud is a PHP-based application which requires an HTTP server
([`services.nextcloud`](#opt-services.nextcloud.enable)
and optionally supports
[`services.nginx`](#opt-services.nginx.enable)).
For the database, you can set
[`services.nextcloud.config.dbtype`](#opt-services.nextcloud.config.dbtype) to
either `sqlite` (the default), `mysql`, or `pgsql`. For the last two, by
default, a local database will be created and nextcloud will connect to it via
socket; this can be disabled by setting
[`services.nextcloud.database.createLocally`](#opt-services.nextcloud.database.createLocally)
to `false`.
optionally supports
[`services.nginx`](#opt-services.nginx.enable))
and a database (it's recommended to use
[`services.postgresql`](#opt-services.postgresql.enable)).
A very basic configuration may look like this:
```
@@ -32,10 +26,30 @@ A very basic configuration may look like this:
hostName = "nextcloud.tld";
config = {
dbtype = "pgsql";
dbuser = "nextcloud";
dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself
dbname = "nextcloud";
adminpassFile = "/path/to/admin-pass-file";
adminuser = "root";
};
};
services.postgresql = {
enable = true;
ensureDatabases = [ "nextcloud" ];
ensureUsers = [
{ name = "nextcloud";
ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
}
];
};
# ensure that postgres is running *before* running the setup
systemd.services."nextcloud-setup" = {
requires = ["postgresql.service"];
after = ["postgresql.service"];
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
}
```

View File

@@ -57,9 +57,6 @@ let
inherit (config.system) stateVersion;
mysqlLocal = cfg.database.createLocally && cfg.config.dbtype == "mysql";
pgsqlLocal = cfg.database.createLocally && cfg.config.dbtype == "pgsql";
in {
imports = [
@@ -317,9 +314,13 @@ in {
createLocally = mkOption {
type = types.bool;
default = true;
default = false;
description = lib.mdDoc ''
Create the database and database user locally.
Create the database and database user locally. Only available for
mysql database.
Note that this option will use the latest version of MariaDB which
is not officially supported by Nextcloud. As for now a workaround
is used to also support MariaDB version >= 10.6.
'';
};
@@ -351,15 +352,12 @@ in {
};
dbhost = mkOption {
type = types.nullOr types.str;
default =
if pgsqlLocal then "/run/postgresql"
else if mysqlLocal then "localhost:/run/mysqld/mysqld.sock"
else "localhost";
defaultText = "localhost";
default = "localhost";
description = lib.mdDoc ''
Database host or socket path. Defaults to the correct unix socket
instead if `services.nextcloud.database.createLocally` is true and
`services.nextcloud.config.dbtype` is either `pgsql` or `mysql`.
Database host.
Note: for using Unix authentication with PostgreSQL, this should be
set to `/run/postgresql`.
'';
};
dbport = mkOption {
@@ -739,22 +737,8 @@ in {
}
{ assertions = [
{ assertion = cfg.database.createLocally -> cfg.config.dbpassFile == null;
message = ''
Using `services.nextcloud.database.createLocally` (that now defaults
to true) with database password authentication is no longer
supported.
If you use an external database (or want to use password auth for any
other reason), set `services.nextcloud.database.createLocally` to
`false`. The database won't be managed for you (use `services.mysql`
if you want to set it up).
If you want this module to manage your nextcloud database for you,
unset `services.nextcloud.config.dbpassFile` and
`services.nextcloud.config.dbhost` to use socket authentication
instead of password.
'';
{ assertion = cfg.database.createLocally -> cfg.config.dbtype == "mysql";
message = ''services.nextcloud.config.dbtype must be set to mysql if services.nextcloud.database.createLocally is set to true.'';
}
]; }
@@ -918,8 +902,6 @@ in {
in {
wantedBy = [ "multi-user.target" ];
before = [ "phpfpm-nextcloud.service" ];
after = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
requires = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.service";
path = [ occ ];
script = ''
${optionalString (c.dbpassFile != null) ''
@@ -1025,7 +1007,7 @@ in {
environment.systemPackages = [ occ ];
services.mysql = lib.mkIf mysqlLocal {
services.mysql = lib.mkIf cfg.database.createLocally {
enable = true;
package = lib.mkDefault pkgs.mariadb;
ensureDatabases = [ cfg.config.dbname ];
@@ -1033,15 +1015,14 @@ in {
name = cfg.config.dbuser;
ensurePermissions = { "${cfg.config.dbname}.*" = "ALL PRIVILEGES"; };
}];
};
services.postgresql = mkIf pgsqlLocal {
enable = true;
ensureDatabases = [ cfg.config.dbname ];
ensureUsers = [{
name = cfg.config.dbuser;
ensurePermissions = { "DATABASE ${cfg.config.dbname}" = "ALL PRIVILEGES"; };
}];
initialScript = pkgs.writeText "mysql-init" ''
CREATE USER '${cfg.config.dbname}'@'localhost' IDENTIFIED BY '${builtins.readFile( cfg.config.dbpassFile )}';
CREATE DATABASE IF NOT EXISTS ${cfg.config.dbname};
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER,
CREATE TEMPORARY TABLES ON ${cfg.config.dbname}.* TO '${cfg.config.dbuser}'@'localhost'
IDENTIFIED BY '${builtins.readFile( cfg.config.dbpassFile )}';
FLUSH privileges;
'';
};
services.nginx.enable = mkDefault true;

View File

@@ -1,71 +1,65 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.stargazer;
globalSection = ''
listen = ${lib.concatStringsSep " " cfg.listen}
connection-logging = ${lib.boolToString cfg.connectionLogging}
log-ip = ${lib.boolToString cfg.ipLog}
log-ip-partial = ${lib.boolToString cfg.ipLogPartial}
routesFormat = pkgs.formats.ini { };
globalFile = pkgs.writeText "global.ini" ''
listen = ${concatStringsSep " " cfg.listen}
connection-logging = ${boolToString cfg.connectionLogging}
log-ip = ${boolToString cfg.ipLog}
log-ip-partial = ${boolToString cfg.ipLogPartial}
request-timeout = ${toString cfg.requestTimeout}
response-timeout = ${toString cfg.responseTimeout}
[:tls]
store = ${toString cfg.store}
organization = ${cfg.certOrg}
gen-certs = ${lib.boolToString cfg.genCerts}
regen-certs = ${lib.boolToString cfg.regenCerts}
${lib.optionalString (cfg.certLifetime != "") "cert-lifetime = ${cfg.certLifetime}"}
gen-certs = ${boolToString cfg.genCerts}
regen-certs = ${boolToString cfg.regenCerts}
${optionalString (cfg.certLifetime != "") "cert-lifetime = ${cfg.certLifetime}"}
'';
genINI = lib.generators.toINI { };
configFile = pkgs.writeText "config.ini" (lib.strings.concatStrings (
[ globalSection ] ++ (lib.lists.forEach cfg.routes (section:
let
name = section.route;
params = builtins.removeAttrs section [ "route" ];
in
genINI
{
"${name}" = params;
} + "\n"
))
));
routesFile = routesFormat.generate "router.ini" cfg.routes;
configFile = pkgs.runCommand "config.ini" { } ''
cat ${globalFile} ${routesFile} > $out
'';
in
{
options.services.stargazer = {
enable = lib.mkEnableOption (lib.mdDoc "Stargazer Gemini server");
enable = mkEnableOption (lib.mdDoc "Stargazer Gemini server");
listen = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ "0.0.0.0" ] ++ lib.optional config.networking.enableIPv6 "[::0]";
defaultText = lib.literalExpression ''[ "0.0.0.0" ] ++ lib.optional config.networking.enableIPv6 "[::0]"'';
example = lib.literalExpression ''[ "10.0.0.12" "[2002:a00:1::]" ]'';
type = types.listOf types.str;
default = [ "0.0.0.0" ] ++ optional config.networking.enableIPv6 "[::0]";
defaultText = literalExpression ''[ "0.0.0.0" ] ++ lib.optional config.networking.enableIPv6 "[::0]"'';
example = literalExpression ''[ "10.0.0.12" "[2002:a00:1::]" ]'';
description = lib.mdDoc ''
Address and port to listen on.
'';
};
connectionLogging = lib.mkOption {
type = lib.types.bool;
type = types.bool;
default = true;
description = lib.mdDoc "Whether or not to log connections to stdout.";
};
ipLog = lib.mkOption {
type = lib.types.bool;
type = types.bool;
default = false;
description = lib.mdDoc "Log client IP addresses in the connection log.";
};
ipLogPartial = lib.mkOption {
type = lib.types.bool;
type = types.bool;
default = false;
description = lib.mdDoc "Log partial client IP addresses in the connection log.";
};
requestTimeout = lib.mkOption {
type = lib.types.int;
type = types.int;
default = 5;
description = lib.mdDoc ''
Number of seconds to wait for the client to send a complete
@@ -74,7 +68,7 @@ in
};
responseTimeout = lib.mkOption {
type = lib.types.int;
type = types.int;
default = 0;
description = lib.mdDoc ''
Number of seconds to wait for the client to send a complete
@@ -84,7 +78,7 @@ in
};
store = lib.mkOption {
type = lib.types.path;
type = types.path;
default = /var/lib/gemini/certs;
description = lib.mdDoc ''
Path to the certificate store on disk. This should be a
@@ -93,7 +87,7 @@ in
};
certOrg = lib.mkOption {
type = lib.types.str;
type = types.str;
default = "stargazer";
description = lib.mdDoc ''
The name of the organization responsible for the X.509
@@ -102,7 +96,7 @@ in
};
genCerts = lib.mkOption {
type = lib.types.bool;
type = types.bool;
default = true;
description = lib.mdDoc ''
Set to false to disable automatic certificate generation.
@@ -111,7 +105,7 @@ in
};
regenCerts = lib.mkOption {
type = lib.types.bool;
type = types.bool;
default = true;
description = lib.mdDoc ''
Set to false to turn off automatic regeneration of expired certificates.
@@ -120,76 +114,54 @@ in
};
certLifetime = lib.mkOption {
type = lib.types.str;
type = types.str;
default = "";
description = lib.mdDoc ''
How long certs generated by Stargazer should live for.
Certs live forever by default.
'';
example = lib.literalExpression "\"1y\"";
example = literalExpression "\"1y\"";
};
routes = lib.mkOption {
type = lib.types.listOf
(lib.types.submodule {
freeformType = with lib.types; attrsOf (nullOr
(oneOf [
bool
int
float
str
]) // {
description = "INI atom (null, bool, int, float or string)";
});
options.route = lib.mkOption {
type = lib.types.str;
description = lib.mdDoc "Route section name";
};
});
default = [ ];
type = routesFormat.type;
default = { };
description = lib.mdDoc ''
Routes that Stargazer should server.
Expressed as a list of attribute sets. Each set must have a key `route`
that becomes the section name for that route in the stargazer ini cofig.
The remaining keys and vaules become the parameters for that route.
[Refer to upstream docs for other params](https://git.sr.ht/~zethra/stargazer/tree/main/item/doc/stargazer.ini.5.txt)
[Refer to upstream docs](https://git.sr.ht/~zethra/stargazer/tree/main/item/doc/stargazer.ini.5.txt)
'';
example = lib.literalExpression ''
[
{
route = "example.com";
root = "/srv/gemini/example.com"
}
{
route = "example.com:/man";
example = literalExpression ''
{
"example.com" = {
root = "/srv/gemini/example.com";
};
"example.com:/man" = {
root = "/cgi-bin";
cgi = true;
}
{
route = "other.org~(.*)";
};
"other.org~(.*)" = {
redirect = "gemini://example.com";
rewrite = "\1";
}
]
};
}
'';
};
user = lib.mkOption {
type = lib.types.str;
user = mkOption {
type = types.str;
default = "stargazer";
description = lib.mdDoc "User account under which stargazer runs.";
};
group = lib.mkOption {
type = lib.types.str;
group = mkOption {
type = types.str;
default = "stargazer";
description = lib.mdDoc "Group account under which stargazer runs.";
};
};
config = lib.mkIf cfg.enable {
config = mkIf cfg.enable {
systemd.services.stargazer = {
description = "Stargazer gemini server";
after = [ "network.target" ];
@@ -205,19 +177,19 @@ in
# Create default cert store
system.activationScripts.makeStargazerCertDir =
lib.optionalAttrs (cfg.store == /var/lib/gemini/certs) ''
optionalAttrs (cfg.store == /var/lib/gemini/certs) ''
mkdir -p /var/lib/gemini/certs
chown -R ${cfg.user}:${cfg.group} /var/lib/gemini/certs
'';
users.users = lib.optionalAttrs (cfg.user == "stargazer") {
users.users = optionalAttrs (cfg.user == "stargazer") {
stargazer = {
group = cfg.group;
isSystemUser = true;
};
};
users.groups = lib.optionalAttrs (cfg.group == "stargazer") {
users.groups = optionalAttrs (cfg.group == "stargazer") {
stargazer = { };
};
};

View File

@@ -1,208 +0,0 @@
{ config, lib, pkgs, utils, ... }:
with lib;
let
xcfg = config.services.xserver;
cfg = xcfg.desktopManager.deepin;
nixos-gsettings-overrides = pkgs.deepin.dde-gsettings-schemas.override {
extraGSettingsOverridePackages = cfg.extraGSettingsOverridePackages;
extraGSettingsOverrides = cfg.extraGSettingsOverrides;
};
in
{
options = {
services.xserver.desktopManager.deepin = {
enable = mkEnableOption (lib.mdDoc "Enable Deepin desktop manager");
extraGSettingsOverrides = mkOption {
default = "";
type = types.lines;
description = lib.mdDoc "Additional gsettings overrides.";
};
extraGSettingsOverridePackages = mkOption {
default = [ ];
type = types.listOf types.path;
description = lib.mdDoc "List of packages for which gsettings are overridden.";
};
};
environment.deepin.excludePackages = mkOption {
default = [ ];
type = types.listOf types.package;
description = lib.mdDoc "List of default packages to exclude from the configuration";
};
};
config = mkIf cfg.enable
{
services.xserver.displayManager.sessionPackages = [ pkgs.deepin.startdde ];
services.xserver.displayManager.defaultSession = mkDefault "deepin";
# Update the DBus activation environment after launching the desktop manager.
services.xserver.displayManager.sessionCommands = ''
${lib.getBin pkgs.dbus}/bin/dbus-update-activation-environment --systemd --all
'';
hardware.bluetooth.enable = mkDefault true;
hardware.pulseaudio.enable = mkDefault true;
security.polkit.enable = true;
services.deepin.dde-daemon.enable = mkForce true;
services.deepin.dde-api.enable = mkForce true;
services.deepin.app-services.enable = mkForce true;
services.colord.enable = mkDefault true;
services.accounts-daemon.enable = mkDefault true;
services.gvfs.enable = mkDefault true;
services.gnome.glib-networking.enable = mkDefault true;
services.gnome.gnome-keyring.enable = mkDefault true;
services.bamf.enable = mkDefault true;
services.xserver.libinput.enable = mkDefault true;
services.udisks2.enable = true;
services.upower.enable = mkDefault config.powerManagement.enable;
networking.networkmanager.enable = mkDefault true;
programs.dconf.enable = mkDefault true;
fonts.fonts = with pkgs; [ noto-fonts ];
xdg.mime.enable = true;
xdg.menus.enable = true;
xdg.icons.enable = true;
xdg.portal.enable = mkDefault true;
xdg.portal.extraPortals = mkDefault [
(pkgs.xdg-desktop-portal-gtk.override {
buildPortalsInGnome = false;
})
];
environment.sessionVariables = {
NIX_GSETTINGS_OVERRIDES_DIR = "${nixos-gsettings-overrides}/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas";
DDE_POLKIT_AGENT_PLUGINS_DIRS = [ "${pkgs.deepin.dpa-ext-gnomekeyring}/lib/polkit-1-dde/plugins" ];
};
environment.pathsToLink = [
"/lib/dde-dock/plugins"
"/lib/dde-control-center"
"/lib/dde-session-shell"
"/lib/dde-file-manager"
"/share/backgrounds"
"/share/wallpapers"
];
environment.etc = {
"distribution.info".text = ''
[Distribution]
Name=NixOS
WebsiteName=www.nixos.org
Website=https://www.nixos.org
Logo=${pkgs.nixos-icons}/share/icons/hicolor/96x96/apps/nix-snowflake.png
LogoLight=${pkgs.nixos-icons}/share/icons/hicolor/32x32/apps/nix-snowflake.png
LogoTransparent=${pkgs.deepin.deepin-desktop-base}/share/pixmaps/distribution_logo_transparent.svg
'';
"deepin-installer.conf".text = ''
system_info_vendor_name="Copyright (c) 2003-2023 NixOS contributors"
'';
};
systemd.tmpfiles.rules = [
"d /var/lib/AccountsService 0775 root root - -"
"C /var/lib/AccountsService/icons 0775 root root - ${pkgs.deepin.dde-account-faces}/var/lib/AccountsService/icons"
];
security.pam.services.dde-lock.text = ''
# original at {dde-session-shell}/etc/pam.d/dde-lock
auth substack login
account include login
password substack login
session include login
'';
environment.systemPackages = with pkgs; with deepin;
let
requiredPackages = [
pciutils # for dtkcore/startdde
xdotool # for dde-daemon
glib # for gsettings program / gdbus
gtk3 # for gtk-launch program
xdg-user-dirs # Update user dirs
util-linux # runuser
polkit_gnome
librsvg # dde-api use rsvg-convert
lshw # for dtkcore
libsForQt5.kde-gtk-config # deepin-api/gtk-thumbnailer need
libsForQt5.kglobalaccel
xsettingsd # lightdm-deepin-greeter
qt5platform-plugins
deepin-pw-check
deepin-turbo
dde-account-faces
deepin-icon-theme
deepin-sound-theme
deepin-gtk-theme
deepin-wallpapers
startdde
dde-dock
dde-launcher
dde-session-ui
dde-session-shell
dde-file-manager
dde-control-center
dde-network-core
dde-clipboard
dde-calendar
dde-polkit-agent
dpa-ext-gnomekeyring
deepin-desktop-schemas
deepin-terminal
dde-kwin
deepin-kwin
];
optionalPackages = [
onboard # dde-dock plugin
deepin-camera
deepin-calculator
deepin-compressor
deepin-editor
deepin-picker
deepin-draw
deepin-album
deepin-image-viewer
deepin-music
deepin-movie-reborn
deepin-system-monitor
deepin-screen-recorder
deepin-shortcut-viewer
];
in
requiredPackages
++ utils.removePackagesByName optionalPackages config.environment.deepin.excludePackages;
services.dbus.packages = with pkgs.deepin; [
dde-dock
dde-launcher
dde-session-ui
dde-session-shell
dde-file-manager
dde-control-center
dde-calendar
dde-clipboard
dde-kwin
deepin-kwin
deepin-pw-check
];
systemd.packages = with pkgs.deepin; [
dde-launcher
dde-file-manager
dde-calendar
dde-clipboard
deepin-kwin
];
};
}

View File

@@ -21,7 +21,7 @@ in
./none.nix ./xterm.nix ./phosh.nix ./xfce.nix ./plasma5.nix ./lumina.nix
./lxqt.nix ./enlightenment.nix ./gnome.nix ./retroarch.nix ./kodi.nix
./mate.nix ./pantheon.nix ./surf-display.nix ./cde.nix
./cinnamon.nix ./budgie.nix ./deepin.nix
./cinnamon.nix ./budgie.nix
];
options = {

View File

@@ -121,7 +121,7 @@ let
fi
done
for i in $(find ${toString cfg.modules} -type d | sort); do
for i in $(find ${toString cfg.modules} -type d); do
if test $(echo $i/*.so* | wc -w) -ne 0; then
echo " ModulePath \"$i\"" >> $out
fi

View File

@@ -40,7 +40,7 @@ let
# This can only be done here because we *cannot* depend on $out
# referring to the toplevel, except by living in the toplevel itself.
toplevelInjector = lib.escapeShellArgs [
"${pkgs.buildPackages.jq}/bin/jq"
"${pkgs.jq}/bin/jq"
''
."org.nixos.bootspec.v1".toplevel = $toplevel |
."org.nixos.bootspec.v1".init = $init
@@ -60,7 +60,7 @@ let
children);
in
lib.escapeShellArgs [
"${pkgs.buildPackages.jq}/bin/jq"
"${pkgs.jq}/bin/jq"
"--sort-keys"
''."org.nixos.specialisation.v1" = ($ARGS.named | map_values(. | first))''
] + " ${lib.concatStringsSep " " specialisationLoader}";

View File

@@ -34,29 +34,23 @@ sub getList {
}
sub readFile {
my ($fn) = @_;
# enable slurp mode: read entire file in one go
local $/ = undef;
open my $fh, "<$fn" or return undef;
my $s = <$fh>;
close $fh;
# disable slurp mode
local $/ = "\n";
chomp $s;
return $s;
my ($fn) = @_; local $/ = undef;
open FILE, "<$fn" or return undef; my $s = <FILE>; close FILE;
local $/ = "\n"; chomp $s; return $s;
}
sub writeFile {
my ($fn, $s) = @_;
open my $fh, ">$fn" or die "cannot create $fn: $!\n";
print $fh $s or die "cannot write to $fn: $!\n";
close $fh or die "cannot close $fn: $!\n";
open FILE, ">$fn" or die "cannot create $fn: $!\n";
print FILE $s or die;
close FILE or die;
}
sub runCommand {
open(my $fh, "-|", @_) or die "Failed to execute: $@_\n";
my @ret = $fh->getlines();
close $fh;
my ($cmd) = @_;
open FILE, "$cmd 2>/dev/null |" or die "Failed to execute: $cmd\n";
my @ret = <FILE>;
close FILE;
return ($?, @ret);
}
@@ -206,7 +200,7 @@ sub GrubFs {
$search = $types{$fsIdentifier} . ' ';
# Based on the type pull in the identifier from the system
my ($status, @devInfo) = runCommand("@utillinux@/bin/blkid", "-o", "export", @{[$fs->device]});
my ($status, @devInfo) = runCommand("@utillinux@/bin/blkid -o export @{[$fs->device]}");
if ($status != 0) {
die "Failed to get blkid info (returned $status) for @{[$fs->mount]} on @{[$fs->device]}";
}
@@ -219,7 +213,7 @@ sub GrubFs {
# BTRFS is a special case in that we need to fix the referrenced path based on subvolumes
if ($fs->type eq 'btrfs') {
my ($status, @id_info) = runCommand("@btrfsprogs@/bin/btrfs", "subvol", "show", @{[$fs->mount]});
my ($status, @id_info) = runCommand("@btrfsprogs@/bin/btrfs subvol show @{[$fs->mount]}");
if ($status != 0) {
die "Failed to retrieve subvolume info for @{[$fs->mount]}\n";
}
@@ -227,7 +221,7 @@ sub GrubFs {
if ($#ids > 0) {
die "Btrfs subvol name for @{[$fs->device]} listed multiple times in mount\n"
} elsif ($#ids == 0) {
my ($status, @path_info) = runCommand("@btrfsprogs@/bin/btrfs", "subvol", "list", @{[$fs->mount]});
my ($status, @path_info) = runCommand("@btrfsprogs@/bin/btrfs subvol list @{[$fs->mount]}");
if ($status != 0) {
die "Failed to find @{[$fs->mount]} subvolume id from btrfs\n";
}

View File

@@ -2383,7 +2383,7 @@ let
bridgeVLANConfig = mkOption {
default = {};
example = { VLAN = "10-20"; };
type = types.addCheck (types.attrsOf unitOption) check.network.sectionBridgeVLAN;
type = types.addCheck (types.attrsOf unitOption) check.network.sectionbridgeVLAN;
description = lib.mdDoc ''
Each attribute in this set specifies an option in the
`[BridgeVLAN]` section of the unit. See

View File

@@ -410,11 +410,6 @@ mountFS() {
n=$((n + 1))
done
# For bind mounts, busybox has a tendency to ignore options, which can be a
# security issue (e.g. "nosuid"). Remounting the partition seems to fix the
# issue.
mount "/mnt-root$mountPoint" -o "remount,$optionsPrefixed"
[ "$mountPoint" == "/" ] &&
[ -f "/mnt-root/etc/NIXOS_LUSTRATE" ] &&
lustrateRoot "/mnt-root"

View File

@@ -130,7 +130,7 @@ let
${concatStringsSep " \\\n" ([ "-f qcow2" ]
++ optional (cfg.useBootLoader && cfg.useDefaultFilesystems) "-F qcow2 -b ${systemImage}/nixos.qcow2"
++ optional (!(cfg.useBootLoader && cfg.useDefaultFilesystems)) "-o size=${toString config.virtualisation.diskSize}M"
++ [ ''"$NIX_DISK_IMAGE"'' ])}
++ [ "$NIX_DISK_IMAGE" ])}
echo "Virtualisation disk image created."
fi
@@ -169,26 +169,18 @@ let
# Create a directory for exchanging data with the VM.
mkdir -p "$TMPDIR/xchg"
${lib.optionalString cfg.useEFIBoot
${lib.optionalString cfg.useBootLoader
''
# Expose EFI variables, it's useful even when we are not using a bootloader (!).
# We might be interested in having EFI variable storage present even if we aren't booting via UEFI, hence
# no guard against `useBootLoader`. Examples:
# - testing PXE boot or other EFI applications
# - directbooting LinuxBoot, which `kexec()s` into a UEFI environment that can boot e.g. Windows
NIX_EFI_VARS=$(readlink -f "''${NIX_EFI_VARS:-${config.system.name}-efi-vars.fd}")
# VM needs writable EFI vars
if ! test -e "$NIX_EFI_VARS"; then
${if cfg.useBootLoader then
# We still need the EFI var from the make-disk-image derivation
# because our "switch-to-configuration" process might
# write into it and we want to keep this data.
''cp ${systemImage}/efi-vars.fd "$NIX_EFI_VARS"''
else
''cp ${cfg.efi.variables} "$NIX_EFI_VARS"''
}
chmod 0644 "$NIX_EFI_VARS"
fi
${lib.optionalString cfg.useEFIBoot
''
# VM needs writable EFI vars
if ! test -e "$NIX_EFI_VARS"; then
cp ${systemImage}/efi-vars.fd "$NIX_EFI_VARS"
chmod 0644 "$NIX_EFI_VARS"
fi
''}
''}
cd "$TMPDIR"
@@ -804,6 +796,42 @@ in
};
};
virtualisation.tpm = {
enable = mkEnableOption ''a TPM device in the virtual machine with a driver, using swtpm.
To use it in a `test_script`, you can use `machine.tpm` which is a TPM driver offering some basic
facilities to manipulate the TPM socket on the host.
'';
package = mkPackageOptionMD cfg.host.pkgs "swtpm" { };
socketPath = mkOption {
type = types.str;
default = "/tmp/swtpm-sock";
description = lib.mdDoc "swtpm socket path on the host";
};
deviceModel = mkOption {
type = types.str;
default = ({
"i686-linux" = "tpm-tis";
"x86_64-linux" = "tpm-tis";
"ppc64-linux" = "tpm-spapr";
"armv7-linux" = "tpm-tis-device";
"aarch64-linux" = "tpm-tis-device";
}.${pkgs.hostPlatform.system});
defaultText = ''({
"i686-linux" = "tpm-tis";
"x86_64-linux" = "tpm-tis";
"ppc64-linux" = "tpm-spapr";
"armv7-linux" = "tpm-tis-device";
"aarch64-linux" = "tpm-tis-device";
}.''${pkgs.hostPlatform.system})'';
example = "tpm-tis-device";
description = lib.mdDoc "QEMU device model for the TPM, uses the appropriate default based on the system and the package passed.";
};
};
virtualisation.useDefaultFilesystems =
mkOption {
type = types.bool;
@@ -954,7 +982,8 @@ in
boot.initrd.availableKernelModules =
optional cfg.writableStore "overlay"
++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx";
++ optional (cfg.qemu.diskInterface == "scsi") "sym53c8xx"
++ optional (cfg.tpm.enable) "tpm_tis";
virtualisation.additionalPaths = [ config.system.build.toplevel ];
@@ -1020,6 +1049,11 @@ in
(mkIf (!cfg.graphics) [
"-nographic"
])
(mkIf (cfg.tpm.enable) [
"-chardev socket,id=chrtpm,path=${cfg.tpm.socketPath}"
"-tpmdev emulator,id=tpm_dev_0,chardev=chrtpm"
"-device ${cfg.tpm.deviceModel},tpmdev=tpm_dev_0"
])
];
virtualisation.qemu.drives = mkMerge [

View File

@@ -46,7 +46,7 @@ let
inherit
(rec {
doRunTest = arg: ((import ../lib/testing-python.nix { inherit system pkgs; }).evalTest {
imports = [ arg readOnlyPkgs ];
imports = [ arg ];
}).config.result;
findTests = tree:
if tree?recurseForDerivations && tree.recurseForDerivations
@@ -65,36 +65,10 @@ let
runTestOn
;
# Using a single instance of nixpkgs makes test evaluation faster.
# To make sure we don't accidentally depend on a modified pkgs, we make the
# related options read-only. We need to test the right configuration.
#
# If your service depends on a nixpkgs setting, first try to avoid that, but
# otherwise, you can remove the readOnlyPkgs import and test your service as
# usual.
readOnlyPkgs =
# TODO: We currently accept this for nixosTests, so that the `pkgs` argument
# is consistent with `pkgs` in `pkgs.nixosTests`. Can we reinitialize
# it with `allowAliases = false`?
# warnIf pkgs.config.allowAliases "nixosTests: pkgs includes aliases."
{
_class = "nixosTest";
node.pkgs = pkgs;
};
in {
# Testing the test driver
nixos-test-driver = {
extra-python-packages = handleTest ./nixos-test-driver/extra-python-packages.nix {};
node-name = runTest ./nixos-test-driver/node-name.nix;
};
# NixOS vm tests and non-vm unit tests
_3proxy = runTest ./3proxy.nix;
aaaaxy = runTest ./aaaaxy.nix;
acme = runTest { imports = [ ./acme.nix ]; };
acme = runTest ./acme.nix;
adguardhome = runTest ./adguardhome.nix;
aesmd = runTestOn ["x86_64-linux"] ./aesmd.nix;
agate = runTest ./web-servers/agate.nix;
@@ -172,7 +146,6 @@ in {
collectd = handleTest ./collectd.nix {};
connman = handleTest ./connman.nix {};
consul = handleTest ./consul.nix {};
consul-template = handleTest ./consul-template.nix {};
containers-bridge = handleTest ./containers-bridge.nix {};
containers-custom-pkgs.nix = handleTest ./containers-custom-pkgs.nix {};
containers-ephemeral = handleTest ./containers-ephemeral.nix {};
@@ -197,7 +170,6 @@ in {
cups-pdf = handleTest ./cups-pdf.nix {};
custom-ca = handleTest ./custom-ca.nix {};
croc = handleTest ./croc.nix {};
deepin = handleTest ./deepin.nix {};
deluge = handleTest ./deluge.nix {};
dendrite = handleTest ./matrix/dendrite.nix {};
dex-oidc = handleTest ./dex-oidc.nix {};
@@ -223,7 +195,6 @@ in {
dovecot = handleTest ./dovecot.nix {};
drbd = handleTest ./drbd.nix {};
earlyoom = handleTestOn ["x86_64-linux"] ./earlyoom.nix {};
early-mount-options = handleTest ./early-mount-options.nix {};
ec2-config = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-config or {};
ec2-nixops = (handleTestOn ["x86_64-linux"] ./ec2.nix {}).boot-ec2-nixops or {};
ecryptfs = handleTest ./ecryptfs.nix {};
@@ -247,6 +218,7 @@ in {
etcd-cluster = handleTestOn ["x86_64-linux"] ./etcd-cluster.nix {};
etebase-server = handleTest ./etebase-server.nix {};
etesync-dav = handleTest ./etesync-dav.nix {};
extra-python-packages = handleTest ./extra-python-packages.nix {};
evcc = handleTest ./evcc.nix {};
fancontrol = handleTest ./fancontrol.nix {};
fcitx5 = handleTest ./fcitx5 {};
@@ -369,7 +341,6 @@ in {
kafka = handleTest ./kafka.nix {};
kanidm = handleTest ./kanidm.nix {};
karma = handleTest ./karma.nix {};
kavita = handleTest ./kavita.nix {};
kbd-setfont-decompress = handleTest ./kbd-setfont-decompress.nix {};
kbd-update-search-paths-patch = handleTest ./kbd-update-search-paths-patch.nix {};
kea = handleTest ./kea.nix {};
@@ -420,7 +391,7 @@ in {
lxd-image-server = handleTest ./lxd-image-server.nix {};
#logstash = handleTest ./logstash.nix {};
lorri = handleTest ./lorri/default.nix {};
maddy = discoverTests (import ./maddy { inherit handleTest; });
maddy = handleTest ./maddy.nix {};
maestral = handleTest ./maestral.nix {};
magic-wormhole-mailbox-server = handleTest ./magic-wormhole-mailbox-server.nix {};
magnetico = handleTest ./magnetico.nix {};
@@ -782,7 +753,6 @@ in {
varnish60 = handleTest ./varnish.nix { package = pkgs.varnish60; };
varnish72 = handleTest ./varnish.nix { package = pkgs.varnish72; };
vault = handleTest ./vault.nix {};
vault-agent = handleTest ./vault-agent.nix {};
vault-dev = handleTest ./vault-dev.nix {};
vault-postgresql = handleTest ./vault-postgresql.nix {};
vaultwarden = handleTest ./vaultwarden.nix {};

View File

@@ -1,36 +0,0 @@
import ./make-test-python.nix ({ ... }: {
name = "consul-template";
nodes.machine = { ... }: {
services.consul-template.instances.example.settings = {
template = [{
contents = ''
{{ key "example" }}
'';
perms = "0600";
destination = "/example";
}];
};
services.consul = {
enable = true;
extraConfig = {
server = true;
bootstrap_expect = 1;
bind_addr = "127.0.0.1";
};
};
};
testScript = ''
machine.wait_for_unit("consul.service")
machine.wait_for_open_port(8500)
machine.wait_for_unit("consul-template-example.service")
machine.wait_until_succeeds('consul kv put example example')
machine.wait_for_file("/example")
machine.succeed('grep "example" /example')
'';
})

View File

@@ -1,57 +0,0 @@
import ./make-test-python.nix ({ pkgs, lib, ... }: {
name = "deepin";
meta = with lib; {
maintainers = teams.deepin.members;
};
nodes.machine = { ... }: {
imports = [
./common/user-account.nix
];
services.xserver.enable = true;
services.xserver.displayManager = {
lightdm.enable = true;
autoLogin = {
enable = true;
user = "alice";
};
};
services.xserver.desktopManager.deepin.enable = true;
};
testScript = { nodes, ... }:
let
user = nodes.machine.users.users.alice;
in
''
with subtest("Wait for login"):
machine.wait_for_x()
machine.wait_for_file("${user.home}/.Xauthority")
machine.succeed("xauth merge ${user.home}/.Xauthority")
with subtest("Check that logging in has given the user ownership of devices"):
machine.succeed("getfacl -p /dev/snd/timer | grep -q ${user.name}")
with subtest("Check if DDE wm chooser actually start"):
machine.wait_until_succeeds("pgrep -f dde-wm-chooser")
machine.wait_for_window("dde-wm-chooser")
machine.execute("pkill dde-wm-chooser")
with subtest("Check if Deepin session components actually start"):
machine.wait_until_succeeds("pgrep -f dde-session-daemon")
machine.wait_for_window("dde-session-daemon")
machine.wait_until_succeeds("pgrep -f dde-desktop")
machine.wait_for_window("dde-desktop")
with subtest("Open deepin-terminal"):
machine.succeed("su - ${user.name} -c 'DISPLAY=:0 deepin-terminal >&2 &'")
machine.wait_for_window("deepin-terminal")
machine.sleep(20)
machine.screenshot("screen")
'';
})

View File

@@ -1,19 +0,0 @@
# Test for https://github.com/NixOS/nixpkgs/pull/193469
import ./make-test-python.nix {
name = "early-mount-options";
nodes.machine = {
virtualisation.fileSystems."/var" = {
options = [ "bind" "nosuid" "nodev" "noexec" ];
device = "/var";
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
var_mount_info = machine.succeed("findmnt /var -n -o OPTIONS")
options = var_mount_info.strip().split(",")
assert "nosuid" in options and "nodev" in options and "noexec" in options
'';
}

View File

@@ -1,4 +1,4 @@
import ../make-test-python.nix ({ ... }:
import ./make-test-python.nix ({ ... }:
{
name = "extra-python-packages";

View File

@@ -345,7 +345,6 @@ let
(docbook-xsl-ns.override {
withManOptDedupPatch = true;
})
kbd.dev
kmod.dev
libarchive.dev
libxml2.bin

View File

@@ -1,36 +0,0 @@
import ./make-test-python.nix ({ pkgs, ...} : {
name = "kavita";
meta = with pkgs.lib.maintainers; {
maintainers = [ misterio77 ];
};
nodes = {
kavita = { config, pkgs, ... }: {
services.kavita = {
enable = true;
port = 5000;
tokenKeyFile = builtins.toFile "kavita.key" "QfpjFvjT83BLtZ74GE3U3Q==";
};
};
};
testScript = let
regUrl = "http://kavita:5000/api/Account/register";
payload = builtins.toFile "payload.json" (builtins.toJSON {
username = "foo";
password = "correcthorsebatterystaple";
email = "foo@bar";
});
in ''
kavita.start
kavita.wait_for_unit("kavita.service")
# Check that static assets are working
kavita.wait_until_succeeds("curl http://kavita:5000/site.webmanifest | grep Kavita")
# Check that registration is working
kavita.succeed("curl -fX POST ${regUrl} --json @${payload}")
# But only for the first one
kavita.fail("curl -fX POST ${regUrl} --json @${payload}")
'';
})

View File

@@ -1,5 +1,5 @@
import ../make-test-python.nix ({ pkgs, ... }: {
name = "maddy-unencrypted";
import ./make-test-python.nix ({ pkgs, ... }: {
name = "maddy";
meta = with pkgs.lib.maintainers; { maintainers = [ onny ]; };
nodes = {

View File

@@ -1,6 +0,0 @@
{ handleTest }:
{
unencrypted = handleTest ./unencrypted.nix { };
tls = handleTest ./tls.nix { };
}

View File

@@ -1,94 +0,0 @@
import ../make-test-python.nix ({ pkgs, ... }:
let
certs = import ../common/acme/server/snakeoil-certs.nix;
domain = certs.domain;
in {
name = "maddy-tls";
meta = with pkgs.lib.maintainers; { maintainers = [ onny ]; };
nodes = {
server = { options, ... }: {
services.maddy = {
enable = true;
hostname = domain;
primaryDomain = domain;
openFirewall = true;
ensureAccounts = [ "postmaster@${domain}" ];
ensureCredentials = {
# Do not use this in production. This will make passwords world-readable
# in the Nix store
"postmaster@${domain}".passwordFile = "${pkgs.writeText "postmaster" "test"}";
};
tls = {
loader = "file";
certificates = [{
certPath = "${certs.${domain}.cert}";
keyPath = "${certs.${domain}.key}";
}];
};
# Enable TLS listeners. Configuring this via the module is not yet
# implemented.
config = builtins.replaceStrings [
"imap tcp://0.0.0.0:143"
"submission tcp://0.0.0.0:587"
] [
"imap tls://0.0.0.0:993 tcp://0.0.0.0:143"
"submission tls://0.0.0.0:465 tcp://0.0.0.0:587"
] options.services.maddy.config.default;
};
# Not covered by openFirewall yet
networking.firewall.allowedTCPPorts = [ 993 465 ];
};
client = { nodes, ... }: {
security.pki.certificateFiles = [
certs.ca.cert
];
networking.extraHosts = ''
${nodes.server.networking.primaryIPAddress} ${domain}
'';
environment.systemPackages = [
(pkgs.writers.writePython3Bin "send-testmail" { } ''
import smtplib
import ssl
from email.mime.text import MIMEText
context = ssl.create_default_context()
msg = MIMEText("Hello World")
msg['Subject'] = 'Test'
msg['From'] = "postmaster@${domain}"
msg['To'] = "postmaster@${domain}"
with smtplib.SMTP_SSL(host='${domain}', port=465, context=context) as smtp:
smtp.login('postmaster@${domain}', 'test')
smtp.sendmail(
'postmaster@${domain}', 'postmaster@${domain}', msg.as_string()
)
'')
(pkgs.writers.writePython3Bin "test-imap" { } ''
import imaplib
with imaplib.IMAP4_SSL('${domain}') as imap:
imap.login('postmaster@${domain}', 'test')
imap.select()
status, refs = imap.search(None, 'ALL')
assert status == 'OK'
assert len(refs) == 1
status, msg = imap.fetch(refs[0], 'BODY[TEXT]')
assert status == 'OK'
assert msg[0][1].strip() == b"Hello World"
'')
];
};
};
testScript = ''
start_all()
server.wait_for_unit("maddy.service")
server.wait_for_open_port(143)
server.wait_for_open_port(993)
server.wait_for_open_port(587)
server.wait_for_open_port(465)
client.succeed("send-testmail")
client.succeed("test-imap")
'';
})

View File

@@ -7,8 +7,8 @@
let
shared = {
services.mediawiki.enable = true;
services.mediawiki.httpd.virtualHost.hostName = "localhost";
services.mediawiki.httpd.virtualHost.adminAddr = "root@example.com";
services.mediawiki.virtualHost.hostName = "localhost";
services.mediawiki.virtualHost.adminAddr = "root@example.com";
services.mediawiki.passwordFile = pkgs.writeText "password" "correcthorsebatterystaple";
services.mediawiki.extensions = {
Matomo = pkgs.fetchzip {
@@ -54,24 +54,4 @@ in
assert "MediaWiki has been installed" in page
'';
};
nohttpd = testLib.makeTest {
name = "mediawiki-nohttpd";
nodes.machine = {
services.mediawiki.webserver = "none";
};
testScript = { nodes, ... }: ''
start_all()
machine.wait_for_unit("phpfpm-mediawiki.service")
env = (
"SCRIPT_NAME=/index.php",
"SCRIPT_FILENAME=${nodes.machine.services.mediawiki.finalPackage}/share/mediawiki/index.php",
"REMOTE_ADDR=127.0.0.1",
'QUERY_STRING=title=Main_Page',
"REQUEST_METHOD=GET",
);
page = machine.succeed(f"{' '.join(env)} ${pkgs.fcgi}/bin/cgi-fcgi -bind -connect ${nodes.machine.services.phpfpm.pools.mediawiki.socket}")
assert "MediaWiki has been installed" in page, f"no 'MediaWiki has been installed' in:\n{page}"
'';
};
}

View File

@@ -1,11 +1,6 @@
import ../make-test-python.nix ({ pkgs, ...}: let
username = "custom_admin_username";
# This will be used both for redis and postgresql
pass = "hunter2";
# Don't do this at home, use a file outside of the nix store instead
passFile = toString (pkgs.writeText "pass-file" ''
${pass}
'');
adminpass = "hunter2";
adminuser = "custom-admin-username";
in {
name = "nextcloud-with-declarative-redis";
meta = with pkgs.lib.maintainers; {
@@ -27,15 +22,15 @@ in {
redis = true;
memcached = false;
};
# This test also validates that we can use an "external" database
database.createLocally = false;
config = {
dbtype = "pgsql";
dbname = "nextcloud";
dbuser = username;
dbpassFile = passFile;
adminuser = username;
adminpassFile = passFile;
dbuser = "nextcloud";
dbhost = "/run/postgresql";
inherit adminuser;
adminpassFile = toString (pkgs.writeText "admin-pass-file" ''
${adminpass}
'');
};
secretFile = "/etc/nextcloud-secrets.json";
@@ -57,20 +52,20 @@ in {
systemd.services.nextcloud-setup= {
requires = ["postgresql.service"];
after = [ "postgresql.service" ];
after = [
"postgresql.service"
];
};
services.postgresql = {
enable = true;
ensureDatabases = [ "nextcloud" ];
ensureUsers = [
{ name = "nextcloud";
ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES";
}
];
};
systemd.services.postgresql.postStart = pkgs.lib.mkAfter ''
password=$(cat ${passFile})
${config.services.postgresql.package}/bin/psql <<EOF
CREATE ROLE ${username} WITH LOGIN PASSWORD '$password' CREATEDB;
CREATE DATABASE nextcloud;
GRANT ALL PRIVILEGES ON DATABASE nextcloud TO ${username};
EOF
'';
# This file is meant to contain secret options which should
# not go into the nix store. Here it is just used to set the
@@ -91,8 +86,8 @@ in {
export RCLONE_CONFIG_NEXTCLOUD_TYPE=webdav
export RCLONE_CONFIG_NEXTCLOUD_URL="http://nextcloud/remote.php/webdav/"
export RCLONE_CONFIG_NEXTCLOUD_VENDOR="nextcloud"
export RCLONE_CONFIG_NEXTCLOUD_USER="${username}"
export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${pass})"
export RCLONE_CONFIG_NEXTCLOUD_USER="${adminuser}"
export RCLONE_CONFIG_NEXTCLOUD_PASS="$(${pkgs.rclone}/bin/rclone obscure ${adminpass})"
"''${@}"
'';
copySharedFile = pkgs.writeScript "copy-shared-file" ''

View File

@@ -26,13 +26,24 @@ in {
redis = false;
memcached = true;
};
database.createLocally = true;
config = {
dbtype = "mysql";
dbname = "nextcloud";
dbuser = "nextcloud";
dbhost = "127.0.0.1";
dbport = 3306;
dbpassFile = "${pkgs.writeText "dbpass" "hunter2" }";
# Don't inherit adminuser since "root" is supposed to be the default
adminpassFile = "${pkgs.writeText "adminpass" adminpass}"; # Don't try this at home!
};
};
systemd.services.nextcloud-setup= {
requires = ["mysql.service"];
after = ["mysql.service"];
};
services.memcached.enable = true;
};
};

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