Merge master into staging-next
This commit is contained in:
@@ -55,10 +55,14 @@ jobs:
|
||||
})).map(file => file.filename)
|
||||
|
||||
if (files.some(file => [
|
||||
'.github/workflows/build.yml',
|
||||
'.github/workflows/check.yml',
|
||||
'.github/workflows/eval.yml',
|
||||
'.github/workflows/lint.yml',
|
||||
'.github/workflows/merge-group.yml',
|
||||
'.github/workflows/test.yml',
|
||||
'ci/github-script/supportedSystems.js',
|
||||
'ci/supportedBranches.js',
|
||||
].includes(file))) core.setOutput('merge-group', true)
|
||||
|
||||
if (files.some(file => [
|
||||
@@ -71,8 +75,16 @@ jobs:
|
||||
'.github/workflows/pull-request-target.yml',
|
||||
'.github/workflows/test.yml',
|
||||
'ci/github-script/bot.js',
|
||||
'ci/github-script/check-target-branch.js',
|
||||
'ci/github-script/commits.js',
|
||||
'ci/github-script/lint-commits.js',
|
||||
'ci/github-script/merge.js',
|
||||
'ci/github-script/prepare.js',
|
||||
'ci/github-script/reviewers.js',
|
||||
'ci/github-script/reviews.js',
|
||||
'ci/github-script/supportedSystems.js',
|
||||
'ci/github-script/withRateLimit.js',
|
||||
'ci/supportedBranches.js',
|
||||
].includes(file))) core.setOutput('pr', true)
|
||||
|
||||
merge-group:
|
||||
|
||||
@@ -123,9 +123,7 @@ let
|
||||
# - values: lists of `packagePlatformPath`s
|
||||
diffAttrs = builtins.fromJSON (builtins.readFile "${combined}/combined-diff.json");
|
||||
|
||||
changedPackagePlatformAttrs = convertToPackagePlatformAttrs diffAttrs.changed;
|
||||
rebuildsPackagePlatformAttrs = convertToPackagePlatformAttrs diffAttrs.rebuilds;
|
||||
removedPackagePlatformAttrs = convertToPackagePlatformAttrs diffAttrs.removed;
|
||||
|
||||
changed-paths =
|
||||
let
|
||||
@@ -162,9 +160,10 @@ let
|
||||
|
||||
inherit
|
||||
(callPackage ./maintainers.nix {
|
||||
changedattrs = lib.attrNames (lib.groupBy (a: a.name) changedPackagePlatformAttrs);
|
||||
changedpathsjson = touchedFilesJson;
|
||||
removedattrs = lib.attrNames (lib.groupBy (a: a.name) removedPackagePlatformAttrs);
|
||||
affectedAttrPaths = map (a: a.packagePath) (
|
||||
convertToPackagePlatformAttrs (diffAttrs.changed ++ diffAttrs.removed)
|
||||
);
|
||||
changedFiles = lib.importJSON touchedFilesJson;
|
||||
})
|
||||
users
|
||||
teams
|
||||
@@ -181,7 +180,7 @@ runCommand "compare"
|
||||
];
|
||||
users = builtins.toJSON users;
|
||||
teams = builtins.toJSON teams;
|
||||
packages = builtins.toJSON packages;
|
||||
packages = builtins.toJSON (lib.map (lib.concatStringsSep ".") packages);
|
||||
passAsFile = [
|
||||
"users"
|
||||
"teams"
|
||||
|
||||
@@ -1,70 +1,54 @@
|
||||
# Figure out which maintainers (users/teams) are relevant for a PR:
|
||||
# - All maintainers that can be linked directly to changedFiles
|
||||
# - Maintainers of affectedAttrPaths if a file directly related to the attribute is in changedFiles
|
||||
#
|
||||
# Files and attributes are linked in various ways:
|
||||
# - pkgs/by-name/<attr>/* is linked to pkgs.<attr>
|
||||
# - The file position of various attributes of pkgs.<attr>
|
||||
# - Explicitly specified file positions in derivations
|
||||
#
|
||||
# Test with
|
||||
# nix-instantiate --eval --strict --json test.nix -A result | jq
|
||||
#
|
||||
# Empty list as an output means success
|
||||
{
|
||||
lib,
|
||||
changedattrs,
|
||||
changedpathsjson,
|
||||
removedattrs,
|
||||
}:
|
||||
let
|
||||
pkgs = import ../../.. {
|
||||
# Files that were changed
|
||||
# Type: ListOf (Nixpkgs-root-relative path)
|
||||
changedFiles,
|
||||
# Attributes whose value was affected by the change
|
||||
# Type: ListOf (ListOf String)
|
||||
affectedAttrPaths,
|
||||
|
||||
pkgs ? import ../../.. {
|
||||
system = "x86_64-linux";
|
||||
# We should never try to ping maintainers through package aliases, this can only lead to errors.
|
||||
# One example case is, where an attribute is a throw alias, but then re-introduced in a PR.
|
||||
# This would trigger the throw. By disabling aliases, we can fallback gracefully below.
|
||||
config.allowAliases = false;
|
||||
};
|
||||
overlays = [ ];
|
||||
},
|
||||
lib,
|
||||
}:
|
||||
let
|
||||
nixpkgsRoot = toString ../../.. + "/";
|
||||
stripNixpkgsRootFromKeys = lib.mapAttrs' (
|
||||
file: value: lib.nameValuePair (lib.removePrefix nixpkgsRoot file) value
|
||||
);
|
||||
|
||||
changedpaths = lib.importJSON changedpathsjson;
|
||||
moduleMeta = (pkgs.nixos { }).config.meta;
|
||||
|
||||
# Extract attributes that changed from by-name paths.
|
||||
# This allows pinging reviewers for pure refactors.
|
||||
touchedattrs = lib.pipe changedpaths [
|
||||
(lib.filter (changed: lib.hasPrefix "pkgs/by-name/" changed && changed != "pkgs/by-name/README.md"))
|
||||
(map (lib.splitString "/"))
|
||||
(map (path: lib.elemAt path 3))
|
||||
lib.unique
|
||||
];
|
||||
# Currently just nixos module maintainers, but in the future we can use this for code owners too
|
||||
fileUsers = stripNixpkgsRootFromKeys moduleMeta.maintainers;
|
||||
fileTeams = stripNixpkgsRootFromKeys moduleMeta.teams;
|
||||
|
||||
anyMatchingFile = filename: lib.any (lib.hasPrefix filename) changedpaths;
|
||||
anyMatchingFile = filename: lib.any (lib.hasPrefix filename) changedFiles;
|
||||
|
||||
anyMatchingFiles = files: lib.any anyMatchingFile files;
|
||||
|
||||
sharded = name: "${lib.substring 0 2 name}/${name}";
|
||||
|
||||
attrsWithMaintainers = lib.pipe (changedattrs ++ removedattrs ++ touchedattrs) [
|
||||
# An attribute can appear in changed/removed *and* touched
|
||||
lib.unique
|
||||
(map (
|
||||
name:
|
||||
let
|
||||
path = lib.splitString "." name;
|
||||
# Some packages might be reported as changed on a different platform, but
|
||||
# not even have an attribute on the platform the maintainers are requested on.
|
||||
# Fallback to `null` for these to filter them out below.
|
||||
package = lib.attrByPath path null pkgs;
|
||||
in
|
||||
{
|
||||
inherit name package;
|
||||
# Adds all files in by-name to each package, no matter whether they are discoverable
|
||||
# via meta attributes below. For example, this allows pinging maintainers for
|
||||
# updates to .json files.
|
||||
# TODO: Support by-name package sets.
|
||||
filenames = lib.optional (lib.length path == 1) "pkgs/by-name/${sharded (lib.head path)}/";
|
||||
# meta.maintainers also contains all individual team members.
|
||||
# We only want to ping individuals if they're added individually as maintainers, not via teams.
|
||||
users = package.meta.nonTeamMaintainers or [ ];
|
||||
teams = package.meta.teams or [ ];
|
||||
}
|
||||
))
|
||||
# No need to match up packages without maintainers with their files.
|
||||
# This also filters out attributes where `package = null`, which is the
|
||||
# case for libintl, for example.
|
||||
(lib.filter (pkg: pkg.users != [ ] || pkg.teams != [ ]))
|
||||
];
|
||||
|
||||
relevantFilenames =
|
||||
drv:
|
||||
(lib.unique (
|
||||
map (pos: lib.removePrefix "${toString ../../..}/" pos.file) (
|
||||
map (pos: lib.removePrefix nixpkgsRoot pos.file) (
|
||||
lib.filter (x: x != null) [
|
||||
(drv.meta.maintainersPosition or null)
|
||||
(drv.meta.teamsPosition or null)
|
||||
@@ -87,50 +71,82 @@ let
|
||||
)
|
||||
));
|
||||
|
||||
attrsWithFilenames = map (
|
||||
pkg: pkg // { filenames = pkg.filenames ++ relevantFilenames pkg.package; }
|
||||
) attrsWithMaintainers;
|
||||
relevantAffectedAttrPaths = lib.filter (
|
||||
attrPath:
|
||||
# Some packages might be reported as changed on a different platform, but
|
||||
# not even have an attribute on the platform the maintainers are requested on.
|
||||
# Fallback to `null` for these to filter them out
|
||||
let
|
||||
package = lib.attrByPath attrPath null pkgs;
|
||||
in
|
||||
package != null && anyMatchingFiles (relevantFilenames package)
|
||||
) affectedAttrPaths;
|
||||
|
||||
attrsWithModifiedFiles = lib.filter (pkg: anyMatchingFiles pkg.filenames) attrsWithFilenames;
|
||||
# Extract attributes that changed from by-name paths.
|
||||
# This allows pinging reviewers for pure refactors.
|
||||
changedByNameAttrPaths = lib.pipe changedFiles [
|
||||
(lib.filter (changed: lib.hasPrefix "pkgs/by-name/" changed))
|
||||
(map (lib.splitString "/"))
|
||||
# Filters out e.g. pkgs/by-name/README.md
|
||||
(lib.filter (path: lib.length path > 3))
|
||||
(map (path: lib.elemAt path 3))
|
||||
(map lib.singleton)
|
||||
];
|
||||
|
||||
# An attribute can appear in affected *and* touched
|
||||
attrPathsToGetMaintainersFor = lib.unique (relevantAffectedAttrPaths ++ changedByNameAttrPaths);
|
||||
|
||||
attrPathEntities = lib.concatMap (
|
||||
attrPath:
|
||||
let
|
||||
package = lib.getAttrFromPath attrPath pkgs;
|
||||
in
|
||||
# meta.maintainers also contains all individual team members.
|
||||
# We only want to ping individuals if they're added individually as maintainers, not via teams.
|
||||
userPings { inherit attrPath; } (package.meta.nonTeamMaintainers or [ ])
|
||||
++ lib.concatMap (teamPings { inherit attrPath; }) (package.meta.teams or [ ])
|
||||
) attrPathsToGetMaintainersFor;
|
||||
|
||||
changedFileEntities = lib.concatMap (
|
||||
file:
|
||||
userPings { inherit file; } (fileUsers.${file} or [ ])
|
||||
++ lib.concatMap (teamPings { inherit file; }) (fileTeams.${file} or [ ])
|
||||
) changedFiles;
|
||||
|
||||
userPings =
|
||||
pkg:
|
||||
context:
|
||||
map (maintainer: {
|
||||
type = "user";
|
||||
userId = maintainer.githubId;
|
||||
packageName = pkg.name;
|
||||
inherit context;
|
||||
});
|
||||
|
||||
teamPings =
|
||||
pkg: team:
|
||||
if team ? github then
|
||||
context: team:
|
||||
if team ? githubId then
|
||||
[
|
||||
{
|
||||
type = "team";
|
||||
teamId = team.githubId;
|
||||
packageName = pkg.name;
|
||||
inherit context;
|
||||
}
|
||||
]
|
||||
else
|
||||
userPings pkg team.members;
|
||||
userPings context team.members;
|
||||
|
||||
maintainersToPing = lib.concatMap (
|
||||
pkg: userPings pkg pkg.users ++ lib.concatMap (teamPings pkg) pkg.teams
|
||||
) attrsWithModifiedFiles;
|
||||
|
||||
byType = lib.groupBy (ping: ping.type) maintainersToPing;
|
||||
byType = lib.groupBy (ping: ping.type) (attrPathEntities ++ changedFileEntities);
|
||||
|
||||
byUser = lib.pipe (byType.user or [ ]) [
|
||||
(lib.groupBy (ping: toString ping.userId))
|
||||
(lib.mapAttrs (_user: lib.map (pkg: pkg.packageName)))
|
||||
(lib.mapAttrs (_user: lib.map (pkg: pkg.context)))
|
||||
];
|
||||
byTeam = lib.pipe (byType.team or [ ]) [
|
||||
(lib.groupBy (ping: toString ping.teamId))
|
||||
(lib.mapAttrs (_team: lib.map (pkg: pkg.packageName)))
|
||||
(lib.mapAttrs (_team: lib.map (pkg: pkg.context)))
|
||||
];
|
||||
in
|
||||
{
|
||||
users = byUser;
|
||||
teams = byTeam;
|
||||
packages = lib.catAttrs "name" attrsWithModifiedFiles;
|
||||
packages = attrPathsToGetMaintainersFor;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
{
|
||||
pkgs ? import ../../.. {
|
||||
config = { };
|
||||
overlays = [ ];
|
||||
},
|
||||
lib ? pkgs.lib,
|
||||
}:
|
||||
let
|
||||
fun = import ./maintainers.nix;
|
||||
|
||||
mockPkgs =
|
||||
{
|
||||
packages ? [ ],
|
||||
modules ? [ ],
|
||||
githubTeams ? true,
|
||||
}:
|
||||
lib.updateManyAttrsByPath
|
||||
(lib.imap0 (i: p: {
|
||||
path = p;
|
||||
update = _: {
|
||||
meta.maintainersPosition.file = lib.concatStringsSep "/" p;
|
||||
meta.nonTeamMaintainers = [ { githubId = i; } ];
|
||||
meta.teams =
|
||||
if githubTeams then [ { githubId = i + 100; } ] else [ { members = [ { githubId = i + 100; } ]; } ];
|
||||
};
|
||||
}) packages)
|
||||
{
|
||||
nixos =
|
||||
{ }:
|
||||
{
|
||||
config.meta.maintainers = lib.listToAttrs (
|
||||
lib.imap0 (i: m: lib.nameValuePair m [ { githubId = i; } ]) modules
|
||||
);
|
||||
config.meta.teams = lib.listToAttrs (
|
||||
lib.imap0 (
|
||||
i: m:
|
||||
lib.nameValuePair m (
|
||||
if githubTeams then [ { githubId = i + 100; } ] else [ { members = [ { githubId = i + 100; } ]; } ]
|
||||
)
|
||||
) modules
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
tests = {
|
||||
testEmpty = {
|
||||
expr = fun {
|
||||
pkgs = mockPkgs { };
|
||||
inherit lib;
|
||||
changedFiles = [ ];
|
||||
affectedAttrPaths = [ ];
|
||||
};
|
||||
expected = {
|
||||
packages = [ ];
|
||||
teams = { };
|
||||
users = { };
|
||||
};
|
||||
};
|
||||
testNonExistentAffected = {
|
||||
expr = fun {
|
||||
pkgs = mockPkgs { };
|
||||
inherit lib;
|
||||
changedFiles = [ "a" ];
|
||||
affectedAttrPaths = [ [ "b" ] ];
|
||||
};
|
||||
expected = {
|
||||
packages = [ ];
|
||||
teams = { };
|
||||
users = { };
|
||||
};
|
||||
};
|
||||
testIrrelevantAffected = {
|
||||
expr = fun {
|
||||
pkgs = mockPkgs {
|
||||
packages = [ [ "b" ] ];
|
||||
};
|
||||
inherit lib;
|
||||
changedFiles = [ "a" ];
|
||||
affectedAttrPaths = [ [ "b" ] ];
|
||||
};
|
||||
expected = {
|
||||
packages = [ ];
|
||||
teams = { };
|
||||
users = { };
|
||||
};
|
||||
};
|
||||
testRelevantAffected = {
|
||||
expr = fun {
|
||||
pkgs = mockPkgs {
|
||||
packages = [ [ "b" ] ];
|
||||
};
|
||||
inherit lib;
|
||||
# Also tests that subpaths work
|
||||
changedFiles = [ "b/c" ];
|
||||
affectedAttrPaths = [ [ "b" ] ];
|
||||
};
|
||||
expected = {
|
||||
packages = [ [ "b" ] ];
|
||||
teams."100" = [
|
||||
{ attrPath = [ "b" ]; }
|
||||
];
|
||||
users."0" = [
|
||||
{ attrPath = [ "b" ]; }
|
||||
];
|
||||
};
|
||||
};
|
||||
testRelevantAffectedNonGitHub = {
|
||||
expr = fun {
|
||||
pkgs = mockPkgs {
|
||||
packages = [ [ "b" ] ];
|
||||
githubTeams = false;
|
||||
};
|
||||
inherit lib;
|
||||
changedFiles = [ "b/c" ];
|
||||
affectedAttrPaths = [ [ "b" ] ];
|
||||
};
|
||||
expected = {
|
||||
packages = [ [ "b" ] ];
|
||||
teams = { };
|
||||
users."0" = [
|
||||
{ attrPath = [ "b" ]; }
|
||||
];
|
||||
users."100" = [
|
||||
{ attrPath = [ "b" ]; }
|
||||
];
|
||||
};
|
||||
};
|
||||
testByNameChanged = {
|
||||
expr = fun {
|
||||
pkgs = mockPkgs {
|
||||
packages = [ [ "hello" ] ];
|
||||
};
|
||||
inherit lib;
|
||||
changedFiles = [ "pkgs/by-name/he/hello/sources.json" ];
|
||||
affectedAttrPaths = [ ];
|
||||
};
|
||||
expected = {
|
||||
packages = [ [ "hello" ] ];
|
||||
teams."100" = [
|
||||
{ attrPath = [ "hello" ]; }
|
||||
];
|
||||
users."0" = [
|
||||
{ attrPath = [ "hello" ]; }
|
||||
];
|
||||
};
|
||||
};
|
||||
testByNameReadmeChanged = {
|
||||
expr = fun {
|
||||
pkgs = mockPkgs {
|
||||
packages = [ [ "hello" ] ];
|
||||
};
|
||||
inherit lib;
|
||||
changedFiles = [ "pkgs/by-name/README.md" ];
|
||||
affectedAttrPaths = [ ];
|
||||
};
|
||||
expected = {
|
||||
packages = [ ];
|
||||
teams = { };
|
||||
users = { };
|
||||
};
|
||||
};
|
||||
testNoDuplicates = {
|
||||
expr = fun {
|
||||
pkgs = mockPkgs {
|
||||
packages = [ [ "hello" ] ];
|
||||
};
|
||||
inherit lib;
|
||||
changedFiles = [
|
||||
"hello"
|
||||
"pkgs/by-name/he/hello/sources.json"
|
||||
];
|
||||
affectedAttrPaths = [ [ "hello" ] ];
|
||||
};
|
||||
expected = {
|
||||
packages = [ [ "hello" ] ];
|
||||
teams."100" = [
|
||||
{ attrPath = [ "hello" ]; }
|
||||
];
|
||||
users."0" = [
|
||||
{ attrPath = [ "hello" ]; }
|
||||
];
|
||||
};
|
||||
};
|
||||
testModuleMaintainers = {
|
||||
expr = fun {
|
||||
pkgs = mockPkgs {
|
||||
modules = [ "a" ];
|
||||
};
|
||||
inherit lib;
|
||||
changedFiles = [ "a" ];
|
||||
affectedAttrPaths = [ ];
|
||||
};
|
||||
expected = {
|
||||
packages = [ ];
|
||||
teams."100" = [
|
||||
{ file = "a"; }
|
||||
];
|
||||
users."0" = [
|
||||
{ file = "a"; }
|
||||
];
|
||||
};
|
||||
};
|
||||
testModuleMaintainersNonGithub = {
|
||||
expr = fun {
|
||||
pkgs = mockPkgs {
|
||||
modules = [ "a" ];
|
||||
githubTeams = false;
|
||||
};
|
||||
inherit lib;
|
||||
changedFiles = [ "a" ];
|
||||
affectedAttrPaths = [ ];
|
||||
};
|
||||
expected = {
|
||||
packages = [ ];
|
||||
teams = { };
|
||||
users."100" = [
|
||||
{ file = "a"; }
|
||||
];
|
||||
users."0" = [
|
||||
{ file = "a"; }
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
result = lib.runTests tests;
|
||||
}
|
||||
@@ -4,39 +4,12 @@
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
mkOptionType
|
||||
types
|
||||
;
|
||||
|
||||
maintainer = mkOptionType {
|
||||
name = "maintainer";
|
||||
check = email: lib.elem email (lib.attrValues lib.maintainers);
|
||||
merge = loc: defs: {
|
||||
# lib.last: Perhaps this could be merged instead, if "at most once per module"
|
||||
# is a problem (see option description).
|
||||
${(lib.last defs).file} = (lib.last defs).value;
|
||||
};
|
||||
};
|
||||
|
||||
listOfMaintainers = types.listOf maintainer // {
|
||||
merge =
|
||||
loc: defs:
|
||||
lib.zipAttrs (
|
||||
lib.flatten (
|
||||
lib.imap1 (
|
||||
n: def:
|
||||
lib.imap1 (
|
||||
m: def':
|
||||
maintainer.merge (loc ++ [ "[${toString n}-${toString m}]" ]) [
|
||||
{
|
||||
inherit (def) file;
|
||||
value = def';
|
||||
}
|
||||
]
|
||||
) def.value
|
||||
) defs
|
||||
)
|
||||
);
|
||||
# The resulting value of this type shows where all values were defined
|
||||
sourceList = types.listOf types.raw // {
|
||||
merge = loc: defs: lib.listToAttrs (lib.map ({ file, value }: lib.nameValuePair file value) defs);
|
||||
};
|
||||
in
|
||||
{
|
||||
@@ -44,7 +17,14 @@ in
|
||||
options = {
|
||||
meta = {
|
||||
maintainers = mkOption {
|
||||
type = listOfMaintainers;
|
||||
type =
|
||||
let
|
||||
allMaintainers = lib.attrValues lib.maintainers;
|
||||
in
|
||||
lib.types.addCheck sourceList (lib.all (v: lib.elem v allMaintainers))
|
||||
// {
|
||||
description = "list of lib.maintainers";
|
||||
};
|
||||
default = [ ];
|
||||
example = lib.literalExpression "[ lib.maintainers.alice lib.maintainers.bob ]";
|
||||
description = ''
|
||||
@@ -54,6 +34,22 @@ in
|
||||
The option value is not a list of maintainers, but an attribute set that maps module file names to lists of maintainers.
|
||||
'';
|
||||
};
|
||||
teams = mkOption {
|
||||
type =
|
||||
let
|
||||
allTeams = lib.attrValues lib.teams;
|
||||
in
|
||||
lib.types.addCheck sourceList (lib.all (v: lib.elem v allTeams))
|
||||
// {
|
||||
description = "list of lib.teams";
|
||||
};
|
||||
default = [ ];
|
||||
example = lib.literalExpression "[ lib.teams.acme lib.teams.haskell ]";
|
||||
description = ''
|
||||
List of team maintainers of each module.
|
||||
This option should be defined at most once per module.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
|
||||
@@ -14,9 +14,17 @@ let
|
||||
};
|
||||
in
|
||||
rec {
|
||||
lib = import ../../../lib;
|
||||
# Inject ghost into lib.maintainers so it passes the addCheck validation
|
||||
lib = (import ../../../lib).extend (
|
||||
final: prev: {
|
||||
maintainers = prev.maintainers // {
|
||||
inherit ghost;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
example = lib.evalModules {
|
||||
specialArgs.lib = lib;
|
||||
modules = [
|
||||
../meta-maintainers.nix
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ in
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.freedesktop.members;
|
||||
teams = [ lib.teams.freedesktop ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}:
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.freedesktop.members;
|
||||
teams = [ lib.teams.freedesktop ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.freedesktop.members;
|
||||
teams = [ lib.teams.freedesktop ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -13,7 +13,7 @@ in
|
||||
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.freedesktop.members ++ [ ];
|
||||
teams = [ lib.teams.freedesktop ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -32,7 +32,7 @@ in
|
||||
];
|
||||
|
||||
meta = {
|
||||
maintainers = teams.freedesktop.members;
|
||||
teams = [ teams.freedesktop ];
|
||||
};
|
||||
|
||||
options.xdg.portal = {
|
||||
|
||||
@@ -10,7 +10,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.lxqt.members;
|
||||
teams = [ lib.teams.lxqt ];
|
||||
};
|
||||
|
||||
options.xdg.portal.lxqt = {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}:
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.freedesktop.members;
|
||||
teams = [ lib.teams.freedesktop ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -1758,6 +1758,7 @@
|
||||
./services/web-apps/snipe-it.nix
|
||||
./services/web-apps/snips-sh.nix
|
||||
./services/web-apps/sogo.nix
|
||||
./services/web-apps/speedtest-tracker.nix
|
||||
./services/web-apps/sshwifty.nix
|
||||
./services/web-apps/stash.nix
|
||||
./services/web-apps/stirling-pdf.nix
|
||||
|
||||
@@ -49,5 +49,5 @@ in
|
||||
systemd.user.services.dsearch.wantedBy = mkIf cfg.systemd.enable [ cfg.systemd.target ];
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.danklinux.members;
|
||||
meta.teams = [ lib.teams.danklinux ];
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -16,7 +16,7 @@ in
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -10,7 +10,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.freedesktop.members;
|
||||
teams = [ lib.teams.freedesktop ];
|
||||
};
|
||||
|
||||
options.programs.nm-applet = {
|
||||
|
||||
@@ -285,5 +285,5 @@ in
|
||||
];
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.steam.members;
|
||||
meta.teams = [ lib.teams.steam ];
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.xfce.members;
|
||||
teams = [ lib.teams.xfce ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -226,5 +226,5 @@ in
|
||||
hardware.graphics.enable = lib.mkDefault true;
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.danklinux.members;
|
||||
meta.teams = [ lib.teams.danklinux ];
|
||||
}
|
||||
|
||||
@@ -130,5 +130,5 @@ in
|
||||
] "Nvidia patches are no longer needed")
|
||||
];
|
||||
|
||||
meta.maintainers = lib.teams.hyprland.members;
|
||||
meta.teams = [ lib.teams.hyprland ];
|
||||
}
|
||||
|
||||
@@ -26,5 +26,5 @@ in
|
||||
security.pam.services.hyprlock = { };
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.hyprland.members;
|
||||
meta.teams = [ lib.teams.hyprland ];
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.xfce.members;
|
||||
teams = [ lib.teams.xfce ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -1218,7 +1218,7 @@ in
|
||||
];
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.acme.members;
|
||||
teams = [ lib.teams.acme ];
|
||||
doc = ./default.md;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -272,5 +272,5 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.apparmor.members;
|
||||
meta.teams = [ lib.teams.apparmor ];
|
||||
}
|
||||
|
||||
@@ -962,5 +962,6 @@ in
|
||||
(import ./rke2.nix args)
|
||||
];
|
||||
|
||||
meta.maintainers = pkgs.rke2.meta.maintainers ++ lib.teams.k3s.members;
|
||||
meta.teams = [ lib.teams.k3s ];
|
||||
meta.maintainers = pkgs.rke2.meta.maintainers;
|
||||
}
|
||||
|
||||
@@ -313,5 +313,5 @@ in
|
||||
'')
|
||||
];
|
||||
|
||||
meta.maintainers = lib.teams.buildbot.members;
|
||||
meta.teams = [ lib.teams.buildbot ];
|
||||
}
|
||||
|
||||
@@ -196,6 +196,6 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.buildbot.members;
|
||||
meta.teams = [ lib.teams.buildbot ];
|
||||
|
||||
}
|
||||
|
||||
@@ -893,5 +893,5 @@ in
|
||||
)
|
||||
];
|
||||
|
||||
meta.maintainers = teams.gitlab.members;
|
||||
meta.teams = [ teams.gitlab ];
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ let
|
||||
in
|
||||
{
|
||||
|
||||
meta.maintainers = [ "thevar1able" ];
|
||||
meta.maintainers = with lib.maintainers; [ thevar1able ];
|
||||
|
||||
###### interface
|
||||
|
||||
|
||||
@@ -335,7 +335,23 @@ in
|
||||
If the master is password protected (using the requirePass configuration)
|
||||
it is possible to tell the slave to authenticate before starting the replication synchronization
|
||||
process, otherwise the master will refuse the slave request.
|
||||
(STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)'';
|
||||
(STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE)
|
||||
'';
|
||||
};
|
||||
|
||||
masterAuthFile = lib.mkOption {
|
||||
type = with types; nullOr path;
|
||||
default = null;
|
||||
description = "File with password for the master user.";
|
||||
example = "/run/keys/redis-master-password";
|
||||
};
|
||||
|
||||
masterUser = lib.mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
If the master is password protected via ACLs this option can be used to specify
|
||||
the Redis user that is used by replicas.'';
|
||||
};
|
||||
|
||||
requirePass = lib.mkOption {
|
||||
@@ -355,6 +371,43 @@ in
|
||||
example = "/run/keys/redis-password";
|
||||
};
|
||||
|
||||
sentinelAuthPassFile = lib.mkOption {
|
||||
type = with types; nullOr path;
|
||||
default = null;
|
||||
description = "File with password for connecting to other Sentinel instances.";
|
||||
example = "/run/keys/sentinel-password";
|
||||
};
|
||||
|
||||
sentinelAuthUser = lib.mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = "The username to use to monitor a master from Sentinel.";
|
||||
};
|
||||
|
||||
sentinelMasterHost = lib.mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = "The IP address (recommended) or hostname of the Redis master that Sentinel will monitor.";
|
||||
};
|
||||
|
||||
sentinelMasterName = lib.mkOption {
|
||||
type = with types; nullOr str;
|
||||
default = null;
|
||||
description = "The master name of the Redis master that Sentinel will monitor.";
|
||||
};
|
||||
|
||||
sentinelMasterPort = lib.mkOption {
|
||||
type = with types; nullOr int;
|
||||
default = null;
|
||||
description = "The TCP port of the Redis master that Sentinel will monitor.";
|
||||
};
|
||||
|
||||
sentinelMasterQuorum = lib.mkOption {
|
||||
type = with types; nullOr int;
|
||||
default = null;
|
||||
description = "The Sentinel quorum (minimum number of Sentinel nodes online for failover)";
|
||||
};
|
||||
|
||||
appendOnly = lib.mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
@@ -452,14 +505,55 @@ in
|
||||
|
||||
config = lib.mkIf (enabledServers != { }) {
|
||||
|
||||
assertions = lib.attrValues (
|
||||
lib.mapAttrs (name: conf: {
|
||||
assertion = conf.requirePass != null -> conf.requirePassFile == null;
|
||||
message = ''
|
||||
You can only set one services.redis.servers.${name}.requirePass
|
||||
or services.redis.servers.${name}.requirePassFile
|
||||
'';
|
||||
}) enabledServers
|
||||
assertions = lib.concatLists (
|
||||
lib.mapAttrsToList (name: conf: [
|
||||
{
|
||||
assertion = conf.requirePass != null -> conf.requirePassFile == null;
|
||||
message = ''
|
||||
You can only set one of services.redis.servers.${name}.requirePass
|
||||
or services.redis.servers.${name}.requirePassFile
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = conf.masterAuth != null -> conf.masterAuthFile == null;
|
||||
message = ''
|
||||
You can only set one of services.redis.servers.${name}.masterAuth
|
||||
or services.redis.servers.${name}.masterAuthFile
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = conf.masterUser != null -> (conf.masterAuth != null || conf.masterAuthFile != null);
|
||||
message = ''
|
||||
If using services.redis.servers.${name}.masterUser, either
|
||||
services.redis.servers.${name}.masterAuthFile or
|
||||
services.redis.servers.${name}.masterAuth must be provided
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion =
|
||||
conf.sentinelMasterName != null
|
||||
-> (
|
||||
conf.sentinelMasterHost != null
|
||||
&& conf.sentinelMasterPort != null
|
||||
&& conf.sentinelMasterQuorum != null
|
||||
);
|
||||
message = ''
|
||||
For Sentinel,
|
||||
services.redis.servers.${name}.sentinelMasterName,
|
||||
services.redis.servers.${name}.sentinelMasterHost,
|
||||
services.redis.servers.${name}.sentinelMasterPort,
|
||||
and services.redis.servers.${name}.sentinelMasterQuorum
|
||||
must all be provided
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = conf.sentinelAuthPassFile != null -> conf.sentinelMasterName != null;
|
||||
message = ''
|
||||
For Sentinel authentication, services.redis.servers.${name}.sentinelMasterName,
|
||||
must be provided
|
||||
'';
|
||||
}
|
||||
]) enabledServers
|
||||
);
|
||||
|
||||
boot.kernel.sysctl = lib.mkIf cfg.vmOverCommit {
|
||||
@@ -498,6 +592,17 @@ in
|
||||
ExecStart = "${cfg.package}/bin/${
|
||||
cfg.package.serverBin or "redis-server"
|
||||
} /var/lib/${redisName name}/redis.conf ${lib.escapeShellArgs conf.extraParams}";
|
||||
|
||||
# NOTE: Redis/Valkey Sentinel persists dynamic cluster state by rewriting its
|
||||
# configuration file at runtime (redis.conf). This includes monitors,
|
||||
# authentication credentials, and failover metadata, and this behaviour
|
||||
# cannot be disabled.
|
||||
# As a result, a fully declarative configuration is not possible for
|
||||
# Sentinel-managed options. The preStart logic below appends sentinel
|
||||
# configuration only if it is not already present, in order to avoid
|
||||
# overwriting state that is owned and maintained by Sentinel itself.
|
||||
# This is an intentional deviation from strict declarative semantics and
|
||||
# is required for correct Sentinel operation.
|
||||
ExecStartPre =
|
||||
"+"
|
||||
+ pkgs.writeShellScript "${redisName name}-prep-conf" (
|
||||
@@ -515,10 +620,40 @@ in
|
||||
fi
|
||||
echo 'include "${redisConfStore}"' > "${redisConfRun}"
|
||||
${lib.optionalString (conf.requirePassFile != null) ''
|
||||
{
|
||||
echo -n "requirepass "
|
||||
cat ${lib.escapeShellArg conf.requirePassFile}
|
||||
} >> "${redisConfRun}"
|
||||
echo "requirepass $(cat ${lib.escapeShellArg conf.requirePassFile})" >> "${redisConfRun}"
|
||||
''}
|
||||
${lib.optionalString (conf.masterUser != null) ''
|
||||
echo "masteruser ${conf.masterUser}" >> "${redisConfRun}"
|
||||
''}
|
||||
${lib.optionalString (conf.masterAuthFile != null) ''
|
||||
echo "masterauth $(cat ${lib.escapeShellArg conf.masterAuthFile})" >> "${redisConfRun}"
|
||||
''}
|
||||
${lib.optionalString (conf.sentinelMasterHost != null) ''
|
||||
sentinel_monitor_line="sentinel monitor ${conf.sentinelMasterName} ${conf.sentinelMasterHost} ${toString conf.sentinelMasterPort} ${toString conf.sentinelMasterQuorum}"
|
||||
if grep -qE "^sentinel monitor ${conf.sentinelMasterName}\b" "${redisConfVar}"; then
|
||||
sed -i \
|
||||
"s|^sentinel monitor ${conf.sentinelMasterName}\b.*|$sentinel_monitor_line|" "${redisConfVar}"
|
||||
else
|
||||
echo "$sentinel_monitor_line" >> "${redisConfVar}"
|
||||
fi
|
||||
''}
|
||||
${lib.optionalString (conf.sentinelAuthUser != null) ''
|
||||
sentinel_auth_user_line="sentinel auth-user ${conf.sentinelMasterName} ${conf.sentinelAuthUser}"
|
||||
if grep -qE "^sentinel auth-user ${conf.sentinelMasterName}\b" "${redisConfVar}"; then
|
||||
sed -i \
|
||||
"s|^sentinel auth-user ${conf.sentinelMasterName}\b.*|$sentinel_auth_user_line|" "${redisConfVar}"
|
||||
else
|
||||
echo "$sentinel_auth_user_line" >> "${redisConfVar}"
|
||||
fi
|
||||
''}
|
||||
${lib.optionalString (conf.sentinelAuthPassFile != null) ''
|
||||
sentinel_auth_pass_line="sentinel auth-pass ${conf.sentinelMasterName} $(cat ${lib.escapeShellArg conf.sentinelAuthPassFile})"
|
||||
if grep -qE "^sentinel auth-pass ${conf.sentinelMasterName}\b" "${redisConfVar}"; then
|
||||
sed -i \
|
||||
"s|^sentinel auth-pass ${conf.sentinelMasterName}\b.*|$sentinel_auth_pass_line|" "${redisConfVar}"
|
||||
else
|
||||
echo "$sentinel_auth_pass_line" >> "${redisConfVar}"
|
||||
fi
|
||||
''}
|
||||
''
|
||||
);
|
||||
|
||||
@@ -61,7 +61,7 @@ let
|
||||
notExcluded = pkg: utils.disablePackageByName pkg config.environment.budgie.excludePackages;
|
||||
in
|
||||
{
|
||||
meta.maintainers = lib.teams.budgie.members;
|
||||
meta.teams = [ lib.teams.budgie ];
|
||||
|
||||
imports = [
|
||||
(lib.mkRenamedOptionModule
|
||||
|
||||
@@ -44,7 +44,7 @@ let
|
||||
];
|
||||
in
|
||||
{
|
||||
meta.maintainers = lib.teams.cosmic.members;
|
||||
meta.teams = [ lib.teams.cosmic ];
|
||||
|
||||
options = {
|
||||
services.desktopManager.cosmic = {
|
||||
|
||||
@@ -82,7 +82,7 @@ in
|
||||
{
|
||||
meta = {
|
||||
doc = ./gnome.md;
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
imports = [
|
||||
|
||||
@@ -292,5 +292,5 @@ in
|
||||
})
|
||||
];
|
||||
|
||||
meta.maintainers = lib.teams.lomiri.members;
|
||||
meta.teams = [ lib.teams.lomiri ];
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ in
|
||||
|
||||
meta = {
|
||||
doc = ./pantheon.md;
|
||||
maintainers = teams.pantheon.members;
|
||||
teams = [ teams.pantheon ];
|
||||
};
|
||||
|
||||
imports = [
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
}:
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.freedesktop.members;
|
||||
teams = [ lib.teams.freedesktop ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -373,6 +373,6 @@ in
|
||||
};
|
||||
|
||||
meta = {
|
||||
maintainers = [ ] ++ lib.teams.pantheon.members;
|
||||
teams = [ lib.teams.pantheon ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -13,7 +13,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -16,7 +16,7 @@ in
|
||||
|
||||
{
|
||||
meta = {
|
||||
maintainers = teams.gnome.members;
|
||||
teams = [ teams.gnome ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -48,7 +48,7 @@ in
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -12,7 +12,7 @@ in
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -16,7 +16,7 @@ in
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
imports = [
|
||||
|
||||
@@ -14,7 +14,7 @@ in
|
||||
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -10,7 +10,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
imports = [
|
||||
|
||||
@@ -16,7 +16,7 @@ in
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -85,7 +85,8 @@ let
|
||||
};
|
||||
in
|
||||
{
|
||||
meta.maintainers = teams.freedesktop.members ++ [ maintainers.k900 ];
|
||||
meta.teams = [ teams.freedesktop ];
|
||||
meta.maintainers = [ maintainers.k900 ];
|
||||
|
||||
###### interface
|
||||
options = {
|
||||
|
||||
@@ -18,7 +18,7 @@ in
|
||||
];
|
||||
|
||||
meta = {
|
||||
maintainers = [ ] ++ lib.teams.pantheon.members;
|
||||
teams = [ lib.teams.pantheon ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = [ ] ++ lib.teams.pantheon.members;
|
||||
teams = [ lib.teams.pantheon ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -16,7 +16,7 @@ let
|
||||
in
|
||||
|
||||
{
|
||||
meta.maintainers = lib.teams.cosmic.members;
|
||||
meta.teams = [ lib.teams.cosmic ];
|
||||
|
||||
options.services.displayManager.cosmic-greeter = {
|
||||
enable = lib.mkEnableOption "COSMIC greeter";
|
||||
|
||||
@@ -321,5 +321,5 @@ in
|
||||
services.libinput.enable = mkDefault true;
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.danklinux.members;
|
||||
meta.teams = [ lib.teams.danklinux ];
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ in
|
||||
];
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.gnome.members;
|
||||
teams = [ lib.teams.gnome ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -171,7 +171,7 @@ in
|
||||
|
||||
meta = {
|
||||
buildDocsInSandbox = false;
|
||||
maintainers = lib.teams.home-assistant.members;
|
||||
teams = [ lib.teams.home-assistant ];
|
||||
};
|
||||
|
||||
options.services.home-assistant = {
|
||||
|
||||
@@ -341,5 +341,5 @@ in
|
||||
};
|
||||
};
|
||||
};
|
||||
meta.maintainers = lib.teams.matrix.members;
|
||||
meta.teams = [ lib.teams.matrix ];
|
||||
}
|
||||
|
||||
@@ -849,5 +849,5 @@ in
|
||||
};
|
||||
|
||||
meta.doc = ./forgejo.md;
|
||||
meta.maintainers = lib.teams.forgejo.members;
|
||||
meta.teams = [ lib.teams.forgejo ];
|
||||
}
|
||||
|
||||
@@ -1911,5 +1911,5 @@ in
|
||||
};
|
||||
|
||||
meta.doc = ./gitlab.md;
|
||||
meta.maintainers = teams.gitlab.members;
|
||||
meta.teams = [ teams.gitlab ];
|
||||
}
|
||||
|
||||
@@ -63,5 +63,5 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.beam.members;
|
||||
meta.teams = [ lib.teams.beam ];
|
||||
}
|
||||
|
||||
@@ -444,5 +444,5 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.jitsi.members;
|
||||
meta.teams = [ lib.teams.jitsi ];
|
||||
}
|
||||
|
||||
@@ -166,5 +166,5 @@ in
|
||||
lib.mkDefault "${pkgs.jicofo}/etc/jitsi/jicofo/logging.properties-journal";
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.jitsi.members;
|
||||
meta.teams = [ lib.teams.jitsi ];
|
||||
}
|
||||
|
||||
@@ -243,5 +243,5 @@ in
|
||||
lib.mkDefault "${stateDir}/logging.properties-journal";
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.jitsi.members;
|
||||
meta.teams = [ lib.teams.jitsi ];
|
||||
}
|
||||
|
||||
@@ -331,5 +331,5 @@ in
|
||||
];
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.jitsi.members;
|
||||
meta.teams = [ lib.teams.jitsi ];
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.freedesktop.members;
|
||||
teams = [ lib.teams.freedesktop ];
|
||||
};
|
||||
|
||||
options = with lib; {
|
||||
|
||||
@@ -142,9 +142,8 @@ in
|
||||
{
|
||||
|
||||
meta = {
|
||||
maintainers = teams.freedesktop.members ++ [
|
||||
lib.maintainers.frontear
|
||||
];
|
||||
teams = [ lib.teams.freedesktop ];
|
||||
maintainers = [ lib.maintainers.frontear ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -29,8 +29,15 @@ let
|
||||
|
||||
configFile = pkgs.writeText "shadowsocks.json" (builtins.toJSON opts);
|
||||
|
||||
executablesMap = {
|
||||
"${getName pkgs.shadowsocks-libev}" = {
|
||||
server = "ss-server";
|
||||
};
|
||||
"${getName pkgs.shadowsocks-rust}" = {
|
||||
server = "ssserver";
|
||||
};
|
||||
};
|
||||
in
|
||||
|
||||
{
|
||||
|
||||
###### interface
|
||||
@@ -47,14 +54,25 @@ in
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkPackageOption pkgs "Shadowsocks" {
|
||||
default = "shadowsocks-libev";
|
||||
};
|
||||
|
||||
localAddress = mkOption {
|
||||
type = types.coercedTo types.str singleton (types.listOf types.str);
|
||||
type =
|
||||
with types;
|
||||
oneOf [
|
||||
str
|
||||
(listOf str)
|
||||
];
|
||||
# Keeped for compatibility
|
||||
default = [
|
||||
"[::0]"
|
||||
"0.0.0.0"
|
||||
];
|
||||
description = ''
|
||||
Local addresses to which the server binds.
|
||||
Note: shadowsocks-rust accepts only string parameter.
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -163,14 +181,19 @@ in
|
||||
(noPasswd && !noPasswdFile) || (!noPasswd && noPasswdFile);
|
||||
message = "Option `password` or `passwordFile` must be set and cannot be set simultaneously";
|
||||
}
|
||||
{
|
||||
# Ensure localAddress is a string if package is shadowsocks-rust
|
||||
assertion = !(getName cfg.package == "shadowsocks-rust" && !lib.strings.isString cfg.localAddress);
|
||||
message = "Option `localAddress` must be a string when using shadowsocks-rust.";
|
||||
}
|
||||
];
|
||||
|
||||
systemd.services.shadowsocks-libev = {
|
||||
description = "shadowsocks-libev Daemon";
|
||||
systemd.services.${getName cfg.package} = {
|
||||
description = "${getName cfg.package} Daemon";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [
|
||||
pkgs.shadowsocks-libev
|
||||
cfg.package
|
||||
]
|
||||
++ optional (cfg.plugin != null) cfg.plugin
|
||||
++ optional (cfg.passwordFile != null) pkgs.jq;
|
||||
@@ -179,7 +202,9 @@ in
|
||||
${optionalString (cfg.passwordFile != null) ''
|
||||
cat ${configFile} | jq --arg password "$(cat "${cfg.passwordFile}")" '. + { password: $password }' > /tmp/shadowsocks.json
|
||||
''}
|
||||
exec ss-server -c ${if cfg.passwordFile != null then "/tmp/shadowsocks.json" else configFile}
|
||||
exec ${(executablesMap.${getName cfg.package}).server} -c ${
|
||||
if cfg.passwordFile != null then "/tmp/shadowsocks.json" else configFile
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
@@ -121,6 +121,9 @@ in
|
||||
Path to file which contains the master key.
|
||||
By doing so, all routes will be protected and will require a key to be accessed.
|
||||
If no master key is provided, all routes can be accessed without requiring any key.
|
||||
|
||||
You can generate a master key by running `openssl rand -base64 36`.
|
||||
Alternatively, you can start Meilisearch without a master key and use the pre-generated key from the service's logs that can be obtained by `journalctl -u meilisearch | grep -- --master-key`.
|
||||
'';
|
||||
default = null;
|
||||
type = lib.types.nullOr lib.types.path;
|
||||
|
||||
@@ -299,10 +299,8 @@ in
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
};
|
||||
|
||||
meta.maintainers =
|
||||
with lib.maintainers;
|
||||
[
|
||||
ppom
|
||||
]
|
||||
++ lib.teams.ngi.members;
|
||||
meta.teams = [ lib.teams.ngi ];
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
ppom
|
||||
];
|
||||
}
|
||||
|
||||
@@ -28,5 +28,5 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.hyprland.members;
|
||||
meta.teams = [ lib.teams.hyprland ];
|
||||
}
|
||||
|
||||
@@ -756,5 +756,5 @@ in
|
||||
};
|
||||
|
||||
meta.doc = ./jitsi-meet.md;
|
||||
meta.maintainers = lib.teams.jitsi.members;
|
||||
meta.teams = [ lib.teams.jitsi ];
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
}:
|
||||
let
|
||||
cfg = config.services.librechat;
|
||||
meiliCfg = config.services.meilisearch;
|
||||
format = pkgs.formats.yaml { };
|
||||
configFile = format.generate "librechat.yaml" cfg.settings;
|
||||
exportCredentials = n: _: ''export ${n}="$(${pkgs.systemd}/bin/systemd-creds cat ${n}_FILE)"'';
|
||||
@@ -155,6 +156,26 @@ in
|
||||
};
|
||||
|
||||
enableLocalDB = lib.mkEnableOption "a local mongodb instance";
|
||||
|
||||
meilisearch = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = {
|
||||
enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether to enable and configure Meilisearch locally for Librechat.
|
||||
You will manually need to set `services.meilisearch.masterKeyFile`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
default = { };
|
||||
description = ''
|
||||
See [LibreChat search feature](https://www.librechat.ai/docs/features/search).
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
@@ -178,6 +199,12 @@ in
|
||||
You can use https://www.librechat.ai/toolkit/creds_generator to generate these.
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = cfg.meilisearch.enable -> meiliCfg.masterKeyFile != null;
|
||||
message = ''
|
||||
LibreChat's Meilisearch integration requires `services.meilisearch.masterKeyFile` to be set.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
networking.firewall.allowedTCPPorts = lib.optional cfg.openFirewall cfg.port;
|
||||
@@ -192,7 +219,8 @@ in
|
||||
after = [
|
||||
"tmpfiles.target"
|
||||
]
|
||||
++ lib.optional cfg.enableLocalDB "mongodb.service";
|
||||
++ lib.optional cfg.meilisearch.enable "meilisearch.service";
|
||||
wants = lib.optional cfg.meilisearch.enable "meilisearch.service";
|
||||
description = "Open-source app for all your AI conversations, fully customizable and compatible with any AI provider";
|
||||
environment = cfg.env;
|
||||
script = # sh
|
||||
@@ -249,6 +277,11 @@ in
|
||||
|
||||
services.librechat.env.MONGO_URI = lib.mkIf cfg.enableLocalDB "mongodb://localhost:27017";
|
||||
services.mongodb.enable = lib.mkIf cfg.enableLocalDB true;
|
||||
|
||||
services.meilisearch.enable = lib.mkIf cfg.meilisearch.enable true;
|
||||
services.librechat.env.SEARCH = lib.mkIf cfg.meilisearch.enable true;
|
||||
services.librechat.env.MEILI_HOST = lib.mkIf cfg.meilisearch.enable "http://${meiliCfg.settings.http_addr}";
|
||||
services.librechat.credentials.MEILI_MASTER_KEY = lib.mkIf cfg.meilisearch.enable meiliCfg.masterKeyFile;
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
|
||||
@@ -1774,5 +1774,5 @@ in
|
||||
);
|
||||
|
||||
meta.doc = ./nextcloud.md;
|
||||
meta.maintainers = lib.teams.nextcloud.members;
|
||||
meta.teams = [ lib.teams.nextcloud ];
|
||||
}
|
||||
|
||||
@@ -252,5 +252,5 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = lib.teams.ngi.members;
|
||||
meta.teams = [ lib.teams.ngi ];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.speedtest-tracker;
|
||||
|
||||
user = cfg.user;
|
||||
group = cfg.group;
|
||||
|
||||
defaultUser = "speedtest-tracker";
|
||||
defaultGroup = "speedtest-tracker";
|
||||
|
||||
artisan = "${cfg.package}/artisan";
|
||||
|
||||
env-file-values = lib.mapAttrs' (n: v: {
|
||||
name = lib.removeSuffix "_FILE" n;
|
||||
value = v;
|
||||
}) (lib.filterAttrs (n: v: v != null && lib.match ".+_FILE" n != null) cfg.settings);
|
||||
|
||||
env-nonfile-values = lib.filterAttrs (n: v: lib.match ".+_FILE" n == null) cfg.settings;
|
||||
|
||||
speedtest-tracker-maintenance = pkgs.writeShellScript "speedtest-tracker-maintenance.sh" ''
|
||||
set -a
|
||||
${lib.toShellVars env-nonfile-values}
|
||||
${lib.concatLines (lib.mapAttrsToList (n: v: "${n}=\"$(< ${v})\"") env-file-values)}
|
||||
set +a
|
||||
${lib.optionalString (
|
||||
cfg.settings.DB_CONNECTION == "sqlite"
|
||||
) "touch ${cfg.dataDir}/storage/database/database.sqlite"}
|
||||
rm -f ${cfg.dataDir}/cache/*.php
|
||||
${artisan} package:discover
|
||||
${artisan} migrate --force
|
||||
${artisan} optimize:clear
|
||||
${artisan} view:cache
|
||||
${artisan} config:cache
|
||||
'';
|
||||
|
||||
speedtest-tracker-env-script =
|
||||
command:
|
||||
pkgs.writeShellScript "speedtest-tracker-${builtins.replaceStrings [ ":" " " ] [ "-" "-" ] command}.sh" ''
|
||||
set -a
|
||||
${lib.toShellVars env-nonfile-values}
|
||||
${lib.concatLines (lib.mapAttrsToList (n: v: "${n}=\"$(< ${v})\"") env-file-values)}
|
||||
set +a
|
||||
exec ${artisan} ${command}
|
||||
'';
|
||||
|
||||
commonServiceConfig = {
|
||||
Type = "oneshot";
|
||||
User = user;
|
||||
Group = group;
|
||||
StateDirectory = "speedtest-tracker";
|
||||
ReadWritePaths = [ cfg.dataDir ];
|
||||
WorkingDirectory = cfg.package;
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
CapabilityBoundingSet = "";
|
||||
AmbientCapabilities = "";
|
||||
ProtectSystem = "strict";
|
||||
ProtectKernelTunables = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectClock = true;
|
||||
ProtectHostname = true;
|
||||
ProtectHome = "tmpfs";
|
||||
ProtectKernelLogs = true;
|
||||
ProtectProc = "invisible";
|
||||
ProcSubset = "pid";
|
||||
PrivateNetwork = false;
|
||||
RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX";
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service @resources"
|
||||
"~@obsolete @privileged"
|
||||
];
|
||||
RestrictSUIDSGID = true;
|
||||
RemoveIPC = true;
|
||||
NoNewPrivileges = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictNamespaces = true;
|
||||
LockPersonality = true;
|
||||
PrivateUsers = true;
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
options.services.speedtest-tracker = {
|
||||
|
||||
enable = lib.mkEnableOption "Speedtest Tracker: A self-hosted internet performance tracking application";
|
||||
|
||||
package =
|
||||
lib.mkPackageOption pkgs "speedtest-tracker" { }
|
||||
// lib.mkOption {
|
||||
apply =
|
||||
speedtest-tracker:
|
||||
speedtest-tracker.override (prev: {
|
||||
dataDir = cfg.dataDir;
|
||||
});
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = defaultUser;
|
||||
description = "User account under which Speedtest Tracker runs.";
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = if cfg.enableNginx then "nginx" else defaultGroup;
|
||||
defaultText = "If `services.speedtest-tracker.enableNginx` is true then `nginx` else ${defaultGroup}";
|
||||
description = ''
|
||||
Group under which Speedtest Tracker runs. It is best to set this to the group
|
||||
of whatever webserver is being used as the frontend.
|
||||
'';
|
||||
};
|
||||
|
||||
dataDir = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
default = "/var/lib/speedtest-tracker";
|
||||
description = ''
|
||||
The place where Speedtest Tracker stores its state.
|
||||
'';
|
||||
};
|
||||
|
||||
enableNginx = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to enable nginx or not. If enabled, an nginx virtual host will
|
||||
be created for access to Speedtest Tracker. If not enabled, then you may use
|
||||
`''${config.services.speedtest-tracker.package}` as your document root in
|
||||
whichever webserver you wish to setup.
|
||||
'';
|
||||
};
|
||||
|
||||
virtualHost = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "localhost";
|
||||
description = ''
|
||||
The hostname at which you wish Speedtest Tracker to be served. If you have
|
||||
enabled nginx using `services.speedtest-tracker.enableNginx` then this will
|
||||
be used.
|
||||
'';
|
||||
};
|
||||
|
||||
poolConfig = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.oneOf [
|
||||
lib.types.str
|
||||
lib.types.int
|
||||
lib.types.bool
|
||||
]
|
||||
);
|
||||
default = { };
|
||||
defaultText = ''
|
||||
{
|
||||
"pm" = "dynamic";
|
||||
"pm.max_children" = 32;
|
||||
"pm.start_servers" = 2;
|
||||
"pm.min_spare_servers" = 2;
|
||||
"pm.max_spare_servers" = 4;
|
||||
"pm.max_requests" = 500;
|
||||
}
|
||||
'';
|
||||
description = ''
|
||||
Options for the Speedtest Tracker PHP pool. See the documentation on `php-fpm.conf`
|
||||
for details on configuration directives.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
default = { };
|
||||
description = ''
|
||||
Options for Speedtest Tracker configuration. Refer to
|
||||
<https://github.com/alexjustesen/speedtest-tracker> for
|
||||
details on supported values. All `_FILE` values are supported:
|
||||
append `_FILE` to the setting name to provide a path to a file
|
||||
containing the secret value.
|
||||
'';
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
APP_KEY_FILE = "/var/secrets/speedtest-tracker-app-key.txt";
|
||||
DB_CONNECTION = "mysql";
|
||||
DB_HOST = "db";
|
||||
DB_PORT = 3306;
|
||||
DB_DATABASE = "speedtest-tracker";
|
||||
DB_USERNAME = "speedtest-tracker";
|
||||
DB_PASSWORD_FILE = "/var/secrets/speedtest-tracker-mysql-password.txt";
|
||||
}
|
||||
'';
|
||||
type = lib.types.submodule {
|
||||
freeformType = lib.types.attrsOf (
|
||||
lib.types.oneOf [
|
||||
lib.types.str
|
||||
lib.types.int
|
||||
lib.types.bool
|
||||
]
|
||||
);
|
||||
options = {
|
||||
APP_KEY_FILE = lib.mkOption {
|
||||
type = lib.types.path;
|
||||
description = ''
|
||||
The path to your appkey. The file should contain a 32 character
|
||||
random app key. This may be set using `echo "base64:$(head -c 32
|
||||
/dev/urandom | base64)" > /path/to/key-file`.
|
||||
'';
|
||||
};
|
||||
APP_URL = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default =
|
||||
if cfg.virtualHost == "localhost" then
|
||||
"http://${cfg.virtualHost}"
|
||||
else
|
||||
"https://${cfg.virtualHost}";
|
||||
defaultText = ''
|
||||
http(s)://''${config.services.speedtest-tracker.virtualHost}
|
||||
'';
|
||||
description = ''
|
||||
The APP_URL used by Speedtest Tracker internally. Please make sure this
|
||||
URL matches the external URL of your installation. It is used to
|
||||
validate specific requests and to generate URLs in notifications.
|
||||
'';
|
||||
};
|
||||
DB_CONNECTION = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"sqlite"
|
||||
"mysql"
|
||||
"mariadb"
|
||||
"pgsql"
|
||||
];
|
||||
default = "sqlite";
|
||||
example = "pgsql";
|
||||
description = ''
|
||||
The type of database you wish to use. Can be one of "sqlite",
|
||||
"mysql", "mariadb" or "pgsql".
|
||||
'';
|
||||
};
|
||||
DB_HOST = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "localhost";
|
||||
description = ''
|
||||
The IP or hostname which hosts your database.
|
||||
'';
|
||||
};
|
||||
DB_PORT = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.int;
|
||||
default =
|
||||
if cfg.settings.DB_CONNECTION == "pgsql" then
|
||||
5432
|
||||
else if cfg.settings.DB_CONNECTION == "mysql" || cfg.settings.DB_CONNECTION == "mariadb" then
|
||||
3306
|
||||
else
|
||||
null;
|
||||
defaultText = ''
|
||||
`null` if DB_CONNECTION is "sqlite", `3306` if "mysql" or "mariadb", `5432` if "pgsql"
|
||||
'';
|
||||
description = ''
|
||||
The port your database is listening at. sqlite does not require
|
||||
this value to be filled.
|
||||
'';
|
||||
};
|
||||
DB_DATABASE = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default =
|
||||
if cfg.settings.DB_CONNECTION == "sqlite" then
|
||||
"${cfg.dataDir}/storage/database/database.sqlite"
|
||||
else
|
||||
"speedtest-tracker";
|
||||
defaultText = ''
|
||||
"''${config.services.speedtest-tracker.dataDir}/storage/database/database.sqlite" if DB_CONNECTION is "sqlite", "speedtest-tracker" otherwise
|
||||
'';
|
||||
description = ''
|
||||
The name of the database, or path to the sqlite file.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
|
||||
services.phpfpm.pools.speedtest-tracker = {
|
||||
inherit user group;
|
||||
phpPackage = cfg.package.phpPackage;
|
||||
phpOptions = ''
|
||||
log_errors = on
|
||||
'';
|
||||
settings = {
|
||||
"listen.mode" = lib.mkDefault "0660";
|
||||
"listen.owner" = lib.mkDefault user;
|
||||
"listen.group" = lib.mkDefault group;
|
||||
"pm" = lib.mkDefault "dynamic";
|
||||
"pm.max_children" = lib.mkDefault 32;
|
||||
"pm.start_servers" = lib.mkDefault 2;
|
||||
"pm.min_spare_servers" = lib.mkDefault 2;
|
||||
"pm.max_spare_servers" = lib.mkDefault 4;
|
||||
"pm.max_requests" = lib.mkDefault 500;
|
||||
}
|
||||
// cfg.poolConfig;
|
||||
};
|
||||
|
||||
systemd.services.speedtest-tracker-setup = {
|
||||
after = [
|
||||
"postgresql.target"
|
||||
"mysql.service"
|
||||
];
|
||||
requiredBy = [ "phpfpm-speedtest-tracker.service" ];
|
||||
before = [ "phpfpm-speedtest-tracker.service" ];
|
||||
serviceConfig = {
|
||||
ExecStart = speedtest-tracker-maintenance;
|
||||
RemainAfterExit = true;
|
||||
}
|
||||
// commonServiceConfig;
|
||||
unitConfig.JoinsNamespaceOf = "phpfpm-speedtest-tracker.service";
|
||||
restartTriggers = [ cfg.package ];
|
||||
partOf = [ "phpfpm-speedtest-tracker.service" ];
|
||||
};
|
||||
|
||||
systemd.services.speedtest-tracker-scheduler = {
|
||||
after = [ "speedtest-tracker-setup.service" ];
|
||||
wants = [ "speedtest-tracker-setup.service" ];
|
||||
description = "Speedtest Tracker scheduler";
|
||||
path = [ pkgs.ookla-speedtest ];
|
||||
serviceConfig = {
|
||||
ExecStart = speedtest-tracker-env-script "schedule:run";
|
||||
}
|
||||
// commonServiceConfig;
|
||||
};
|
||||
|
||||
systemd.timers.speedtest-tracker-scheduler = {
|
||||
description = "Speedtest Tracker scheduler timer";
|
||||
timerConfig = {
|
||||
OnCalendar = "minutely";
|
||||
Persistent = true;
|
||||
};
|
||||
wantedBy = [ "timers.target" ];
|
||||
restartTriggers = [ cfg.package ];
|
||||
};
|
||||
|
||||
systemd.services.speedtest-tracker-queue-worker = {
|
||||
after = [ "speedtest-tracker-setup.service" ];
|
||||
wants = [ "speedtest-tracker-setup.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
description = "Speedtest Tracker queue worker";
|
||||
path = [ pkgs.ookla-speedtest ];
|
||||
serviceConfig = commonServiceConfig // {
|
||||
Type = "simple";
|
||||
Restart = "always";
|
||||
ExecStart = speedtest-tracker-env-script "queue:work --sleep=3 --tries=3";
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx = lib.mkIf cfg.enableNginx {
|
||||
enable = true;
|
||||
recommendedTlsSettings = lib.mkDefault true;
|
||||
recommendedOptimisation = lib.mkDefault true;
|
||||
recommendedGzipSettings = lib.mkDefault true;
|
||||
virtualHosts.${cfg.virtualHost} = {
|
||||
root = "${cfg.package}/public";
|
||||
locations = {
|
||||
"/" = {
|
||||
tryFiles = "$uri $uri/ /index.php?$query_string";
|
||||
index = "index.php";
|
||||
extraConfig = ''
|
||||
sendfile off;
|
||||
'';
|
||||
};
|
||||
"~ \\.php$" = {
|
||||
extraConfig = ''
|
||||
include ${config.services.nginx.package}/conf/fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||
fastcgi_param modHeadersAvailable true;
|
||||
fastcgi_pass unix:${config.services.phpfpm.pools.speedtest-tracker.socket};
|
||||
'';
|
||||
};
|
||||
"~ \\.(js|css|gif|png|ico|jpg|jpeg)$" = {
|
||||
extraConfig = "expires 365d;";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.settings."10-speedtest-tracker" =
|
||||
lib.genAttrs
|
||||
[
|
||||
"${cfg.dataDir}/storage"
|
||||
"${cfg.dataDir}/storage/app"
|
||||
"${cfg.dataDir}/storage/database"
|
||||
"${cfg.dataDir}/storage/framework"
|
||||
"${cfg.dataDir}/storage/framework/cache"
|
||||
"${cfg.dataDir}/storage/framework/sessions"
|
||||
"${cfg.dataDir}/storage/framework/views"
|
||||
"${cfg.dataDir}/storage/logs"
|
||||
"${cfg.dataDir}/cache"
|
||||
]
|
||||
(n: {
|
||||
d = {
|
||||
inherit group;
|
||||
mode = "0700";
|
||||
inherit user;
|
||||
};
|
||||
})
|
||||
// {
|
||||
"${cfg.dataDir}".d = {
|
||||
inherit group;
|
||||
mode = "0710";
|
||||
inherit user;
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
users = lib.mkIf (user == defaultUser) {
|
||||
${defaultUser} = {
|
||||
inherit group;
|
||||
isSystemUser = true;
|
||||
home = cfg.dataDir;
|
||||
};
|
||||
};
|
||||
groups = lib.mkIf (group == defaultGroup) { ${defaultGroup} = { }; };
|
||||
};
|
||||
};
|
||||
|
||||
meta.maintainers = pkgs.speedtest-tracker.meta.maintainers;
|
||||
}
|
||||
@@ -25,7 +25,7 @@ in
|
||||
|
||||
{
|
||||
meta = {
|
||||
maintainers = teams.enlightenment.members;
|
||||
teams = [ teams.enlightenment ];
|
||||
};
|
||||
|
||||
imports = [
|
||||
|
||||
@@ -16,7 +16,7 @@ in
|
||||
|
||||
{
|
||||
meta = {
|
||||
maintainers = teams.lumina.members;
|
||||
teams = [ teams.lumina ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -15,7 +15,7 @@ in
|
||||
|
||||
{
|
||||
meta = {
|
||||
maintainers = teams.lxqt.members;
|
||||
teams = [ teams.lxqt ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -15,7 +15,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = teams.xfce.members;
|
||||
teams = [ teams.xfce ];
|
||||
};
|
||||
|
||||
imports = [
|
||||
|
||||
@@ -40,6 +40,6 @@ python3.pkgs.buildPythonApplication {
|
||||
'';
|
||||
|
||||
meta = {
|
||||
maintainers = [ ] ++ lib.teams.pantheon.members;
|
||||
teams = [ lib.teams.pantheon ];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ let
|
||||
|
||||
in
|
||||
{
|
||||
meta.maintainers = lib.teams.lomiri.members;
|
||||
meta.teams = [ lib.teams.lomiri ];
|
||||
|
||||
options = {
|
||||
services.xserver.displayManager.lightdm.greeters.lomiri = {
|
||||
|
||||
@@ -16,7 +16,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = [ ] ++ lib.teams.pantheon.members;
|
||||
teams = [ lib.teams.pantheon ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -73,7 +73,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = [ ] ++ lib.teams.pantheon.members;
|
||||
teams = [ lib.teams.pantheon ];
|
||||
};
|
||||
|
||||
# Note: the order in which lightdm greeter modules are imported
|
||||
|
||||
@@ -13,7 +13,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = teams.pantheon.members;
|
||||
teams = [ teams.pantheon ];
|
||||
};
|
||||
|
||||
###### interface
|
||||
|
||||
@@ -13,7 +13,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = [ ] ++ lib.teams.podman.members;
|
||||
teams = [ lib.teams.podman ];
|
||||
};
|
||||
|
||||
options.virtualisation.containers = {
|
||||
|
||||
@@ -21,7 +21,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = teams.podman.members;
|
||||
teams = [ teams.podman ];
|
||||
};
|
||||
|
||||
options.virtualisation.cri-o = {
|
||||
|
||||
@@ -10,7 +10,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.lxc.members;
|
||||
teams = [ lib.teams.lxc ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -10,7 +10,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.lxc.members;
|
||||
teams = [ lib.teams.lxc ];
|
||||
};
|
||||
|
||||
imports = [
|
||||
|
||||
@@ -176,7 +176,7 @@ let
|
||||
in
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.lxc.members;
|
||||
teams = [ lib.teams.lxc ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
{
|
||||
meta = {
|
||||
maintainers = lib.teams.lxc.members;
|
||||
teams = [ lib.teams.lxc ];
|
||||
};
|
||||
|
||||
imports = [
|
||||
|
||||
@@ -71,7 +71,7 @@ in
|
||||
];
|
||||
|
||||
meta = {
|
||||
maintainers = lib.teams.lxc.members;
|
||||
teams = [ lib.teams.lxc ];
|
||||
};
|
||||
|
||||
options = {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user