Merge master into haskell-updates

This commit is contained in:
github-actions[bot] 2024-08-29 00:15:02 +00:00 committed by GitHub
commit 6cdc8ac1f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
268 changed files with 9993 additions and 7704 deletions

View File

@ -533,7 +533,6 @@ writeScript "my-file"
Contents of File
''
```
:::
This is equivalent to:
@ -546,6 +545,7 @@ writeTextFile {
executable = true;
}
```
:::
### `writeScriptBin` {#trivial-builder-writeScriptBin}

View File

@ -13173,6 +13173,13 @@
githubId = 191622;
name = "Denys Pavlov";
};
meator = {
email = "meator.dev@gmail.com";
github = "meator";
githubId = 67633081;
name = "meator";
keys = [ { fingerprint = "7B0F 58A5 E0F1 A2EA 1157 8A73 1A14 CB34 64CB E5BF"; } ];
};
meditans = {
email = "meditans@gmail.com";
github = "meditans";
@ -21170,6 +21177,12 @@
githubId = 16036882;
name = "Thibault Gagnaux";
};
tri-ler = {
github = "tri-ler";
githubId = 47867303;
email = "tylerh689@gmail.com";
name = "Tyler Hong";
};
trino = {
email = "muehlhans.hubert@ekodia.de";
github = "hmuehlhans";

View File

@ -43,6 +43,8 @@
- [Flood](https://flood.js.org/), a beautiful WebUI for various torrent clients. Available as [services.flood](options.html#opt-services.flood).
- [Firefly-iii Data Importer](https://github.com/firefly-iii/data-importer), a data importer for Firefly-III. Available as [services.firefly-iii-data-importer](options.html#opt-services.firefly-iii-data-importer)
- [QGroundControl], a ground station support and configuration manager for the PX4 and APM Flight Stacks. Available as [programs.qgroundcontrol](options.html#opt-programs.qgroundcontrol.enable).
- [Eintopf](https://eintopf.info), community event and calendar web application. Available as [services.eintopf](options.html#opt-services.eintopf).
@ -96,6 +98,10 @@
- [chromadb](https://www.trychroma.com/), an open-source AI application
database. Batteries included. Available as [services.chromadb](options.html#opt-services.chromadb.enable).
- [Wakapi](https://wakapi.dev/), a time tracking software for programmers. Available as [services.wakapi](#opt-services.wakapi.enable).
- [foot](https://codeberg.org/dnkl/foot), a fast, lightweight and minimalistic Wayland terminal emulator. Available as [programs.foot](#opt-programs.foot.enable).
## Backward Incompatibilities {#sec-release-24.11-incompatibilities}
- `transmission` package has been aliased with a `trace` warning to `transmission_3`. Since [Transmission 4 has been released last year](https://github.com/transmission/transmission/releases/tag/4.0.0), and Transmission 3 will eventually go away, it was decided perform this warning alias to make people aware of the new version. The `services.transmission.package` defaults to `transmission_3` as well because the upgrade can cause data loss in certain specific usage patterns (examples: [#5153](https://github.com/transmission/transmission/issues/5153), [#6796](https://github.com/transmission/transmission/issues/6796)). Please make sure to back up to your data directory per your usage:
@ -399,10 +405,8 @@
- The hooks `yarnConfigHook` and `yarnBuildHook` were added. These should replace `yarn2nix.mkYarnPackage` and other `yarn2nix` related tools. The motivation to get rid of `yarn2nix` tools is the fact that they are too complex and hard to maintain, and they rely upon too much Nix evaluation which is problematic if import-from-derivation is not allowed (see more details at [#296856](https://github.com/NixOS/nixpkgs/issues/296856). The transition from `mkYarnPackage` to `yarn{Config,Build}Hook` is tracked at [#324246](https://github.com/NixOS/nixpkgs/issues/324246).
- Cinnamon has been updated to 6.2.
- Following Mint 22 defaults, the Cinnamon module no longer ships geary and hexchat by default.
- Nemo is now built with gtk-layer-shell support, note that for now it will be expected to see nemo-desktop
listed as a regular entry in Cinnamon Wayland session's window list applet.
- Cinnamon has been updated to 6.2, please check [upstream announcement](https://www.linuxmint.com/rel_wilma_whatsnew.php) for more details.
Following Mint 22 defaults, the Cinnamon module no longer ships geary and hexchat by default.
- The `shadowstack` hardening flag has been added, though disabled by default.

View File

@ -58,10 +58,18 @@ pkgs.stdenv.mkDerivation {
# Make a crude approximation of the size of the target image.
# If the script starts failing, increase the fudge factors here.
numInodes=$(find ./rootImage | wc -l)
numDataBlocks=$(du -s -c -B 4096 --apparent-size ./rootImage | tail -1 | awk '{ print int($1 * 1.10) }')
numDataBlocks=$(du -s -c -B 4096 --apparent-size ./rootImage | tail -1 | awk '{ print int($1 * 1.20) }')
bytes=$((2 * 4096 * $numInodes + 4096 * $numDataBlocks))
echo "Creating an EXT4 image of $bytes bytes (numInodes=$numInodes, numDataBlocks=$numDataBlocks)"
mebibyte=$(( 1024 * 1024 ))
# Round up to the nearest mebibyte.
# This ensures whole 512 bytes sector sizes in the disk image
# and helps towards aligning partitions optimally.
if (( bytes % mebibyte )); then
bytes=$(( ( bytes / mebibyte + 1) * mebibyte ))
fi
truncate -s $bytes $img
faketime -f "1970-01-01 00:00:01" fakeroot mkfs.ext4 -L ${volumeLabel} -U ${uuid} -d ./rootImage $img

View File

@ -63,7 +63,7 @@ with lib;
# Firefox for reading the manual.
firefox
glxinfo
mesa-demos
];
}

View File

@ -193,6 +193,7 @@
./programs/fish.nix
./programs/flashrom.nix
./programs/flexoptix-app.nix
./programs/foot
./programs/freetds.nix
./programs/fuse.nix
./programs/fzf.nix
@ -286,6 +287,7 @@
./programs/ssh.nix
./programs/starship.nix
./programs/steam.nix
./programs/streamcontroller.nix
./programs/streamdeck-ui.nix
./programs/sysdig.nix
./programs/system-config-printer.nix
@ -1401,6 +1403,7 @@
./services/web-apps/ethercalc.nix
./services/web-apps/filesender.nix
./services/web-apps/firefly-iii.nix
./services/web-apps/firefly-iii-data-importer.nix
./services/web-apps/flarum.nix
./services/web-apps/fluidd.nix
./services/web-apps/freshrss.nix
@ -1489,6 +1492,7 @@
./services/web-apps/trilium.nix
./services/web-apps/tt-rss.nix
./services/web-apps/vikunja.nix
./services/web-apps/wakapi.nix
./services/web-apps/weblate.nix
./services/web-apps/whitebophir.nix
./services/web-apps/wiki-js.nix

View File

@ -17,5 +17,5 @@
# Enable sound in virtualbox appliances.
hardware.pulseaudio.enable = true;
environment.systemPackages = [ pkgs.glxinfo pkgs.firefox ];
environment.systemPackages = [ pkgs.mesa-demos pkgs.firefox ];
}

View File

@ -0,0 +1,27 @@
osc7_cwd() {
local strlen=${#PWD}
local encoded=""
local pos c o
for (( pos=0; pos<strlen; pos++ )); do
c=${PWD:$pos:1}
case "$c" in
[-/:_.!\'\(\)~[:alnum:]] ) o="${c}" ;;
* ) printf -v o '%%%02X' "'${c}" ;;
esac
encoded+="${o}"
done
printf '\e]7;file://%s%s\e\\' "${HOSTNAME}" "${encoded}"
}
PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND; }osc7_cwd
prompt_marker() {
printf '\e]133;A\e\\'
}
PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND; }prompt_marker
PS0+='\e]133;C\e\\'
command_done() {
printf '\e]133;D\e\\'
}
PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND; }command_done

View File

@ -0,0 +1,20 @@
function update_cwd_osc --on-variable PWD --description 'Notify terminals when $PWD changes'
if status --is-command-substitution || set -q INSIDE_EMACS
return
end
printf \e\]7\;file://%s%s\e\\ $hostname (string escape --style=url $PWD)
end
update_cwd_osc # Run once since we might have inherited PWD from a parent shell
function mark_prompt_start --on-event fish_prompt
echo -en "\e]133;A\e\\"
end
function foot_cmd_start --on-event fish_preexec
echo -en "\e]133;C\e\\"
end
function foot_cmd_end --on-event fish_postexec
echo -en "\e]133;D\e\\"
end

View File

@ -0,0 +1,92 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.foot;
settingsFormat = pkgs.formats.ini {
listsAsDuplicateKeys = true;
mkKeyValue =
with lib.generators;
mkKeyValueDefault {
mkValueString =
v:
mkValueStringDefault { } (
if v == true then
"yes"
else if v == false then
"no"
else if v == null then
"none"
else
v
);
} "=";
};
in
{
options.programs.foot = {
enable = lib.mkEnableOption "foot terminal emulator";
package = lib.mkPackageOption pkgs "foot" { };
settings = lib.mkOption {
inherit (settingsFormat) type;
default = { };
description = ''
Configuration for foot terminal emulator. Further information can be found in {command}`man 5 foot.ini`.
Global configuration has to be written under the [main] section.
'';
example = {
main.font = "FreeMono:size=12";
scrollback.lines = 100000;
};
};
theme = lib.mkOption {
type = with lib.types; nullOr str;
default = null;
description = ''
Theme name. Check <https://codeberg.org/dnkl/foot/src/branch/master/themes> for available themes.
'';
example = "aeroroot";
};
enableBashIntegration = lib.mkEnableOption "foot bash integration" // {
default = true;
};
enableFishIntegration = lib.mkEnableOption "foot fish integration" // {
default = true;
};
enableZshIntegration = lib.mkEnableOption "foot zsh integration" // {
default = true;
};
};
config = lib.mkIf cfg.enable {
environment = {
systemPackages = [ cfg.package ];
etc."xdg/foot/foot.ini".source = settingsFormat.generate "foot.ini" cfg.settings;
};
programs = {
foot.settings.main.include = lib.optionals (cfg.theme != null) [
"${pkgs.foot.themes}/share/foot/themes/${cfg.theme}"
];
# https://codeberg.org/dnkl/foot/wiki#user-content-shell-integration
bash.interactiveShellInit = lib.mkIf cfg.enableBashIntegration ". ${./bashrc} # enable shell integration for foot terminal";
fish.interactiveShellInit = lib.mkIf cfg.enableFishIntegration "source ${./config.fish} # enable shell integration for foot terminal";
zsh.interactiveShellInit = lib.mkIf cfg.enableZshIntegration ". ${./zshrc} # enable shell integration for foot terminal";
};
};
meta = {
maintainers = with lib.maintainers; [ linsui ];
};
}

View File

@ -0,0 +1,25 @@
function osc7-pwd() {
emulate -L zsh # also sets localoptions for us
setopt extendedglob
local LC_ALL=C
printf '\e]7;file://%s%s\e\' $HOST ${PWD//(#m)([^@-Za-z&-;_~])/%${(l:2::0:)$(([##16]#MATCH))}}
}
function chpwd-osc7-pwd() {
(( ZSH_SUBSHELL )) || osc7-pwd
}
add-zsh-hook -Uz chpwd chpwd-osc7-pwd
precmd() {
print -Pn "\e]133;A\e\\"
}
function precmd {
if ! builtin zle; then
print -n "\e]133;D\e\\"
fi
}
function preexec {
print -n "\e]133;C\e\\"
}

View File

@ -0,0 +1,22 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.streamcontroller;
in
{
options.programs.streamcontroller = {
enable = lib.mkEnableOption "StreamController";
package = lib.mkPackageOption pkgs "streamcontroller" { default = [ "streamcontroller" ]; };
};
config = lib.mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
services.udev.packages = [ cfg.package ];
};
meta.maintainers = with lib.maintainers; [ sifmelcara ];
}

View File

@ -1,7 +1,4 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.postfix;
@ -17,32 +14,32 @@ let
haveLocalRecipients = cfg.localRecipients != null;
clientAccess =
optional (cfg.dnsBlacklistOverrides != "")
lib.optional (cfg.dnsBlacklistOverrides != "")
"check_client_access hash:/etc/postfix/client_access";
dnsBl =
optionals (cfg.dnsBlacklists != [])
lib.optionals (cfg.dnsBlacklists != [])
(map (s: "reject_rbl_client " + s) cfg.dnsBlacklists);
clientRestrictions = concatStringsSep ", " (clientAccess ++ dnsBl);
clientRestrictions = lib.concatStringsSep ", " (clientAccess ++ dnsBl);
mainCf = let
escape = replaceStrings ["$"] ["$$"];
mkList = items: "\n " + concatStringsSep ",\n " items;
escape = lib.replaceStrings ["$"] ["$$"];
mkList = items: "\n " + lib.concatStringsSep ",\n " items;
mkVal = value:
if isList value then mkList value
if lib.isList value then mkList value
else " " + (if value == true then "yes"
else if value == false then "no"
else toString value);
mkEntry = name: value: "${escape name} =${mkVal value}";
in
concatStringsSep "\n" (mapAttrsToList mkEntry cfg.config)
lib.concatStringsSep "\n" (lib.mapAttrsToList mkEntry cfg.config)
+ "\n" + cfg.extraConfig;
masterCfOptions = { options, config, name, ... }: {
options = {
name = mkOption {
type = types.str;
name = lib.mkOption {
type = lib.types.str;
default = name;
example = "smtp";
description = ''
@ -50,15 +47,15 @@ let
'';
};
type = mkOption {
type = types.enum [ "inet" "unix" "unix-dgram" "fifo" "pass" ];
type = lib.mkOption {
type = lib.types.enum [ "inet" "unix" "unix-dgram" "fifo" "pass" ];
default = "unix";
example = "inet";
description = "The type of the service";
};
private = mkOption {
type = types.bool;
private = lib.mkOption {
type = lib.types.bool;
example = false;
description = ''
Whether the service's sockets and storage directory is restricted to
@ -67,14 +64,14 @@ let
'';
};
privileged = mkOption {
type = types.bool;
privileged = lib.mkOption {
type = lib.types.bool;
example = true;
description = "";
};
chroot = mkOption {
type = types.bool;
chroot = lib.mkOption {
type = lib.types.bool;
example = true;
description = ''
Whether the service is chrooted to have only access to the
@ -83,8 +80,8 @@ let
'';
};
wakeup = mkOption {
type = types.int;
wakeup = lib.mkOption {
type = lib.types.int;
example = 60;
description = ''
Automatically wake up the service after the specified number of
@ -93,8 +90,8 @@ let
'';
};
wakeupUnusedComponent = mkOption {
type = types.bool;
wakeupUnusedComponent = lib.mkOption {
type = lib.types.bool;
example = false;
description = ''
If set to `false` the component will only be woken
@ -104,8 +101,8 @@ let
'';
};
maxproc = mkOption {
type = types.int;
maxproc = lib.mkOption {
type = lib.types.int;
example = 1;
description = ''
The maximum number of processes to spawn for this service. If the
@ -115,8 +112,8 @@ let
'';
};
command = mkOption {
type = types.str;
command = lib.mkOption {
type = lib.types.str;
default = name;
example = "smtpd";
description = ''
@ -125,8 +122,8 @@ let
'';
};
args = mkOption {
type = types.listOf types.str;
args = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
example = [ "-o" "smtp_helo_timeout=5" ];
description = ''
@ -136,8 +133,8 @@ let
'';
};
rawEntry = mkOption {
type = types.listOf types.str;
rawEntry = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
internal = true;
description = ''
@ -148,7 +145,7 @@ let
config.rawEntry = let
mkBool = bool: if bool then "y" else "n";
mkArg = arg: "${optionalString (hasPrefix "-" arg) "\n "}${arg}";
mkArg = arg: "${lib.optionalString (lib.hasPrefix "-" arg) "\n "}${arg}";
maybeOption = fun: option:
if options.${option}.isDefined then fun config.${option} else "-";
@ -158,7 +155,7 @@ let
wakeupDefined = options.wakeup.isDefined;
wakeupUCDefined = options.wakeupUnusedComponent.isDefined;
finalValue = toString config.wakeup
+ optionalString (wakeupUCDefined && !config.wakeupUnusedComponent) "?";
+ lib.optionalString (wakeupUCDefined && !config.wakeupUnusedComponent) "?";
in if wakeupDefined then finalValue else "-";
in [
@ -169,7 +166,7 @@ let
(maybeOption mkBool "chroot")
wakeup
(maybeOption toString "maxproc")
(config.command + " " + concatMapStringsSep " " mkArg config.args)
(config.command + " " + lib.concatMapStringsSep " " mkArg config.args)
];
};
@ -184,47 +181,47 @@ let
"# " "" "(yes)" "(yes)" "(no)" "(never)" "(100)" "" ""
];
masterCf = mapAttrsToList (const (getAttr "rawEntry")) cfg.masterConfig;
masterCf = lib.mapAttrsToList (lib.const (lib.getAttr "rawEntry")) cfg.masterConfig;
# A list of the maximum width of the columns across all lines and labels
maxWidths = let
foldLine = line: acc: let
columnLengths = map stringLength line;
in zipListsWith max acc columnLengths;
columnLengths = map lib.stringLength line;
in lib.zipListsWith lib.max acc columnLengths;
# We need to handle the last column specially here, because it's
# open-ended (command + args).
lines = [ labels labelDefaults ] ++ (map (l: init l ++ [""]) masterCf);
in foldr foldLine (genList (const 0) (length labels)) lines;
lines = [ labels labelDefaults ] ++ (map (l: lib.init l ++ [""]) masterCf);
in lib.foldr foldLine (lib.genList (lib.const 0) (lib.length labels)) lines;
# Pad a string with spaces from the right (opposite of fixedWidthString).
pad = width: str: let
padWidth = width - stringLength str;
padding = concatStrings (genList (const " ") padWidth);
in str + optionalString (padWidth > 0) padding;
padWidth = width - lib.stringLength str;
padding = lib.concatStrings (lib.genList (lib.const " ") padWidth);
in str + lib.optionalString (padWidth > 0) padding;
# It's + 2 here, because that's the amount of spacing between columns.
fullWidth = foldr (width: acc: acc + width + 2) 0 maxWidths;
fullWidth = lib.foldr (width: acc: acc + width + 2) 0 maxWidths;
formatLine = line: concatStringsSep " " (zipListsWith pad maxWidths line);
formatLine = line: lib.concatStringsSep " " (lib.zipListsWith pad maxWidths line);
formattedLabels = let
sep = "# " + concatStrings (genList (const "=") (fullWidth + 5));
sep = "# " + lib.concatStrings (lib.genList (lib.const "=") (fullWidth + 5));
lines = [ sep (formatLine labels) (formatLine labelDefaults) sep ];
in concatStringsSep "\n" lines;
in lib.concatStringsSep "\n" lines;
in formattedLabels + "\n" + concatMapStringsSep "\n" formatLine masterCf + "\n" + cfg.extraMasterConf;
in formattedLabels + "\n" + lib.concatMapStringsSep "\n" formatLine masterCf + "\n" + cfg.extraMasterConf;
headerCheckOptions = { ... }:
{
options = {
pattern = mkOption {
type = types.str;
pattern = lib.mkOption {
type = lib.types.str;
default = "/^.*/";
example = "/^X-Mailer:/";
description = "A regexp pattern matching the header";
};
action = mkOption {
type = types.str;
action = lib.mkOption {
type = lib.types.str;
default = "DUNNO";
example = "BCC mail@example.com";
description = "The action to be executed when the pattern is matched";
@ -232,13 +229,13 @@ let
};
};
headerChecks = concatStringsSep "\n" (map (x: "${x.pattern} ${x.action}") cfg.headerChecks) + cfg.extraHeaderChecks;
headerChecks = lib.concatStringsSep "\n" (map (x: "${x.pattern} ${x.action}") cfg.headerChecks) + cfg.extraHeaderChecks;
aliases = let separator = optionalString (cfg.aliasMapType == "hash") ":"; in
optionalString (cfg.postmasterAlias != "") ''
aliases = let separator = lib.optionalString (cfg.aliasMapType == "hash") ":"; in
lib.optionalString (cfg.postmasterAlias != "") ''
postmaster${separator} ${cfg.postmasterAlias}
''
+ optionalString (cfg.rootAlias != "") ''
+ lib.optionalString (cfg.rootAlias != "") ''
root${separator} ${cfg.rootAlias}
''
+ cfg.extraAliases
@ -247,7 +244,7 @@ let
aliasesFile = pkgs.writeText "postfix-aliases" aliases;
canonicalFile = pkgs.writeText "postfix-canonical" cfg.canonical;
virtualFile = pkgs.writeText "postfix-virtual" cfg.virtual;
localRecipientMapFile = pkgs.writeText "postfix-local-recipient-map" (concatMapStrings (x: x + " ACCEPT\n") cfg.localRecipients);
localRecipientMapFile = pkgs.writeText "postfix-local-recipient-map" (lib.concatMapStrings (x: x + " ACCEPT\n") cfg.localRecipients);
checkClientAccessFile = pkgs.writeText "postfix-check-client-access" cfg.dnsBlacklistOverrides;
mainCfFile = pkgs.writeText "postfix-main.cf" mainCf;
masterCfFile = pkgs.writeText "postfix-master.cf" masterCfContent;
@ -264,26 +261,26 @@ in
services.postfix = {
enable = mkOption {
type = types.bool;
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to run the Postfix mail server.";
};
enableSmtp = mkOption {
type = types.bool;
enableSmtp = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to enable smtp in master.cf.";
};
enableSubmission = mkOption {
type = types.bool;
enableSubmission = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to enable smtp submission.";
};
enableSubmissions = mkOption {
type = types.bool;
enableSubmissions = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable smtp submission via smtps.
@ -293,8 +290,8 @@ in
'';
};
submissionOptions = mkOption {
type = with types; attrsOf str;
submissionOptions = lib.mkOption {
type = with lib.types; attrsOf str;
default = {
smtpd_tls_security_level = "encrypt";
smtpd_sasl_auth_enable = "yes";
@ -311,8 +308,8 @@ in
description = "Options for the submission config in master.cf";
};
submissionsOptions = mkOption {
type = with types; attrsOf str;
submissionsOptions = lib.mkOption {
type = with lib.types; attrsOf str;
default = {
smtpd_sasl_auth_enable = "yes";
smtpd_client_restrictions = "permit_sasl_authenticated,reject";
@ -334,26 +331,26 @@ in
'';
};
setSendmail = mkOption {
type = types.bool;
setSendmail = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to set the system sendmail to postfix's.";
};
user = mkOption {
type = types.str;
user = lib.mkOption {
type = lib.types.str;
default = "postfix";
description = "What to call the Postfix user (must be used only for postfix).";
};
group = mkOption {
type = types.str;
group = lib.mkOption {
type = lib.types.str;
default = "postfix";
description = "What to call the Postfix group (must be used only for postfix).";
};
setgidGroup = mkOption {
type = types.str;
setgidGroup = lib.mkOption {
type = lib.types.str;
default = "postdrop";
description = ''
How to call postfix setgid group (for postdrop). Should
@ -361,8 +358,8 @@ in
'';
};
networks = mkOption {
type = types.nullOr (types.listOf types.str);
networks = lib.mkOption {
type = lib.types.nullOr (lib.types.listOf lib.types.str);
default = null;
example = ["192.168.0.1/24"];
description = ''
@ -372,8 +369,8 @@ in
'';
};
networksStyle = mkOption {
type = types.str;
networksStyle = lib.mkOption {
type = lib.types.str;
default = "";
description = ''
Name of standard way of trusted network specification to use,
@ -382,8 +379,8 @@ in
'';
};
hostname = mkOption {
type = types.str;
hostname = lib.mkOption {
type = lib.types.str;
default = "";
description = ''
Hostname to use. Leave blank to use just the hostname of machine.
@ -391,24 +388,24 @@ in
'';
};
domain = mkOption {
type = types.str;
domain = lib.mkOption {
type = lib.types.str;
default = "";
description = ''
Domain to use. Leave blank to use hostname minus first component.
'';
};
origin = mkOption {
type = types.str;
origin = lib.mkOption {
type = lib.types.str;
default = "";
description = ''
Origin to use in outgoing e-mail. Leave blank to use hostname.
'';
};
destination = mkOption {
type = types.nullOr (types.listOf types.str);
destination = lib.mkOption {
type = lib.types.nullOr (lib.types.listOf lib.types.str);
default = null;
example = ["localhost"];
description = ''
@ -417,8 +414,8 @@ in
'';
};
relayDomains = mkOption {
type = types.nullOr (types.listOf types.str);
relayDomains = lib.mkOption {
type = lib.types.nullOr (lib.types.listOf lib.types.str);
default = null;
example = ["localdomain"];
description = ''
@ -426,32 +423,32 @@ in
'';
};
relayHost = mkOption {
type = types.str;
relayHost = lib.mkOption {
type = lib.types.str;
default = "";
description = ''
Mail relay for outbound mail.
'';
};
relayPort = mkOption {
type = types.int;
relayPort = lib.mkOption {
type = lib.types.int;
default = 25;
description = ''
SMTP port for relay mail relay.
'';
};
lookupMX = mkOption {
type = types.bool;
lookupMX = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether relay specified is just domain whose MX must be used.
'';
};
postmasterAlias = mkOption {
type = types.str;
postmasterAlias = lib.mkOption {
type = lib.types.str;
default = "root";
description = ''
Who should receive postmaster e-mail. Multiple values can be added by
@ -459,8 +456,8 @@ in
'';
};
rootAlias = mkOption {
type = types.str;
rootAlias = lib.mkOption {
type = lib.types.str;
default = "";
description = ''
Who should receive root e-mail. Blank for no redirection.
@ -468,23 +465,23 @@ in
'';
};
extraAliases = mkOption {
type = types.lines;
extraAliases = lib.mkOption {
type = lib.types.lines;
default = "";
description = ''
Additional entries to put verbatim into aliases file, cf. man-page aliases(8).
'';
};
aliasMapType = mkOption {
type = with types; enum [ "hash" "regexp" "pcre" ];
aliasMapType = lib.mkOption {
type = with lib.types; enum [ "hash" "regexp" "pcre" ];
default = "hash";
example = "regexp";
description = "The format the alias map should have. Use regexp if you want to use regular expressions.";
};
config = mkOption {
type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
config = lib.mkOption {
type = with lib.types; attrsOf (oneOf [ bool int str (listOf str) ]);
description = ''
The main.cf configuration file as key value set.
'';
@ -494,37 +491,37 @@ in
};
};
extraConfig = mkOption {
type = types.lines;
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
description = ''
Extra lines to be added verbatim to the main.cf configuration file.
'';
};
tlsTrustedAuthorities = mkOption {
type = types.str;
tlsTrustedAuthorities = lib.mkOption {
type = lib.types.str;
default = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
defaultText = literalExpression ''"''${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"'';
defaultText = lib.literalExpression ''"''${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"'';
description = ''
File containing trusted certification authorities (CA) to verify certificates of mailservers contacted for mail delivery. This basically sets smtp_tls_CAfile and enables opportunistic tls. Defaults to NixOS trusted certification authorities.
'';
};
sslCert = mkOption {
type = types.str;
sslCert = lib.mkOption {
type = lib.types.str;
default = "";
description = "SSL certificate to use.";
};
sslKey = mkOption {
type = types.str;
sslKey = lib.mkOption {
type = lib.types.str;
default = "";
description = "SSL key to use.";
};
recipientDelimiter = mkOption {
type = types.str;
recipientDelimiter = lib.mkOption {
type = lib.types.str;
default = "";
example = "+";
description = ''
@ -532,32 +529,32 @@ in
'';
};
canonical = mkOption {
type = types.lines;
canonical = lib.mkOption {
type = lib.types.lines;
default = "";
description = ''
Entries for the {manpage}`canonical(5)` table.
'';
};
virtual = mkOption {
type = types.lines;
virtual = lib.mkOption {
type = lib.types.lines;
default = "";
description = ''
Entries for the virtual alias map, cf. man-page virtual(5).
'';
};
virtualMapType = mkOption {
type = types.enum ["hash" "regexp" "pcre"];
virtualMapType = lib.mkOption {
type = lib.types.enum ["hash" "regexp" "pcre"];
default = "hash";
description = ''
What type of virtual alias map file to use. Use `"regexp"` for regular expressions.
'';
};
localRecipients = mkOption {
type = with types; nullOr (listOf str);
localRecipients = lib.mkOption {
type = with lib.types; nullOr (listOf str);
default = null;
description = ''
List of accepted local users. Specify a bare username, an
@ -569,28 +566,28 @@ in
'';
};
transport = mkOption {
transport = lib.mkOption {
default = "";
type = types.lines;
type = lib.types.lines;
description = ''
Entries for the transport map, cf. man-page transport(8).
'';
};
dnsBlacklists = mkOption {
dnsBlacklists = lib.mkOption {
default = [];
type = with types; listOf str;
type = with lib.types; listOf str;
description = "dns blacklist servers to use with smtpd_client_restrictions";
};
dnsBlacklistOverrides = mkOption {
dnsBlacklistOverrides = lib.mkOption {
default = "";
type = types.lines;
type = lib.types.lines;
description = "contents of check_client_access for overriding dnsBlacklists";
};
masterConfig = mkOption {
type = types.attrsOf (types.submodule masterCfOptions);
masterConfig = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule masterCfOptions);
default = {};
example =
{ submission = {
@ -605,48 +602,48 @@ in
'';
};
extraMasterConf = mkOption {
type = types.lines;
extraMasterConf = lib.mkOption {
type = lib.types.lines;
default = "";
example = "submission inet n - n - - smtpd";
description = "Extra lines to append to the generated master.cf file.";
};
enableHeaderChecks = mkOption {
type = types.bool;
enableHeaderChecks = lib.mkOption {
type = lib.types.bool;
default = false;
example = true;
description = "Whether to enable postfix header checks";
};
headerChecks = mkOption {
type = types.listOf (types.submodule headerCheckOptions);
headerChecks = lib.mkOption {
type = lib.types.listOf (lib.types.submodule headerCheckOptions);
default = [];
example = [ { pattern = "/^X-Spam-Flag:/"; action = "REDIRECT spam@example.com"; } ];
description = "Postfix header checks.";
};
extraHeaderChecks = mkOption {
type = types.lines;
extraHeaderChecks = lib.mkOption {
type = lib.types.lines;
default = "";
example = "/^X-Spam-Flag:/ REDIRECT spam@example.com";
description = "Extra lines to /etc/postfix/header_checks file.";
};
aliasFiles = mkOption {
type = types.attrsOf types.path;
aliasFiles = lib.mkOption {
type = lib.types.attrsOf lib.types.path;
default = {};
description = "Aliases' tables to be compiled and placed into /var/lib/postfix/conf.";
};
mapFiles = mkOption {
type = types.attrsOf types.path;
mapFiles = lib.mkOption {
type = lib.types.attrsOf lib.types.path;
default = {};
description = "Maps to be compiled and placed into /var/lib/postfix/conf.";
};
useSrs = mkOption {
type = types.bool;
useSrs = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to enable sender rewriting scheme";
};
@ -658,7 +655,7 @@ in
###### implementation
config = mkIf config.services.postfix.enable (mkMerge [
config = lib.mkIf config.services.postfix.enable (lib.mkMerge [
{
environment = {
@ -670,7 +667,7 @@ in
services.pfix-srsd.enable = config.services.postfix.useSrs;
services.mail.sendmailSetuidWrapper = mkIf config.services.postfix.setSendmail {
services.mail.sendmailSetuidWrapper = lib.mkIf config.services.postfix.setSendmail {
program = "sendmail";
source = "${pkgs.postfix}/bin/sendmail";
owner = "root";
@ -706,7 +703,7 @@ in
setgid = true;
};
users.users = optionalAttrs (user == "postfix")
users.users = lib.optionalAttrs (user == "postfix")
{ postfix = {
description = "Postfix mail server user";
uid = config.ids.uids.postfix;
@ -715,10 +712,10 @@ in
};
users.groups =
optionalAttrs (group == "postfix")
lib.optionalAttrs (group == "postfix")
{ ${group}.gid = config.ids.gids.postfix;
}
// optionalAttrs (setgidGroup == "postdrop")
// lib.optionalAttrs (setgidGroup == "postdrop")
{ ${setgidGroup}.gid = config.ids.gids.postdrop;
};
@ -745,11 +742,11 @@ in
ln -sf ${mainCfFile} /var/lib/postfix/conf/main.cf
ln -sf ${masterCfFile} /var/lib/postfix/conf/master.cf
${concatStringsSep "\n" (mapAttrsToList (to: from: ''
${lib.concatStringsSep "\n" (lib.mapAttrsToList (to: from: ''
ln -sf ${from} /var/lib/postfix/conf/${to}
${pkgs.postfix}/bin/postalias -o -p /var/lib/postfix/conf/${to}
'') cfg.aliasFiles)}
${concatStringsSep "\n" (mapAttrsToList (to: from: ''
${lib.concatStringsSep "\n" (lib.mapAttrsToList (to: from: ''
ln -sf ${from} /var/lib/postfix/conf/${to}
${pkgs.postfix}/bin/postmap /var/lib/postfix/conf/${to}
'') cfg.mapFiles)}
@ -795,7 +792,7 @@ in
};
};
services.postfix.config = (mapAttrs (_: v: mkDefault v) {
services.postfix.config = (lib.mapAttrs (_: v: lib.mkDefault v) {
compatibility_level = pkgs.postfix.version;
mail_owner = cfg.user;
default_privs = "nobody";
@ -819,39 +816,39 @@ in
mail_spool_directory = "/var/spool/mail/";
setgid_group = cfg.setgidGroup;
})
// optionalAttrs (cfg.relayHost != "") { relayhost = if cfg.lookupMX
// lib.optionalAttrs (cfg.relayHost != "") { relayhost = if cfg.lookupMX
then "${cfg.relayHost}:${toString cfg.relayPort}"
else "[${cfg.relayHost}]:${toString cfg.relayPort}"; }
// optionalAttrs (!config.networking.enableIPv6) { inet_protocols = mkDefault "ipv4"; }
// optionalAttrs (cfg.networks != null) { mynetworks = cfg.networks; }
// optionalAttrs (cfg.networksStyle != "") { mynetworks_style = cfg.networksStyle; }
// optionalAttrs (cfg.hostname != "") { myhostname = cfg.hostname; }
// optionalAttrs (cfg.domain != "") { mydomain = cfg.domain; }
// optionalAttrs (cfg.origin != "") { myorigin = cfg.origin; }
// optionalAttrs (cfg.destination != null) { mydestination = cfg.destination; }
// optionalAttrs (cfg.relayDomains != null) { relay_domains = cfg.relayDomains; }
// optionalAttrs (cfg.recipientDelimiter != "") { recipient_delimiter = cfg.recipientDelimiter; }
// optionalAttrs haveAliases { alias_maps = [ "${cfg.aliasMapType}:/etc/postfix/aliases" ]; }
// optionalAttrs haveTransport { transport_maps = [ "hash:/etc/postfix/transport" ]; }
// optionalAttrs haveVirtual { virtual_alias_maps = [ "${cfg.virtualMapType}:/etc/postfix/virtual" ]; }
// optionalAttrs haveLocalRecipients { local_recipient_maps = [ "hash:/etc/postfix/local_recipients" ] ++ optional haveAliases "$alias_maps"; }
// optionalAttrs (cfg.dnsBlacklists != []) { smtpd_client_restrictions = clientRestrictions; }
// optionalAttrs cfg.useSrs {
// lib.optionalAttrs (!config.networking.enableIPv6) { inet_protocols = lib.mkDefault "ipv4"; }
// lib.optionalAttrs (cfg.networks != null) { mynetworks = cfg.networks; }
// lib.optionalAttrs (cfg.networksStyle != "") { mynetworks_style = cfg.networksStyle; }
// lib.optionalAttrs (cfg.hostname != "") { myhostname = cfg.hostname; }
// lib.optionalAttrs (cfg.domain != "") { mydomain = cfg.domain; }
// lib.optionalAttrs (cfg.origin != "") { myorigin = cfg.origin; }
// lib.optionalAttrs (cfg.destination != null) { mydestination = cfg.destination; }
// lib.optionalAttrs (cfg.relayDomains != null) { relay_domains = cfg.relayDomains; }
// lib.optionalAttrs (cfg.recipientDelimiter != "") { recipient_delimiter = cfg.recipientDelimiter; }
// lib.optionalAttrs haveAliases { alias_maps = [ "${cfg.aliasMapType}:/etc/postfix/aliases" ]; }
// lib.optionalAttrs haveTransport { transport_maps = [ "hash:/etc/postfix/transport" ]; }
// lib.optionalAttrs haveVirtual { virtual_alias_maps = [ "${cfg.virtualMapType}:/etc/postfix/virtual" ]; }
// lib.optionalAttrs haveLocalRecipients { local_recipient_maps = [ "hash:/etc/postfix/local_recipients" ] ++ lib.optional haveAliases "$alias_maps"; }
// lib.optionalAttrs (cfg.dnsBlacklists != []) { smtpd_client_restrictions = clientRestrictions; }
// lib.optionalAttrs cfg.useSrs {
sender_canonical_maps = [ "tcp:127.0.0.1:10001" ];
sender_canonical_classes = [ "envelope_sender" ];
recipient_canonical_maps = [ "tcp:127.0.0.1:10002" ];
recipient_canonical_classes = [ "envelope_recipient" ];
}
// optionalAttrs cfg.enableHeaderChecks { header_checks = [ "regexp:/etc/postfix/header_checks" ]; }
// optionalAttrs (cfg.tlsTrustedAuthorities != "") {
// lib.optionalAttrs cfg.enableHeaderChecks { header_checks = [ "regexp:/etc/postfix/header_checks" ]; }
// lib.optionalAttrs (cfg.tlsTrustedAuthorities != "") {
smtp_tls_CAfile = cfg.tlsTrustedAuthorities;
smtp_tls_security_level = mkDefault "may";
smtp_tls_security_level = lib.mkDefault "may";
}
// optionalAttrs (cfg.sslCert != "") {
// lib.optionalAttrs (cfg.sslCert != "") {
smtp_tls_cert_file = cfg.sslCert;
smtp_tls_key_file = cfg.sslKey;
smtp_tls_security_level = mkDefault "may";
smtp_tls_security_level = lib.mkDefault "may";
smtpd_tls_cert_file = cfg.sslCert;
smtpd_tls_key_file = cfg.sslKey;
@ -931,16 +928,16 @@ in
scache = {
maxproc = 1;
};
} // optionalAttrs cfg.enableSubmission {
} // lib.optionalAttrs cfg.enableSubmission {
submission = {
type = "inet";
private = false;
command = "smtpd";
args = let
mkKeyVal = opt: val: [ "-o" (opt + "=" + val) ];
in concatLists (mapAttrsToList mkKeyVal cfg.submissionOptions);
in lib.concatLists (lib.mapAttrsToList mkKeyVal cfg.submissionOptions);
};
} // optionalAttrs cfg.enableSmtp {
} // lib.optionalAttrs cfg.enableSmtp {
smtp_inet = {
name = "smtp";
type = "inet";
@ -952,7 +949,7 @@ in
command = "smtp";
args = [ "-o" "smtp_fallback_relay=" ];
};
} // optionalAttrs cfg.enableSubmissions {
} // lib.optionalAttrs cfg.enableSubmissions {
submissions = {
type = "inet";
private = false;
@ -964,43 +961,43 @@ in
cfg.submissionsOptions.smtpd_tls_security_level == "may";
submissionsOptions = cfg.submissionsOptions // {
smtpd_tls_wrappermode = "yes";
} // optionalAttrs adjustSmtpTlsSecurityLevel {
} // lib.optionalAttrs adjustSmtpTlsSecurityLevel {
smtpd_tls_security_level = "encrypt";
};
in concatLists (mapAttrsToList mkKeyVal submissionsOptions);
in lib.concatLists (lib.mapAttrsToList mkKeyVal submissionsOptions);
};
};
}
(mkIf haveAliases {
(lib.mkIf haveAliases {
services.postfix.aliasFiles.aliases = aliasesFile;
})
(mkIf haveCanonical {
(lib.mkIf haveCanonical {
services.postfix.mapFiles.canonical = canonicalFile;
})
(mkIf haveTransport {
(lib.mkIf haveTransport {
services.postfix.mapFiles.transport = transportFile;
})
(mkIf haveVirtual {
(lib.mkIf haveVirtual {
services.postfix.mapFiles.virtual = virtualFile;
})
(mkIf haveLocalRecipients {
(lib.mkIf haveLocalRecipients {
services.postfix.mapFiles.local_recipients = localRecipientMapFile;
})
(mkIf cfg.enableHeaderChecks {
(lib.mkIf cfg.enableHeaderChecks {
services.postfix.mapFiles.header_checks = headerChecksFile;
})
(mkIf (cfg.dnsBlacklists != []) {
(lib.mkIf (cfg.dnsBlacklists != []) {
services.postfix.mapFiles.client_access = checkClientAccessFile;
})
]);
imports = [
(mkRemovedOptionModule [ "services" "postfix" "sslCACert" ]
(lib.mkRemovedOptionModule [ "services" "postfix" "sslCACert" ]
"services.postfix.sslCACert was replaced by services.postfix.tlsTrustedAuthorities. In case you intend that your server should validate requested client certificates use services.postfix.extraConfig.")
(mkChangedOptionModule [ "services" "postfix" "useDane" ]
(lib.mkChangedOptionModule [ "services" "postfix" "useDane" ]
[ "services" "postfix" "config" "smtp_tls_security_level" ]
(config: mkIf config.services.postfix.useDane "dane"))
(config: lib.mkIf config.services.postfix.useDane "dane"))
];
}

View File

@ -1,14 +1,11 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.sympa;
dataDir = "/var/lib/sympa";
user = "sympa";
group = "sympa";
pkg = pkgs.sympa;
fqdns = attrNames cfg.domains;
fqdns = lib.attrNames cfg.domains;
usingNginx = cfg.web.enable && cfg.web.server == "nginx";
mysqlLocal = cfg.database.createLocally && cfg.database.type == "MySQL";
pgsqlLocal = cfg.database.createLocally && cfg.database.type == "PostgreSQL";
@ -42,15 +39,15 @@ let
} // commonServiceConfig;
configVal = value:
if isBool value then
if lib.isBool value then
if value then "on" else "off"
else toString value;
configGenerator = c: concatStrings (flip mapAttrsToList c (key: val: "${key}\t${configVal val}\n"));
configGenerator = c: lib.concatStrings (lib.flip lib.mapAttrsToList c (key: val: "${key}\t${configVal val}\n"));
mainConfig = pkgs.writeText "sympa.conf" (configGenerator cfg.settings);
robotConfig = fqdn: domain: pkgs.writeText "${fqdn}-robot.conf" (configGenerator domain.settings);
transport = pkgs.writeText "transport.sympa" (concatStringsSep "\n" (flip map fqdns (domain: ''
transport = pkgs.writeText "transport.sympa" (lib.concatStringsSep "\n" (lib.flip map fqdns (domain: ''
${domain} error:User unknown in recipient table
sympa@${domain} sympa:sympa@${domain}
listmaster@${domain} sympa:listmaster@${domain}
@ -58,7 +55,7 @@ let
abuse-feedback-report@${domain} sympabounce:sympa@${domain}
'')));
virtual = pkgs.writeText "virtual.sympa" (concatStringsSep "\n" (flip map fqdns (domain: ''
virtual = pkgs.writeText "virtual.sympa" (lib.concatStringsSep "\n" (lib.flip map fqdns (domain: ''
sympa-request@${domain} postmaster@localhost
sympa-owner@${domain} postmaster@localhost
'')));
@ -73,16 +70,16 @@ let
[% list.name %][% return_path_suffix %]@[% list.domain %] sympabounce:[% list.name %]@[% list.domain %]
'';
enabledFiles = filterAttrs (n: v: v.enable) cfg.settingsFile;
enabledFiles = lib.filterAttrs (n: v: v.enable) cfg.settingsFile;
in
{
###### interface
options.services.sympa = with types; {
options.services.sympa = with lib.types; {
enable = mkEnableOption "Sympa mailing list manager";
enable = lib.mkEnableOption "Sympa mailing list manager";
lang = mkOption {
lang = lib.mkOption {
type = str;
default = "en_US";
example = "cs";
@ -93,7 +90,7 @@ in
'';
};
listMasters = mkOption {
listMasters = lib.mkOption {
type = listOf str;
example = [ "postmaster@sympa.example.org" ];
description = ''
@ -102,7 +99,7 @@ in
'';
};
mainDomain = mkOption {
mainDomain = lib.mkOption {
type = nullOr str;
default = null;
example = "lists.example.org";
@ -112,10 +109,10 @@ in
'';
};
domains = mkOption {
domains = lib.mkOption {
type = attrsOf (submodule ({ name, config, ... }: {
options = {
webHost = mkOption {
webHost = lib.mkOption {
type = nullOr str;
default = null;
example = "archive.example.org";
@ -124,13 +121,13 @@ in
DNS record of type A (or AAAA or CNAME) has to exist with this value.
'';
};
webLocation = mkOption {
webLocation = lib.mkOption {
type = str;
default = "/";
example = "/sympa";
description = "URL path part of the web interface.";
};
settings = mkOption {
settings = lib.mkOption {
type = attrsOf (oneOf [ str int bool ]);
default = {};
example = {
@ -144,8 +141,8 @@ in
};
};
config.settings = mkIf (cfg.web.enable && config.webHost != null) {
wwsympa_url = mkDefault "https://${config.webHost}${strings.removeSuffix "/" config.webLocation}";
config.settings = lib.mkIf (cfg.web.enable && config.webHost != null) {
wwsympa_url = lib.mkDefault "https://${config.webHost}${lib.removeSuffix "/" config.webLocation}";
};
}));
@ -153,7 +150,7 @@ in
Email domains handled by this instance. There have
to be MX records for keys of this attribute set.
'';
example = literalExpression ''
example = lib.literalExpression ''
{
"lists.example.org" = {
webHost = "lists.example.org";
@ -168,14 +165,14 @@ in
};
database = {
type = mkOption {
type = lib.mkOption {
type = enum [ "SQLite" "PostgreSQL" "MySQL" ];
default = "SQLite";
example = "MySQL";
description = "Database engine to use.";
};
host = mkOption {
host = lib.mkOption {
type = nullOr str;
default = null;
description = ''
@ -191,29 +188,29 @@ in
'';
};
port = mkOption {
port = lib.mkOption {
type = nullOr port;
default = null;
description = "Database port. Use `null` for default port.";
};
name = mkOption {
name = lib.mkOption {
type = str;
default = if cfg.database.type == "SQLite" then "${dataDir}/sympa.sqlite" else "sympa";
defaultText = literalExpression ''if database.type == "SQLite" then "${dataDir}/sympa.sqlite" else "sympa"'';
defaultText = lib.literalExpression ''if database.type == "SQLite" then "${dataDir}/sympa.sqlite" else "sympa"'';
description = ''
Database name. When using SQLite this must be an absolute
path to the database file.
'';
};
user = mkOption {
user = lib.mkOption {
type = nullOr str;
default = user;
description = "Database user. The system user name is used as a default.";
};
passwordFile = mkOption {
passwordFile = lib.mkOption {
type = nullOr path;
default = null;
example = "/run/keys/sympa-dbpassword";
@ -222,7 +219,7 @@ in
'';
};
createLocally = mkOption {
createLocally = lib.mkOption {
type = bool;
default = true;
description = "Whether to create a local database automatically.";
@ -230,13 +227,13 @@ in
};
web = {
enable = mkOption {
enable = lib.mkOption {
type = bool;
default = true;
description = "Whether to enable Sympa web interface.";
};
server = mkOption {
server = lib.mkOption {
type = enum [ "nginx" "none" ];
default = "nginx";
description = ''
@ -246,7 +243,7 @@ in
'';
};
https = mkOption {
https = lib.mkOption {
type = bool;
default = true;
description = ''
@ -255,7 +252,7 @@ in
'';
};
fcgiProcs = mkOption {
fcgiProcs = lib.mkOption {
type = ints.positive;
default = 2;
description = "Number of FastCGI processes to fork.";
@ -263,7 +260,7 @@ in
};
mta = {
type = mkOption {
type = lib.mkOption {
type = enum [ "postfix" "none" ];
default = "postfix";
description = ''
@ -276,10 +273,10 @@ in
};
};
settings = mkOption {
settings = lib.mkOption {
type = attrsOf (oneOf [ str int bool ]);
default = {};
example = literalExpression ''
example = lib.literalExpression ''
{
default_home = "lists";
viewlogs_page_size = 50;
@ -292,29 +289,29 @@ in
'';
};
settingsFile = mkOption {
settingsFile = lib.mkOption {
type = attrsOf (submodule ({ name, config, ... }: {
options = {
enable = mkOption {
enable = lib.mkOption {
type = bool;
default = true;
description = "Whether this file should be generated. This option allows specific files to be disabled.";
};
text = mkOption {
text = lib.mkOption {
default = null;
type = nullOr lines;
description = "Text of the file.";
};
source = mkOption {
source = lib.mkOption {
type = path;
description = "Path of the source file.";
};
};
config.source = mkIf (config.text != null) (mkDefault (pkgs.writeText "sympa-${baseNameOf name}" config.text));
config.source = lib.mkIf (config.text != null) (lib.mkDefault (pkgs.writeText "sympa-${baseNameOf name}" config.text));
}));
default = {};
example = literalExpression ''
example = lib.literalExpression ''
{
"list_data/lists.example.org/help" = {
text = "subject This list provides help to users";
@ -327,11 +324,11 @@ in
###### implementation
config = mkIf cfg.enable {
config = lib.mkIf cfg.enable {
services.sympa.settings = (mapAttrs (_: v: mkDefault v) {
domain = if cfg.mainDomain != null then cfg.mainDomain else head fqdns;
listmaster = concatStringsSep "," cfg.listMasters;
services.sympa.settings = (lib.mapAttrs (_: v: lib.mkDefault v) {
domain = if cfg.mainDomain != null then cfg.mainDomain else lib.head fqdns;
listmaster = lib.concatStringsSep "," cfg.listMasters;
lang = cfg.lang;
home = "${dataDir}/list_data";
@ -344,24 +341,24 @@ in
db_name = cfg.database.name;
db_user = cfg.database.name;
}
// (optionalAttrs (cfg.database.host != null) {
// (lib.optionalAttrs (cfg.database.host != null) {
db_host = cfg.database.host;
})
// (optionalAttrs mysqlLocal {
// (lib.optionalAttrs mysqlLocal {
db_host = "localhost"; # use unix domain socket
})
// (optionalAttrs pgsqlLocal {
// (lib.optionalAttrs pgsqlLocal {
db_host = "/run/postgresql"; # use unix domain socket
})
// (optionalAttrs (cfg.database.port != null) {
// (lib.optionalAttrs (cfg.database.port != null) {
db_port = cfg.database.port;
})
// (optionalAttrs (cfg.mta.type == "postfix") {
// (lib.optionalAttrs (cfg.mta.type == "postfix") {
sendmail_aliases = "${dataDir}/sympa_transport";
aliases_program = "${pkgs.postfix}/bin/postmap";
aliases_db_type = "hash";
})
// (optionalAttrs cfg.web.enable {
// (lib.optionalAttrs cfg.web.enable {
static_content_path = "${dataDir}/static_content";
css_path = "${dataDir}/static_content/css";
pictures_path = "${dataDir}/static_content/pictures";
@ -369,12 +366,12 @@ in
}));
services.sympa.settingsFile = {
"virtual.sympa" = mkDefault { source = virtual; };
"transport.sympa" = mkDefault { source = transport; };
"etc/list_aliases.tt2" = mkDefault { source = listAliases; };
"virtual.sympa" = lib.mkDefault { source = virtual; };
"transport.sympa" = lib.mkDefault { source = transport; };
"etc/list_aliases.tt2" = lib.mkDefault { source = listAliases; };
}
// (flip mapAttrs' cfg.domains (fqdn: domain:
nameValuePair "etc/${fqdn}/robot.conf" (mkDefault { source = robotConfig fqdn domain; })));
// (lib.flip lib.mapAttrs' cfg.domains (fqdn: domain:
lib.nameValuePair "etc/${fqdn}/robot.conf" (lib.mkDefault { source = robotConfig fqdn domain; })));
environment = {
systemPackages = [ pkg ];
@ -416,14 +413,14 @@ in
"d /run/sympa 0755 ${user} ${group} - -"
]
++ (flip concatMap fqdns (fqdn: [
++ (lib.flip lib.concatMap fqdns (fqdn: [
"d ${dataDir}/etc/${fqdn} 0700 ${user} ${group} - -"
"d ${dataDir}/list_data/${fqdn} 0700 ${user} ${group} - -"
]))
#++ (flip mapAttrsToList enabledFiles (k: v:
#++ (lib.flip lib.mapAttrsToList enabledFiles (k: v:
# "L+ ${dataDir}/${k} - - - - ${v.source}"
#))
++ (concatLists (flip mapAttrsToList enabledFiles (k: v: [
++ (lib.concatLists (lib.flip lib.mapAttrsToList enabledFiles (k: v: [
# sympa doesn't handle symlinks well (e.g. fails to create locks)
# force-copy instead
"R ${dataDir}/${k} - - - - -"
@ -443,13 +440,13 @@ in
umask 0077
cp -f ${mainConfig} ${dataDir}/etc/sympa.conf
${optionalString (cfg.database.passwordFile != null) ''
${lib.optionalString (cfg.database.passwordFile != null) ''
chmod u+w ${dataDir}/etc/sympa.conf
echo -n "db_passwd " >> ${dataDir}/etc/sympa.conf
cat ${cfg.database.passwordFile} >> ${dataDir}/etc/sympa.conf
''}
${optionalString (cfg.mta.type == "postfix") ''
${lib.optionalString (cfg.mta.type == "postfix") ''
${pkgs.postfix}/bin/postmap hash:${dataDir}/virtual.sympa
${pkgs.postfix}/bin/postmap hash:${dataDir}/transport.sympa
''}
@ -478,7 +475,7 @@ in
serviceConfig = sympaServiceConfig "task_manager";
};
systemd.services.wwsympa = mkIf usingNginx {
systemd.services.wwsympa = lib.mkIf usingNginx {
wantedBy = [ "multi-user.target" ];
after = [ "sympa.service" ];
serviceConfig = {
@ -499,14 +496,14 @@ in
} // commonServiceConfig;
};
services.nginx.enable = mkIf usingNginx true;
services.nginx.virtualHosts = mkIf usingNginx (let
vHosts = unique (remove null (mapAttrsToList (_k: v: v.webHost) cfg.domains));
hostLocations = host: map (v: v.webLocation) (filter (v: v.webHost == host) (attrValues cfg.domains));
httpsOpts = optionalAttrs cfg.web.https { forceSSL = mkDefault true; enableACME = mkDefault true; };
services.nginx.enable = lib.mkIf usingNginx true;
services.nginx.virtualHosts = lib.mkIf usingNginx (let
vHosts = lib.unique (lib.remove null (lib.mapAttrsToList (_k: v: v.webHost) cfg.domains));
hostLocations = host: map (v: v.webLocation) (lib.filter (v: v.webHost == host) (lib.attrValues cfg.domains));
httpsOpts = lib.optionalAttrs cfg.web.https { forceSSL = lib.mkDefault true; enableACME = lib.mkDefault true; };
in
genAttrs vHosts (host: {
locations = genAttrs (hostLocations host) (loc: {
lib.genAttrs vHosts (host: {
locations = lib.genAttrs (hostLocations host) (loc: {
extraConfig = ''
include ${config.services.nginx.package}/conf/fastcgi_params;
@ -517,7 +514,7 @@ in
};
} // httpsOpts));
services.postfix = mkIf (cfg.mta.type == "postfix") {
services.postfix = lib.mkIf (cfg.mta.type == "postfix") {
enable = true;
recipientDelimiter = "+";
config = {
@ -561,9 +558,9 @@ in
};
};
services.mysql = optionalAttrs mysqlLocal {
services.mysql = lib.optionalAttrs mysqlLocal {
enable = true;
package = mkDefault pkgs.mariadb;
package = lib.mkDefault pkgs.mariadb;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [
{ name = cfg.database.user;
@ -572,7 +569,7 @@ in
];
};
services.postgresql = optionalAttrs pgsqlLocal {
services.postgresql = lib.optionalAttrs pgsqlLocal {
enable = true;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [
@ -584,5 +581,5 @@ in
};
meta.maintainers = with maintainers; [ mmilata sorki ];
meta.maintainers = with lib.maintainers; [ mmilata sorki ];
}

View File

@ -1,32 +1,29 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.autorandr;
hookType = types.lines;
hookType = lib.types.lines;
matrixOf = n: m: elemType:
mkOptionType rec {
lib.mkOptionType rec {
name = "matrixOf";
description =
"${toString n}×${toString m} matrix of ${elemType.description}s";
check = xss:
let listOfSize = l: xs: isList xs && length xs == l;
let listOfSize = l: xs: lib.isList xs && lib.length xs == l;
in listOfSize n xss
&& all (xs: listOfSize m xs && all elemType.check xs) xss;
merge = mergeOneOption;
&& lib.all (xs: listOfSize m xs && lib.all elemType.check xs) xss;
merge = lib.mergeOneOption;
getSubOptions = prefix: elemType.getSubOptions (prefix ++ [ "*" "*" ]);
getSubModules = elemType.getSubModules;
substSubModules = mod: matrixOf n m (elemType.substSubModules mod);
functor = (defaultFunctor name) // { wrapped = elemType; };
functor = (lib.defaultFunctor name) // { wrapped = elemType; };
};
profileModule = types.submodule {
profileModule = lib.types.submodule {
options = {
fingerprint = mkOption {
type = types.attrsOf types.str;
fingerprint = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
description = ''
Output name to EDID mapping.
Use `autorandr --fingerprint` to get current setup values.
@ -34,13 +31,13 @@ let
default = { };
};
config = mkOption {
type = types.attrsOf configModule;
config = lib.mkOption {
type = lib.types.attrsOf configModule;
description = "Per output profile configuration.";
default = { };
};
hooks = mkOption {
hooks = lib.mkOption {
type = hooksModule;
description = "Profile hook scripts.";
default = { };
@ -48,66 +45,66 @@ let
};
};
configModule = types.submodule {
configModule = lib.types.submodule {
options = {
enable = mkOption {
type = types.bool;
enable = lib.mkOption {
type = lib.types.bool;
description = "Whether to enable the output.";
default = true;
};
crtc = mkOption {
type = types.nullOr types.ints.unsigned;
crtc = lib.mkOption {
type = lib.types.nullOr lib.types.ints.unsigned;
description = "Output video display controller.";
default = null;
example = 0;
};
primary = mkOption {
type = types.bool;
primary = lib.mkOption {
type = lib.types.bool;
description = "Whether output should be marked as primary";
default = false;
};
position = mkOption {
type = types.str;
position = lib.mkOption {
type = lib.types.str;
description = "Output position";
default = "";
example = "5760x0";
};
mode = mkOption {
type = types.str;
mode = lib.mkOption {
type = lib.types.str;
description = "Output resolution.";
default = "";
example = "3840x2160";
};
rate = mkOption {
type = types.str;
rate = lib.mkOption {
type = lib.types.str;
description = "Output framerate.";
default = "";
example = "60.00";
};
gamma = mkOption {
type = types.str;
gamma = lib.mkOption {
type = lib.types.str;
description = "Output gamma configuration.";
default = "";
example = "1.0:0.909:0.833";
};
rotate = mkOption {
type = types.nullOr (types.enum [ "normal" "left" "right" "inverted" ]);
rotate = lib.mkOption {
type = lib.types.nullOr (lib.types.enum [ "normal" "left" "right" "inverted" ]);
description = "Output rotate configuration.";
default = null;
example = "left";
};
transform = mkOption {
type = types.nullOr (matrixOf 3 3 types.float);
transform = lib.mkOption {
type = lib.types.nullOr (matrixOf 3 3 lib.types.float);
default = null;
example = literalExpression ''
example = lib.literalExpression ''
[
[ 0.6 0.0 0.0 ]
[ 0.0 0.6 0.0 ]
@ -121,30 +118,30 @@ let
'';
};
dpi = mkOption {
type = types.nullOr types.ints.positive;
dpi = lib.mkOption {
type = lib.types.nullOr lib.types.ints.positive;
description = "Output DPI configuration.";
default = null;
example = 96;
};
scale = mkOption {
type = types.nullOr (types.submodule {
scale = lib.mkOption {
type = lib.types.nullOr (lib.types.submodule {
options = {
method = mkOption {
type = types.enum [ "factor" "pixel" ];
method = lib.mkOption {
type = lib.types.enum [ "factor" "pixel" ];
description = "Output scaling method.";
default = "factor";
example = "pixel";
};
x = mkOption {
type = types.either types.float types.ints.positive;
x = lib.mkOption {
type = lib.types.either lib.types.float lib.types.ints.positive;
description = "Horizontal scaling factor/pixels.";
};
y = mkOption {
type = types.either types.float types.ints.positive;
y = lib.mkOption {
type = lib.types.either lib.types.float lib.types.ints.positive;
description = "Vertical scaling factor/pixels.";
};
};
@ -164,7 +161,7 @@ let
exclusive.
'';
default = null;
example = literalExpression ''
example = lib.literalExpression ''
{
x = 1.25;
y = 1.25;
@ -174,22 +171,22 @@ let
};
};
hooksModule = types.submodule {
hooksModule = lib.types.submodule {
options = {
postswitch = mkOption {
type = types.attrsOf hookType;
postswitch = lib.mkOption {
type = lib.types.attrsOf hookType;
description = "Postswitch hook executed after mode switch.";
default = { };
};
preswitch = mkOption {
type = types.attrsOf hookType;
preswitch = lib.mkOption {
type = lib.types.attrsOf hookType;
description = "Preswitch hook executed before mode switch.";
default = { };
};
predetect = mkOption {
type = types.attrsOf hookType;
predetect = lib.mkOption {
type = lib.types.attrsOf hookType;
description = ''
Predetect hook executed before autorandr attempts to run xrandr.
'';
@ -199,37 +196,37 @@ let
};
hookToFile = folder: name: hook:
nameValuePair "xdg/autorandr/${folder}/${name}" {
lib.nameValuePair "xdg/autorandr/${folder}/${name}" {
source = "${pkgs.writeShellScriptBin "hook" hook}/bin/hook";
};
profileToFiles = name: profile:
with profile;
mkMerge ([
lib.mkMerge ([
{
"xdg/autorandr/${name}/setup".text = concatStringsSep "\n"
(mapAttrsToList fingerprintToString fingerprint);
"xdg/autorandr/${name}/setup".text = lib.concatStringsSep "\n"
(lib.mapAttrsToList fingerprintToString fingerprint);
"xdg/autorandr/${name}/config".text =
concatStringsSep "\n" (mapAttrsToList configToString profile.config);
lib.concatStringsSep "\n" (lib.mapAttrsToList configToString profile.config);
}
(mapAttrs' (hookToFile "${name}/postswitch.d") hooks.postswitch)
(mapAttrs' (hookToFile "${name}/preswitch.d") hooks.preswitch)
(mapAttrs' (hookToFile "${name}/predetect.d") hooks.predetect)
(lib.mapAttrs' (hookToFile "${name}/postswitch.d") hooks.postswitch)
(lib.mapAttrs' (hookToFile "${name}/preswitch.d") hooks.preswitch)
(lib.mapAttrs' (hookToFile "${name}/predetect.d") hooks.predetect)
]);
fingerprintToString = name: edid: "${name} ${edid}";
configToString = name: config:
if config.enable then
concatStringsSep "\n" ([ "output ${name}" ]
++ optional (config.position != "") "pos ${config.position}"
++ optional (config.crtc != null) "crtc ${toString config.crtc}"
++ optional config.primary "primary"
++ optional (config.dpi != null) "dpi ${toString config.dpi}"
++ optional (config.gamma != "") "gamma ${config.gamma}"
++ optional (config.mode != "") "mode ${config.mode}"
++ optional (config.rate != "") "rate ${config.rate}"
++ optional (config.rotate != null) "rotate ${config.rotate}"
++ optional (config.transform != null) ("transform "
+ concatMapStringsSep "," toString (flatten config.transform))
++ optional (config.scale != null)
lib.concatStringsSep "\n" ([ "output ${name}" ]
++ lib.optional (config.position != "") "pos ${config.position}"
++ lib.optional (config.crtc != null) "crtc ${toString config.crtc}"
++ lib.optional config.primary "primary"
++ lib.optional (config.dpi != null) "dpi ${toString config.dpi}"
++ lib.optional (config.gamma != "") "gamma ${config.gamma}"
++ lib.optional (config.mode != "") "mode ${config.mode}"
++ lib.optional (config.rate != "") "rate ${config.rate}"
++ lib.optional (config.rotate != null) "rotate ${config.rotate}"
++ lib.optional (config.transform != null) ("transform "
+ lib.concatMapStringsSep "," toString (lib.flatten config.transform))
++ lib.optional (config.scale != null)
((if config.scale.method == "factor" then "scale" else "scale-from")
+ " ${toString config.scale.x}x${toString config.scale.y}"))
else ''
@ -242,11 +239,11 @@ in {
options = {
services.autorandr = {
enable = mkEnableOption "handling of hotplug and sleep events by autorandr";
enable = lib.mkEnableOption "handling of hotplug and sleep events by autorandr";
defaultTarget = mkOption {
defaultTarget = lib.mkOption {
default = "default";
type = types.str;
type = lib.types.str;
description = ''
Fallback if no monitor layout can be detected. See the docs
(https://github.com/phillipberndt/autorandr/blob/v1.0/README.md#how-to-use)
@ -254,23 +251,23 @@ in {
'';
};
ignoreLid = mkOption {
ignoreLid = lib.mkOption {
default = false;
type = types.bool;
type = lib.types.bool;
description = "Treat outputs as connected even if their lids are closed";
};
matchEdid = mkOption {
matchEdid = lib.mkOption {
default = false;
type = types.bool;
type = lib.types.bool;
description = "Match displays based on edid instead of name";
};
hooks = mkOption {
hooks = lib.mkOption {
type = hooksModule;
description = "Global hook scripts";
default = { };
example = literalExpression ''
example = lib.literalExpression ''
{
postswitch = {
"notify-i3" = "''${pkgs.i3}/bin/i3-msg restart";
@ -296,11 +293,11 @@ in {
}
'';
};
profiles = mkOption {
type = types.attrsOf profileModule;
profiles = lib.mkOption {
type = lib.types.attrsOf profileModule;
description = "Autorandr profiles specification.";
default = { };
example = literalExpression ''
example = lib.literalExpression ''
{
"work" = {
fingerprint = {
@ -330,17 +327,17 @@ in {
};
config = mkIf cfg.enable {
config = lib.mkIf cfg.enable {
services.udev.packages = [ pkgs.autorandr ];
environment = {
systemPackages = [ pkgs.autorandr ];
etc = mkMerge ([
(mapAttrs' (hookToFile "postswitch.d") cfg.hooks.postswitch)
(mapAttrs' (hookToFile "preswitch.d") cfg.hooks.preswitch)
(mapAttrs' (hookToFile "predetect.d") cfg.hooks.predetect)
(mkMerge (mapAttrsToList profileToFiles cfg.profiles))
etc = lib.mkMerge ([
(lib.mapAttrs' (hookToFile "postswitch.d") cfg.hooks.postswitch)
(lib.mapAttrs' (hookToFile "preswitch.d") cfg.hooks.preswitch)
(lib.mapAttrs' (hookToFile "predetect.d") cfg.hooks.predetect)
(lib.mkMerge (lib.mapAttrsToList profileToFiles cfg.profiles))
]);
};
@ -357,8 +354,8 @@ in {
--batch \
--change \
--default ${cfg.defaultTarget} \
${optionalString cfg.ignoreLid "--ignore-lid"} \
${optionalString cfg.matchEdid "--match-edid"}
${lib.optionalString cfg.ignoreLid "--ignore-lid"} \
${lib.optionalString cfg.matchEdid "--match-edid"}
'';
Type = "oneshot";
RemainAfterExit = false;
@ -368,5 +365,5 @@ in {
};
meta.maintainers = with maintainers; [ alexnortung ];
meta.maintainers = with lib.maintainers; [ alexnortung ];
}

View File

@ -1,6 +1,4 @@
{ pkgs, lib, config, ... }:
with lib;
let
cfg = config.services.gammu-smsd;
@ -10,7 +8,7 @@ let
Connection = ${cfg.device.connection}
SynchronizeTime = ${if cfg.device.synchronizeTime then "yes" else "no"}
LogFormat = ${cfg.log.format}
${optionalString (cfg.device.pin != null) "PIN = ${cfg.device.pin}"}
${lib.optionalString (cfg.device.pin != null) "PIN = ${cfg.device.pin}"}
${cfg.extraConfig.gammu}
@ -18,25 +16,25 @@ let
LogFile = ${cfg.log.file}
Service = ${cfg.backend.service}
${optionalString (cfg.backend.service == "files") ''
${lib.optionalString (cfg.backend.service == "files") ''
InboxPath = ${cfg.backend.files.inboxPath}
OutboxPath = ${cfg.backend.files.outboxPath}
SentSMSPath = ${cfg.backend.files.sentSMSPath}
ErrorSMSPath = ${cfg.backend.files.errorSMSPath}
''}
${optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "sqlite") ''
${lib.optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "sqlite") ''
Driver = ${cfg.backend.sql.driver}
DBDir = ${cfg.backend.sql.database}
''}
${optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "native_pgsql") (
${lib.optionalString (cfg.backend.service == "sql" && cfg.backend.sql.driver == "native_pgsql") (
with cfg.backend; ''
Driver = ${sql.driver}
${optionalString (sql.database!= null) "Database = ${sql.database}"}
${optionalString (sql.host != null) "Host = ${sql.host}"}
${optionalString (sql.user != null) "User = ${sql.user}"}
${optionalString (sql.password != null) "Password = ${sql.password}"}
${lib.optionalString (sql.database!= null) "Database = ${sql.database}"}
${lib.optionalString (sql.host != null) "Host = ${sql.host}"}
${lib.optionalString (sql.user != null) "User = ${sql.user}"}
${lib.optionalString (sql.password != null) "Password = ${sql.password}"}
'')}
${cfg.extraConfig.smsd}
@ -53,42 +51,42 @@ in {
options = {
services.gammu-smsd = {
enable = mkEnableOption "gammu-smsd daemon";
enable = lib.mkEnableOption "gammu-smsd daemon";
user = mkOption {
type = types.str;
user = lib.mkOption {
type = lib.types.str;
default = "smsd";
description = "User that has access to the device";
};
device = {
path = mkOption {
type = types.path;
path = lib.mkOption {
type = lib.types.path;
description = "Device node or address of the phone";
example = "/dev/ttyUSB2";
};
group = mkOption {
type = types.str;
group = lib.mkOption {
type = lib.types.str;
default = "root";
description = "Owner group of the device";
example = "dialout";
};
connection = mkOption {
type = types.str;
connection = lib.mkOption {
type = lib.types.str;
default = "at";
description = "Protocol which will be used to talk to the phone";
};
synchronizeTime = mkOption {
type = types.bool;
synchronizeTime = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to set time from computer to the phone during starting connection";
};
pin = mkOption {
type = types.nullOr types.str;
pin = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "PIN code for the simcard";
};
@ -96,14 +94,14 @@ in {
log = {
file = mkOption {
type = types.str;
file = lib.mkOption {
type = lib.types.str;
default = "syslog";
description = "Path to file where information about communication will be stored";
};
format = mkOption {
type = types.enum [ "nothing" "text" "textall" "textalldate" "errors" "errorsdate" "binary" ];
format = lib.mkOption {
type = lib.types.enum [ "nothing" "text" "textall" "textalldate" "errors" "errorsdate" "binary" ];
default = "errors";
description = "Determines what will be logged to the LogFile";
};
@ -111,15 +109,15 @@ in {
extraConfig = {
gammu = mkOption {
type = types.lines;
gammu = lib.mkOption {
type = lib.types.lines;
default = "";
description = "Extra config lines to be added into [gammu] section";
};
smsd = mkOption {
type = types.lines;
smsd = lib.mkOption {
type = lib.types.lines;
default = "";
description = "Extra config lines to be added into [smsd] section";
};
@ -127,70 +125,70 @@ in {
backend = {
service = mkOption {
type = types.enum [ "null" "files" "sql" ];
service = lib.mkOption {
type = lib.types.enum [ "null" "files" "sql" ];
default = "null";
description = "Service to use to store sms data.";
};
files = {
inboxPath = mkOption {
type = types.path;
inboxPath = lib.mkOption {
type = lib.types.path;
default = "/var/spool/sms/inbox/";
description = "Where the received SMSes are stored";
};
outboxPath = mkOption {
type = types.path;
outboxPath = lib.mkOption {
type = lib.types.path;
default = "/var/spool/sms/outbox/";
description = "Where SMSes to be sent should be placed";
};
sentSMSPath = mkOption {
type = types.path;
sentSMSPath = lib.mkOption {
type = lib.types.path;
default = "/var/spool/sms/sent/";
description = "Where the transmitted SMSes are placed";
};
errorSMSPath = mkOption {
type = types.path;
errorSMSPath = lib.mkOption {
type = lib.types.path;
default = "/var/spool/sms/error/";
description = "Where SMSes with error in transmission is placed";
};
};
sql = {
driver = mkOption {
type = types.enum [ "native_mysql" "native_pgsql" "odbc" "dbi" ];
driver = lib.mkOption {
type = lib.types.enum [ "native_mysql" "native_pgsql" "odbc" "dbi" ];
description = "DB driver to use";
};
sqlDialect = mkOption {
type = types.nullOr types.str;
sqlDialect = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "SQL dialect to use (odbc driver only)";
};
database = mkOption {
type = types.nullOr types.str;
database = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Database name to store sms data";
};
host = mkOption {
type = types.str;
host = lib.mkOption {
type = lib.types.str;
default = "localhost";
description = "Database server address";
};
user = mkOption {
type = types.nullOr types.str;
user = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "User name used for connection to the database";
};
password = mkOption {
type = types.nullOr types.str;
password = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "User password used for connection to the database";
};
@ -199,7 +197,7 @@ in {
};
};
config = mkIf cfg.enable {
config = lib.mkIf cfg.enable {
users.users.${cfg.user} = {
description = "gammu-smsd user";
isSystemUser = true;
@ -207,7 +205,7 @@ in {
};
environment.systemPackages = with cfg.backend; [ gammuPackage ]
++ optionals (service == "sql" && sql.driver == "sqlite") [ pkgs.sqlite ];
++ lib.optionals (service == "sql" && sql.driver == "sqlite") [ pkgs.sqlite ];
systemd.services.gammu-smsd = {
description = "gammu-smsd daemon";
@ -215,29 +213,29 @@ in {
wantedBy = [ "multi-user.target" ];
wants = with cfg.backend; [ ]
++ optionals (service == "sql" && sql.driver == "native_pgsql") [ "postgresql.service" ];
++ lib.optionals (service == "sql" && sql.driver == "native_pgsql") [ "postgresql.service" ];
preStart = with cfg.backend;
optionalString (service == "files") (with files; ''
lib.optionalString (service == "files") (with files; ''
mkdir -m 755 -p ${inboxPath} ${outboxPath} ${sentSMSPath} ${errorSMSPath}
chown ${cfg.user} -R ${inboxPath}
chown ${cfg.user} -R ${outboxPath}
chown ${cfg.user} -R ${sentSMSPath}
chown ${cfg.user} -R ${errorSMSPath}
'')
+ optionalString (service == "sql" && sql.driver == "sqlite") ''
+ lib.optionalString (service == "sql" && sql.driver == "sqlite") ''
cat "${gammuPackage}/${initDBDir}/sqlite.sql" \
| ${pkgs.sqlite.bin}/bin/sqlite3 ${sql.database}
''
+ (let execPsql = extraArgs: concatStringsSep " " [
(optionalString (sql.password != null) "PGPASSWORD=${sql.password}")
+ (let execPsql = extraArgs: lib.concatStringsSep " " [
(lib.optionalString (sql.password != null) "PGPASSWORD=${sql.password}")
"${config.services.postgresql.package}/bin/psql"
(optionalString (sql.host != null) "-h ${sql.host}")
(optionalString (sql.user != null) "-U ${sql.user}")
(lib.optionalString (sql.host != null) "-h ${sql.host}")
(lib.optionalString (sql.user != null) "-U ${sql.user}")
"$extraArgs"
"${sql.database}"
]; in optionalString (service == "sql" && sql.driver == "native_pgsql") ''
]; in lib.optionalString (service == "sql" && sql.driver == "native_pgsql") ''
echo '\i '"${gammuPackage}/${initDBDir}/pgsql.sql" | ${execPsql ""}
'');

View File

@ -222,6 +222,7 @@ in
environment = {
HOMEPAGE_CONFIG_DIR = configDir;
HOMEPAGE_CACHE_DIR = "/var/cache/homepage-dashboard";
PORT = toString cfg.listenPort;
LOG_TARGETS = lib.mkIf managedConfig "stdout";
};
@ -231,6 +232,7 @@ in
DynamicUser = true;
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
StateDirectory = lib.mkIf (!managedConfig) "homepage-dashboard";
CacheDirectory = "homepage-dashboard";
ExecStart = lib.getExe cfg.package;
Restart = "on-failure";
};

View File

@ -1,7 +1,4 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
gid = config.ids.gids.mediatomb;
@ -13,19 +10,19 @@ let
# configuration on media directory
mediaDirectory = {
options = {
path = mkOption {
type = types.str;
path = lib.mkOption {
type = lib.types.str;
description = ''
Absolute directory path to the media directory to index.
'';
};
recursive = mkOption {
type = types.bool;
recursive = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether the indexation must take place recursively or not.";
};
hidden-files = mkOption {
type = types.bool;
hidden-files = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to index the hidden files or not.";
};
@ -66,7 +63,7 @@ let
</transcoding>
'';
configText = optionalString (! cfg.customCfg) ''
configText = lib.optionalString (! cfg.customCfg) ''
<?xml version="1.0" encoding="UTF-8"?>
<config version="2" xmlns="http://mediatomb.cc/config/2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://mediatomb.cc/config/2 http://mediatomb.cc/config/2.xsd">
<server>
@ -87,7 +84,7 @@ let
</sqlite3>
</storage>
<protocolInfo extend="${optionYesNo cfg.ps3Support}"/>
${optionalString cfg.dsmSupport ''
${lib.optionalString cfg.dsmSupport ''
<custom-http-headers>
<add header="X-User-Agent: redsonic"/>
</custom-http-headers>
@ -95,7 +92,7 @@ let
<manufacturerURL>redsonic.com</manufacturerURL>
<modelNumber>105</modelNumber>
''}
${optionalString cfg.tg100Support ''
${lib.optionalString cfg.tg100Support ''
<upnp-string-limit>101</upnp-string-limit>
''}
<extended-runtime-options>
@ -109,7 +106,7 @@ let
</server>
<import hidden-files="no">
<autoscan use-inotify="auto">
${concatMapStrings toMediaDirectory cfg.mediaDirectories}
${lib.concatMapStrings toMediaDirectory cfg.mediaDirectories}
</autoscan>
<scripting script-charset="UTF-8">
<common-script>${pkg}/share/${name}/js/common.js</common-script>
@ -139,10 +136,10 @@ let
<map from="flv" to="video/x-flv"/>
<map from="mkv" to="video/x-matroska"/>
<map from="mka" to="audio/x-matroska"/>
${optionalString cfg.ps3Support ''
${lib.optionalString cfg.ps3Support ''
<map from="avi" to="video/divx"/>
''}
${optionalString cfg.dsmSupport ''
${lib.optionalString cfg.dsmSupport ''
<map from="avi" to="video/avi"/>
''}
</extension-mimetype>
@ -199,26 +196,26 @@ in {
services.mediatomb = {
enable = mkOption {
type = types.bool;
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable the Gerbera/Mediatomb DLNA server.
'';
};
serverName = mkOption {
type = types.str;
serverName = lib.mkOption {
type = lib.types.str;
default = "Gerbera (Mediatomb)";
description = ''
How to identify the server on the network.
'';
};
package = mkPackageOption pkgs "gerbera" { };
package = lib.mkPackageOption pkgs "gerbera" { };
ps3Support = mkOption {
type = types.bool;
ps3Support = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable ps3 specific tweaks.
@ -226,8 +223,8 @@ in {
'';
};
dsmSupport = mkOption {
type = types.bool;
dsmSupport = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable D-Link DSM 320 specific tweaks.
@ -235,69 +232,69 @@ in {
'';
};
tg100Support = mkOption {
type = types.bool;
tg100Support = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable Telegent TG100 specific tweaks.
'';
};
transcoding = mkOption {
type = types.bool;
transcoding = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable transcoding.
'';
};
dataDir = mkOption {
type = types.path;
dataDir = lib.mkOption {
type = lib.types.path;
default = "/var/lib/${name}";
defaultText = literalExpression ''"/var/lib/''${config.${opt.package}.pname}"'';
defaultText = lib.literalExpression ''"/var/lib/''${config.${opt.package}.pname}"'';
description = ''
The directory where Gerbera/Mediatomb stores its state, data, etc.
'';
};
pcDirectoryHide = mkOption {
type = types.bool;
pcDirectoryHide = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Whether to list the top-level directory or not (from upnp client standpoint).
'';
};
user = mkOption {
type = types.str;
user = lib.mkOption {
type = lib.types.str;
default = "mediatomb";
description = "User account under which the service runs.";
};
group = mkOption {
type = types.str;
group = lib.mkOption {
type = lib.types.str;
default = "mediatomb";
description = "Group account under which the service runs.";
};
port = mkOption {
type = types.port;
port = lib.mkOption {
type = lib.types.port;
default = 49152;
description = ''
The network port to listen on.
'';
};
interface = mkOption {
type = types.str;
interface = lib.mkOption {
type = lib.types.str;
default = "";
description = ''
A specific interface to bind to.
'';
};
openFirewall = mkOption {
type = types.bool;
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
If false (the default), this is up to the user to declare the firewall rules.
@ -310,16 +307,16 @@ in {
'';
};
uuid = mkOption {
type = types.str;
uuid = lib.mkOption {
type = lib.types.str;
default = "fdfc8a4e-a3ad-4c1d-b43d-a2eedb03a687";
description = ''
A unique (on your network) to identify the server by.
'';
};
mediaDirectories = mkOption {
type = with types; listOf (submodule mediaDirectory);
mediaDirectories = lib.mkOption {
type = with lib.types; listOf (submodule mediaDirectory);
default = [];
description = ''
Declare media directories to index.
@ -330,8 +327,8 @@ in {
];
};
customCfg = mkOption {
type = types.bool;
customCfg = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Allow the service to create and use its own config file inside the `dataDir` as
@ -350,9 +347,9 @@ in {
###### implementation
config = let binaryCommand = "${pkg}/bin/${name}";
interfaceFlag = optionalString ( cfg.interface != "") "--interface ${cfg.interface}";
configFlag = optionalString (! cfg.customCfg) "--config ${pkgs.writeText "config.xml" configText}";
in mkIf cfg.enable {
interfaceFlag = lib.optionalString ( cfg.interface != "") "--interface ${cfg.interface}";
configFlag = lib.optionalString (! cfg.customCfg) "--config ${pkgs.writeText "config.xml" configText}";
in lib.mkIf cfg.enable {
systemd.services.mediatomb = {
description = "${cfg.serverName} media Server";
# Gerbera might fail if the network interface is not available on startup
@ -365,11 +362,11 @@ in {
serviceConfig.Group = cfg.group;
};
users.groups = optionalAttrs (cfg.group == "mediatomb") {
users.groups = lib.optionalAttrs (cfg.group == "mediatomb") {
mediatomb.gid = gid;
};
users.users = optionalAttrs (cfg.user == "mediatomb") {
users.users = lib.optionalAttrs (cfg.user == "mediatomb") {
mediatomb = {
isSystemUser = true;
group = cfg.group;
@ -380,11 +377,11 @@ in {
};
# Open firewall only if users enable it
networking.firewall = mkMerge [
(mkIf (cfg.openFirewall && cfg.interface != "") {
networking.firewall = lib.mkMerge [
(lib.mkIf (cfg.openFirewall && cfg.interface != "") {
interfaces."${cfg.interface}" = defaultFirewallRules;
})
(mkIf (cfg.openFirewall && cfg.interface == "") defaultFirewallRules)
(lib.mkIf (cfg.openFirewall && cfg.interface == "") defaultFirewallRules)
];
};
}

View File

@ -4,12 +4,9 @@
pkgs,
...
}:
with lib;
let
cfg = config.services.mqtt2influxdb;
filterNull = filterAttrsRecursive (n: v: v != null);
filterNull = lib.filterAttrsRecursive (n: v: v != null);
configFile = (pkgs.formats.yaml {}).generate "mqtt2influxdb.config.yaml" (
filterNull {
inherit (cfg) mqtt influxdb;
@ -17,26 +14,26 @@ let
}
);
pointType = types.submodule {
pointType = lib.types.submodule {
options = {
measurement = mkOption {
type = types.str;
measurement = lib.mkOption {
type = lib.types.str;
description = "Name of the measurement";
};
topic = mkOption {
type = types.str;
topic = lib.mkOption {
type = lib.types.str;
description = "MQTT topic to subscribe to.";
};
fields = mkOption {
type = types.submodule {
fields = lib.mkOption {
type = lib.types.submodule {
options = {
value = mkOption {
type = types.str;
value = lib.mkOption {
type = lib.types.str;
default = "$.payload";
description = "Value to be picked up";
};
type = mkOption {
type = with types; nullOr str;
type = lib.mkOption {
type = with lib.types; nullOr str;
default = null;
description = "Type to be picked up";
};
@ -44,8 +41,8 @@ let
};
description = "Field selector.";
};
tags = mkOption {
type = with types; attrsOf str;
tags = lib.mkOption {
type = with lib.types; attrsOf str;
default = {};
description = "Tags applied";
};
@ -124,10 +121,10 @@ let
in {
options = {
services.mqtt2influxdb = {
enable = mkEnableOption "BigClown MQTT to InfluxDB bridge";
package = mkPackageOption pkgs ["python3Packages" "mqtt2influxdb"] {};
environmentFiles = mkOption {
type = types.listOf types.path;
enable = lib.mkEnableOption "BigClown MQTT to InfluxDB bridge";
package = lib.mkPackageOption pkgs ["python3Packages" "mqtt2influxdb"] {};
environmentFiles = lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [];
example = [ "/run/keys/mqtt2influxdb.env" ];
description = ''
@ -138,23 +135,23 @@ in {
'';
};
mqtt = {
host = mkOption {
type = types.str;
host = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Host where MQTT server is running.";
};
port = mkOption {
type = types.port;
port = lib.mkOption {
type = lib.types.port;
default = 1883;
description = "MQTT server port.";
};
username = mkOption {
type = with types; nullOr str;
username = lib.mkOption {
type = with lib.types; nullOr str;
default = null;
description = "Username used to connect to the MQTT server.";
};
password = mkOption {
type = with types; nullOr str;
password = lib.mkOption {
type = with lib.types; nullOr str;
default = null;
description = ''
MQTT password.
@ -164,44 +161,44 @@ in {
the store.
'';
};
cafile = mkOption {
type = with types; nullOr path;
cafile = lib.mkOption {
type = with lib.types; nullOr path;
default = null;
description = "Certification Authority file for MQTT";
};
certfile = mkOption {
type = with types; nullOr path;
certfile = lib.mkOption {
type = with lib.types; nullOr path;
default = null;
description = "Certificate file for MQTT";
};
keyfile = mkOption {
type = with types; nullOr path;
keyfile = lib.mkOption {
type = with lib.types; nullOr path;
default = null;
description = "Key file for MQTT";
};
};
influxdb = {
host = mkOption {
type = types.str;
host = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Host where InfluxDB server is running.";
};
port = mkOption {
type = types.port;
port = lib.mkOption {
type = lib.types.port;
default = 8086;
description = "InfluxDB server port";
};
database = mkOption {
type = types.str;
database = lib.mkOption {
type = lib.types.str;
description = "Name of the InfluxDB database.";
};
username = mkOption {
type = with types; nullOr str;
username = lib.mkOption {
type = with lib.types; nullOr str;
default = null;
description = "Username for InfluxDB login.";
};
password = mkOption {
type = with types; nullOr str;
password = lib.mkOption {
type = with lib.types; nullOr str;
default = null;
description = ''
Password for InfluxDB login.
@ -211,26 +208,26 @@ in {
the store.
'';
};
ssl = mkOption {
type = types.bool;
ssl = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Use SSL to connect to the InfluxDB server.";
};
verify_ssl = mkOption {
type = types.bool;
verify_ssl = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Verify SSL certificate when connecting to the InfluxDB server.";
};
};
points = mkOption {
type = types.listOf pointType;
points = lib.mkOption {
type = lib.types.listOf pointType;
default = defaultPoints;
description = "Points to bridge from MQTT to InfluxDB.";
};
};
};
config = mkIf cfg.enable {
config = lib.mkIf cfg.enable {
systemd.services.bigclown-mqtt2influxdb = let
envConfig = cfg.environmentFiles != [];
finalConfig = if envConfig
@ -239,7 +236,7 @@ in {
in {
description = "BigClown MQTT to InfluxDB bridge";
wantedBy = ["multi-user.target"];
wants = mkIf config.services.mosquitto.enable ["mosquitto.service"];
wants = lib.mkIf config.services.mosquitto.enable ["mosquitto.service"];
preStart = ''
umask 077
${pkgs.envsubst}/bin/envsubst -i "${configFile}" -o "${finalConfig}"

View File

@ -1,16 +1,13 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.nitter;
configFile = pkgs.writeText "nitter.conf" ''
${generators.toINI {
${lib.generators.toINI {
# String values need to be quoted
mkKeyValue = generators.mkKeyValueDefault {
mkKeyValue = lib.generators.mkKeyValueDefault {
mkValueString = v:
if isString v then "\"" + (strings.escape ["\""] (toString v)) + "\""
else generators.mkValueStringDefault {} v;
if lib.isString v then "\"" + (lib.escape ["\""] (toString v)) + "\""
else lib.generators.mkValueStringDefault {} v;
} " = ";
} (lib.recursiveUpdate {
Server = cfg.server;
@ -47,57 +44,57 @@ in
{
imports = [
# https://github.com/zedeus/nitter/pull/772
(mkRemovedOptionModule [ "services" "nitter" "replaceInstagram" ] "Nitter no longer supports this option as Bibliogram has been discontinued.")
(lib.mkRemovedOptionModule [ "services" "nitter" "replaceInstagram" ] "Nitter no longer supports this option as Bibliogram has been discontinued.")
];
options = {
services.nitter = {
enable = mkEnableOption "Nitter, an alternative Twitter front-end";
enable = lib.mkEnableOption "Nitter, an alternative Twitter front-end";
package = mkPackageOption pkgs "nitter" { };
package = lib.mkPackageOption pkgs "nitter" { };
server = {
address = mkOption {
type = types.str;
address = lib.mkOption {
type = lib.types.str;
default = "0.0.0.0";
example = "127.0.0.1";
description = "The address to listen on.";
};
port = mkOption {
type = types.port;
port = lib.mkOption {
type = lib.types.port;
default = 8080;
example = 8000;
description = "The port to listen on.";
};
https = mkOption {
type = types.bool;
https = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Set secure attribute on cookies. Keep it disabled to enable cookies when not using HTTPS.";
};
httpMaxConnections = mkOption {
type = types.int;
httpMaxConnections = lib.mkOption {
type = lib.types.int;
default = 100;
description = "Maximum number of HTTP connections.";
};
staticDir = mkOption {
type = types.path;
staticDir = lib.mkOption {
type = lib.types.path;
default = "${cfg.package}/share/nitter/public";
defaultText = literalExpression ''"''${config.services.nitter.package}/share/nitter/public"'';
defaultText = lib.literalExpression ''"''${config.services.nitter.package}/share/nitter/public"'';
description = "Path to the static files directory.";
};
title = mkOption {
type = types.str;
title = lib.mkOption {
type = lib.types.str;
default = "nitter";
description = "Title of the instance.";
};
hostname = mkOption {
type = types.str;
hostname = lib.mkOption {
type = lib.types.str;
default = "localhost";
example = "nitter.net";
description = "Hostname of the instance.";
@ -105,38 +102,38 @@ in
};
cache = {
listMinutes = mkOption {
type = types.int;
listMinutes = lib.mkOption {
type = lib.types.int;
default = 240;
description = "How long to cache list info (not the tweets, so keep it high).";
};
rssMinutes = mkOption {
type = types.int;
rssMinutes = lib.mkOption {
type = lib.types.int;
default = 10;
description = "How long to cache RSS queries.";
};
redisHost = mkOption {
type = types.str;
redisHost = lib.mkOption {
type = lib.types.str;
default = "localhost";
description = "Redis host.";
};
redisPort = mkOption {
type = types.port;
redisPort = lib.mkOption {
type = lib.types.port;
default = 6379;
description = "Redis port.";
};
redisConnections = mkOption {
type = types.int;
redisConnections = lib.mkOption {
type = lib.types.int;
default = 20;
description = "Redis connection pool size.";
};
redisMaxConnections = mkOption {
type = types.int;
redisMaxConnections = lib.mkOption {
type = lib.types.int;
default = 30;
description = ''
Maximum number of connections to Redis.
@ -149,30 +146,30 @@ in
};
config = {
base64Media = mkOption {
type = types.bool;
base64Media = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Use base64 encoding for proxied media URLs.";
};
enableRSS = mkEnableOption "RSS feeds" // { default = true; };
enableRSS = lib.mkEnableOption "RSS feeds" // { default = true; };
enableDebug = mkEnableOption "request logs and debug endpoints";
enableDebug = lib.mkEnableOption "request logs and debug endpoints";
proxy = mkOption {
type = types.str;
proxy = lib.mkOption {
type = lib.types.str;
default = "";
description = "URL to a HTTP/HTTPS proxy.";
};
proxyAuth = mkOption {
type = types.str;
proxyAuth = lib.mkOption {
type = lib.types.str;
default = "";
description = "Credentials for proxy.";
};
tokenCount = mkOption {
type = types.int;
tokenCount = lib.mkOption {
type = lib.types.int;
default = 10;
description = ''
Minimum amount of usable tokens.
@ -187,114 +184,114 @@ in
};
preferences = {
replaceTwitter = mkOption {
type = types.str;
replaceTwitter = lib.mkOption {
type = lib.types.str;
default = "";
example = "nitter.net";
description = "Replace Twitter links with links to this instance (blank to disable).";
};
replaceYouTube = mkOption {
type = types.str;
replaceYouTube = lib.mkOption {
type = lib.types.str;
default = "";
example = "piped.kavin.rocks";
description = "Replace YouTube links with links to this instance (blank to disable).";
};
replaceReddit = mkOption {
type = types.str;
replaceReddit = lib.mkOption {
type = lib.types.str;
default = "";
example = "teddit.net";
description = "Replace Reddit links with links to this instance (blank to disable).";
};
mp4Playback = mkOption {
type = types.bool;
mp4Playback = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Enable MP4 video playback.";
};
hlsPlayback = mkOption {
type = types.bool;
hlsPlayback = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Enable HLS video streaming (requires JavaScript).";
};
proxyVideos = mkOption {
type = types.bool;
proxyVideos = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Proxy video streaming through the server (might be slow).";
};
muteVideos = mkOption {
type = types.bool;
muteVideos = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Mute videos by default.";
};
autoplayGifs = mkOption {
type = types.bool;
autoplayGifs = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Autoplay GIFs.";
};
theme = mkOption {
type = types.str;
theme = lib.mkOption {
type = lib.types.str;
default = "Nitter";
description = "Instance theme.";
};
infiniteScroll = mkOption {
type = types.bool;
infiniteScroll = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Infinite scrolling (requires JavaScript, experimental!).";
};
stickyProfile = mkOption {
type = types.bool;
stickyProfile = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Make profile sidebar stick to top.";
};
bidiSupport = mkOption {
type = types.bool;
bidiSupport = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Support bidirectional text (makes clicking on tweets harder).";
};
hideTweetStats = mkOption {
type = types.bool;
hideTweetStats = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Hide tweet stats (replies, retweets, likes).";
};
hideBanner = mkOption {
type = types.bool;
hideBanner = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Hide profile banner.";
};
hidePins = mkOption {
type = types.bool;
hidePins = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Hide pinned tweets.";
};
hideReplies = mkOption {
type = types.bool;
hideReplies = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Hide tweet replies.";
};
squareAvatars = mkOption {
type = types.bool;
squareAvatars = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Square profile pictures.";
};
};
settings = mkOption {
type = types.attrs;
settings = lib.mkOption {
type = lib.types.attrs;
default = {};
description = ''
Add settings here to override NixOS module generated settings.
@ -304,8 +301,8 @@ in
'';
};
guestAccounts = mkOption {
type = types.path;
guestAccounts = lib.mkOption {
type = lib.types.path;
default = "/var/lib/nitter/guest_accounts.jsonl";
description = ''
Path to the guest accounts file.
@ -321,21 +318,21 @@ in
'';
};
redisCreateLocally = mkOption {
type = types.bool;
redisCreateLocally = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Configure local Redis server for Nitter.";
};
openFirewall = mkOption {
type = types.bool;
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Open ports in the firewall for Nitter web interface.";
};
};
};
config = mkIf cfg.enable {
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = !cfg.redisCreateLocally || (cfg.cache.redisHost == "localhost" && cfg.cache.redisPort == 6379);
@ -397,7 +394,7 @@ in
port = cfg.cache.redisPort;
};
networking.firewall = mkIf cfg.openFirewall {
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.server.port ];
};
};

View File

@ -1,39 +1,36 @@
{ config, lib, pkgs, ...}:
with lib;
let
cfg = config.services.mosquitto;
# note that mosquitto config parsing is very simplistic as of may 2021.
# often times they'll e.g. strtok() a line, check the first two tokens, and ignore the rest.
# there's no escaping available either, so we have to prevent any being necessary.
str = types.strMatching "[^\r\n]*" // {
str = lib.types.strMatching "[^\r\n]*" // {
description = "single-line string";
};
path = types.addCheck types.path (p: str.check "${p}");
configKey = types.strMatching "[^\r\n\t ]+";
optionType = with types; oneOf [ str path bool int ] // {
path = lib.types.addCheck lib.types.path (p: str.check "${p}");
configKey = lib.types.strMatching "[^\r\n\t ]+";
optionType = with lib.types; oneOf [ str path bool int ] // {
description = "string, path, bool, or integer";
};
optionToString = v:
if isBool v then boolToString v
if lib.isBool v then lib.boolToString v
else if path.check v then "${v}"
else toString v;
assertKeysValid = prefix: valid: config:
mapAttrsToList
lib.mapAttrsToList
(n: _: {
assertion = valid ? ${n};
message = "Invalid config key ${prefix}.${n}.";
})
config;
formatFreeform = { prefix ? "" }: mapAttrsToList (n: v: "${prefix}${n} ${optionToString v}");
formatFreeform = { prefix ? "" }: lib.mapAttrsToList (n: v: "${prefix}${n} ${optionToString v}");
userOptions = with types; submodule {
userOptions = with lib.types; submodule {
options = {
password = mkOption {
password = lib.mkOption {
type = uniq (nullOr str);
default = null;
description = ''
@ -41,7 +38,7 @@ let
'';
};
passwordFile = mkOption {
passwordFile = lib.mkOption {
type = uniq (nullOr path);
example = "/path/to/file";
default = null;
@ -54,7 +51,7 @@ let
'';
};
hashedPassword = mkOption {
hashedPassword = lib.mkOption {
type = uniq (nullOr str);
default = null;
description = ''
@ -66,7 +63,7 @@ let
'';
};
hashedPasswordFile = mkOption {
hashedPasswordFile = lib.mkOption {
type = uniq (nullOr path);
example = "/path/to/file";
default = null;
@ -82,7 +79,7 @@ let
'';
};
acl = mkOption {
acl = lib.mkOption {
type = listOf str;
example = [ "read A/B" "readwrite A/#" ];
default = [];
@ -94,15 +91,15 @@ let
};
userAsserts = prefix: users:
mapAttrsToList
lib.mapAttrsToList
(n: _: {
assertion = builtins.match "[^:\r\n]+" n != null;
message = "Invalid user name ${n} in ${prefix}";
})
users
++ mapAttrsToList
++ lib.mapAttrsToList
(n: u: {
assertion = count (s: s != null) [
assertion = lib.count (s: s != null) [
u.password u.passwordFile u.hashedPassword u.hashedPasswordFile
] <= 1;
message = "Cannot set more than one password option for user ${n} in ${prefix}";
@ -112,26 +109,26 @@ let
userScope = prefix: index: "${prefix}-user-${toString index}";
credentialID = prefix: credential: "${prefix}-${credential}";
toScopedUsers = listenerScope: users: pipe users [
attrNames
(imap0 (index: user: nameValuePair user
toScopedUsers = listenerScope: users: lib.pipe users [
lib.attrNames
(lib.imap0 (index: user: lib.nameValuePair user
(users.${user} // { scope = userScope listenerScope index; })
))
listToAttrs
lib.listToAttrs
];
userCredentials = user: credentials: pipe credentials [
(filter (credential: user.${credential} != null))
userCredentials = user: credentials: lib.pipe credentials [
(lib.filter (credential: user.${credential} != null))
(map (credential: "${credentialID user.scope credential}:${user.${credential}}"))
];
usersCredentials = listenerScope: users: credentials: pipe users [
usersCredentials = listenerScope: users: credentials: lib.pipe users [
(toScopedUsers listenerScope)
(mapAttrsToList (_: user: userCredentials user credentials))
concatLists
(lib.mapAttrsToList (_: user: userCredentials user credentials))
lib.concatLists
];
systemdCredentials = listeners: listenerCredentials: pipe listeners [
(imap0 (index: listener: listenerCredentials (listenerScope index) listener))
concatLists
systemdCredentials = listeners: listenerCredentials: lib.pipe listeners [
(lib.imap0 (index: listener: listenerCredentials (listenerScope index) listener))
lib.concatLists
];
makePasswordFile = listenerScope: users: path:
@ -139,12 +136,12 @@ let
makeLines = store: file: let
scopedUsers = toScopedUsers listenerScope users;
in
mapAttrsToList
(name: user: ''addLine ${escapeShellArg name} "''$(systemd-creds cat ${credentialID user.scope store})"'')
(filterAttrs (_: user: user.${store} != null) scopedUsers)
++ mapAttrsToList
(name: user: ''addFile ${escapeShellArg name} "''${CREDENTIALS_DIRECTORY}/${credentialID user.scope file}"'')
(filterAttrs (_: user: user.${file} != null) scopedUsers);
lib.mapAttrsToList
(name: user: ''addLine ${lib.escapeShellArg name} "''$(systemd-creds cat ${credentialID user.scope store})"'')
(lib.filterAttrs (_: user: user.${store} != null) scopedUsers)
++ lib.mapAttrsToList
(name: user: ''addFile ${lib.escapeShellArg name} "''${CREDENTIALS_DIRECTORY}/${credentialID user.scope file}"'')
(lib.filterAttrs (_: user: user.${file} != null) scopedUsers);
plainLines = makeLines "password" "passwordFile";
hashedLines = makeLines "hashedPassword" "hashedPasswordFile";
in
@ -154,7 +151,7 @@ let
set -eu
file=${escapeShellArg path}
file=${lib.escapeShellArg path}
rm -f "$file"
touch "$file"
@ -170,23 +167,23 @@ let
echo "$1:$(cat "$2")" >> "$file"
}
''
+ concatStringsSep "\n"
+ lib.concatStringsSep "\n"
(plainLines
++ optional (plainLines != []) ''
++ lib.optional (plainLines != []) ''
${cfg.package}/bin/mosquitto_passwd -U "$file"
''
++ hashedLines));
authPluginOptions = with types; submodule {
authPluginOptions = with lib.types; submodule {
options = {
plugin = mkOption {
plugin = lib.mkOption {
type = path;
description = ''
Plugin path to load, should be a `.so` file.
'';
};
denySpecialChars = mkOption {
denySpecialChars = lib.mkOption {
type = bool;
description = ''
Automatically disallow all clients using `#`
@ -195,7 +192,7 @@ let
default = true;
};
options = mkOption {
options = lib.mkOption {
type = attrsOf optionType;
description = ''
Options for the auth plugin. Each key turns into a `auth_opt_*`
@ -207,7 +204,7 @@ let
};
authAsserts = prefix: auth:
mapAttrsToList
lib.mapAttrsToList
(n: _: {
assertion = configKey.check n;
message = "Invalid auth plugin key ${prefix}.${n}";
@ -253,9 +250,9 @@ let
use_username_as_clientid = 1;
};
listenerOptions = with types; submodule {
listenerOptions = with lib.types; submodule {
options = {
port = mkOption {
port = lib.mkOption {
type = port;
description = ''
Port to listen on. Must be set to 0 to listen on a unix domain socket.
@ -263,7 +260,7 @@ let
default = 1883;
};
address = mkOption {
address = lib.mkOption {
type = nullOr str;
description = ''
Address to listen on. Listen on `0.0.0.0`/`::`
@ -272,7 +269,7 @@ let
default = null;
};
authPlugins = mkOption {
authPlugins = lib.mkOption {
type = listOf authPluginOptions;
description = ''
Authentication plugin to attach to this listener.
@ -282,7 +279,7 @@ let
default = [];
};
users = mkOption {
users = lib.mkOption {
type = attrsOf userOptions;
example = { john = { password = "123456"; acl = [ "readwrite john/#" ]; }; };
description = ''
@ -291,7 +288,7 @@ let
default = {};
};
omitPasswordAuth = mkOption {
omitPasswordAuth = lib.mkOption {
type = bool;
description = ''
Omits password checking, allowing anyone to log in with any user name unless
@ -300,7 +297,7 @@ let
default = false;
};
acl = mkOption {
acl = lib.mkOption {
type = listOf str;
description = ''
Additional ACL items to prepend to the generated ACL file.
@ -309,7 +306,7 @@ let
default = [];
};
settings = mkOption {
settings = lib.mkOption {
type = submodule {
freeformType = attrsOf optionType;
};
@ -324,7 +321,7 @@ let
listenerAsserts = prefix: listener:
assertKeysValid "${prefix}.settings" freeformListenerKeys listener.settings
++ userAsserts prefix listener.users
++ imap0
++ lib.imap0
(i: v: authAsserts "${prefix}.authPlugins.${toString i}" v)
listener.authPlugins;
@ -333,9 +330,9 @@ let
"listener ${toString listener.port} ${toString listener.address}"
"acl_file /etc/mosquitto/acl-${toString idx}.conf"
]
++ optional (! listener.omitPasswordAuth) "password_file ${cfg.dataDir}/passwd-${toString idx}"
++ lib.optional (! listener.omitPasswordAuth) "password_file ${cfg.dataDir}/passwd-${toString idx}"
++ formatFreeform {} listener.settings
++ concatMap formatAuthPlugin listener.authPlugins;
++ lib.concatMap formatAuthPlugin listener.authPlugins;
freeformBridgeKeys = {
bridge_alpn = 1;
@ -373,19 +370,19 @@ let
try_private = 1;
};
bridgeOptions = with types; submodule {
bridgeOptions = with lib.types; submodule {
options = {
addresses = mkOption {
addresses = lib.mkOption {
type = listOf (submodule {
options = {
address = mkOption {
address = lib.mkOption {
type = str;
description = ''
Address of the remote MQTT broker.
'';
};
port = mkOption {
port = lib.mkOption {
type = port;
description = ''
Port of the remote MQTT broker.
@ -400,7 +397,7 @@ let
'';
};
topics = mkOption {
topics = lib.mkOption {
type = listOf str;
description = ''
Topic patterns to be shared between the two brokers.
@ -411,7 +408,7 @@ let
example = [ "# both 2 local/topic/ remote/topic/" ];
};
settings = mkOption {
settings = lib.mkOption {
type = submodule {
freeformType = attrsOf optionType;
};
@ -426,14 +423,14 @@ let
bridgeAsserts = prefix: bridge:
assertKeysValid "${prefix}.settings" freeformBridgeKeys bridge.settings
++ [ {
assertion = length bridge.addresses > 0;
assertion = lib.length bridge.addresses > 0;
message = "Bridge ${prefix} needs remote broker addresses";
} ];
formatBridge = name: bridge:
[
"connection ${name}"
"addresses ${concatMapStringsSep " " (a: "${a.address}:${toString a.port}") bridge.addresses}"
"addresses ${lib.concatMapStringsSep " " (a: "${a.address}:${toString a.port}") bridge.addresses}"
]
++ map (t: "topic ${t}") bridge.topics
++ formatFreeform {} bridge.settings;
@ -468,12 +465,12 @@ let
websockets_log_level = 1;
};
globalOptions = with types; {
enable = mkEnableOption "the MQTT Mosquitto broker";
globalOptions = with lib.types; {
enable = lib.mkEnableOption "the MQTT Mosquitto broker";
package = mkPackageOption pkgs "mosquitto" { };
package = lib.mkPackageOption pkgs "mosquitto" { };
bridges = mkOption {
bridges = lib.mkOption {
type = attrsOf bridgeOptions;
default = {};
description = ''
@ -481,7 +478,7 @@ let
'';
};
listeners = mkOption {
listeners = lib.mkOption {
type = listOf listenerOptions;
default = [];
description = ''
@ -489,7 +486,7 @@ let
'';
};
includeDirs = mkOption {
includeDirs = lib.mkOption {
type = listOf path;
description = ''
Directories to be scanned for further config files to include.
@ -500,7 +497,7 @@ let
default = [];
};
logDest = mkOption {
logDest = lib.mkOption {
type = listOf (either path (enum [ "stdout" "stderr" "syslog" "topic" "dlt" ]));
description = ''
Destinations to send log messages to.
@ -508,7 +505,7 @@ let
default = [ "stderr" ];
};
logType = mkOption {
logType = lib.mkOption {
type = listOf (enum [ "debug" "error" "warning" "notice" "information"
"subscribe" "unsubscribe" "websockets" "none" "all" ]);
description = ''
@ -517,7 +514,7 @@ let
default = [];
};
persistence = mkOption {
persistence = lib.mkOption {
type = bool;
description = ''
Enable persistent storage of subscriptions and messages.
@ -525,15 +522,15 @@ let
default = true;
};
dataDir = mkOption {
dataDir = lib.mkOption {
default = "/var/lib/mosquitto";
type = types.path;
type = lib.types.path;
description = ''
The data directory.
'';
};
settings = mkOption {
settings = lib.mkOption {
type = submodule {
freeformType = attrsOf optionType;
};
@ -545,10 +542,10 @@ let
};
globalAsserts = prefix: cfg:
flatten [
lib.flatten [
(assertKeysValid "${prefix}.settings" freeformGlobalKeys cfg.settings)
(imap0 (n: l: listenerAsserts "${prefix}.listener.${toString n}" l) cfg.listeners)
(mapAttrsToList (n: b: bridgeAsserts "${prefix}.bridge.${n}" b) cfg.bridges)
(lib.imap0 (n: l: listenerAsserts "${prefix}.listener.${toString n}" l) cfg.listeners)
(lib.mapAttrsToList (n: b: bridgeAsserts "${prefix}.bridge.${n}" b) cfg.bridges)
];
formatGlobal = cfg:
@ -561,12 +558,12 @@ let
cfg.logDest
++ map (t: "log_type ${t}") cfg.logType
++ formatFreeform {} cfg.settings
++ concatLists (imap0 formatListener cfg.listeners)
++ concatLists (mapAttrsToList formatBridge cfg.bridges)
++ lib.concatLists (lib.imap0 formatListener cfg.listeners)
++ lib.concatLists (lib.mapAttrsToList formatBridge cfg.bridges)
++ map (d: "include_dir ${d}") cfg.includeDirs;
configFile = pkgs.writeText "mosquitto.conf"
(concatStringsSep "\n" (formatGlobal cfg));
(lib.concatStringsSep "\n" (formatGlobal cfg));
in
@ -578,7 +575,7 @@ in
###### Implementation
config = mkIf cfg.enable {
config = lib.mkIf cfg.enable {
assertions = globalAsserts "services.mosquitto" cfg;
@ -633,13 +630,13 @@ in
ReadWritePaths = [
cfg.dataDir
"/tmp" # mosquitto_passwd creates files in /tmp before moving them
] ++ filter path.check cfg.logDest;
] ++ lib.filter path.check cfg.logDest;
ReadOnlyPaths =
map (p: "${p}")
(cfg.includeDirs
++ filter
++ lib.filter
(v: v != null)
(flatten [
(lib.flatten [
(map
(l: [
(l.settings.psk_file or null)
@ -652,7 +649,7 @@ in
(l.settings.keyfile or null)
])
cfg.listeners)
(mapAttrsToList
(lib.mapAttrsToList
(_: b: [
(b.settings.bridge_cafile or null)
(b.settings.bridge_capath or null)
@ -680,26 +677,26 @@ in
UMask = "0077";
};
preStart =
concatStringsSep
lib.concatStringsSep
"\n"
(imap0
(lib.imap0
(idx: listener: makePasswordFile (listenerScope idx) listener.users "${cfg.dataDir}/passwd-${toString idx}")
cfg.listeners);
};
environment.etc = listToAttrs (
imap0
environment.etc = lib.listToAttrs (
lib.imap0
(idx: listener: {
name = "mosquitto/acl-${toString idx}.conf";
value = {
user = config.users.users.mosquitto.name;
group = config.users.users.mosquitto.group;
mode = "0400";
text = (concatStringsSep
text = (lib.concatStringsSep
"\n"
(flatten [
(lib.flatten [
listener.acl
(mapAttrsToList
(lib.mapAttrsToList
(n: u: [ "user ${n}" ] ++ map (t: "topic ${t}") u.acl)
listener.users)
]));

View File

@ -1,7 +1,8 @@
{ config
, lib
, pkgs
, ...
{
config,
lib,
pkgs,
...
}:
let
@ -29,10 +30,9 @@ let
package = lib.mkPackageOption pkgs "wstunnel" { };
autoStart =
lib.mkEnableOption "starting this wstunnel instance automatically" // {
default = true;
};
autoStart = lib.mkEnableOption "starting this wstunnel instance automatically" // {
default = true;
};
extraArgs = lib.mkOption {
description = ''
@ -75,192 +75,198 @@ let
};
};
serverSubmodule = { config, ... }: {
options = commonOptions // {
listen = lib.mkOption {
description = ''
Address and port to listen on.
Setting the port to a value below 1024 will also give the process
the required `CAP_NET_BIND_SERVICE` capability.
'';
type = lib.types.submodule hostPortSubmodule;
default = {
host = "0.0.0.0";
port = if config.enableHTTPS then 443 else 80;
};
defaultText = lib.literalExpression ''
{
serverSubmodule =
{ config, ... }:
{
options = commonOptions // {
listen = lib.mkOption {
description = ''
Address and port to listen on.
Setting the port to a value below 1024 will also give the process
the required `CAP_NET_BIND_SERVICE` capability.
'';
type = lib.types.submodule hostPortSubmodule;
default = {
host = "0.0.0.0";
port = if enableHTTPS then 443 else 80;
}
'';
};
port = if config.enableHTTPS then 443 else 80;
};
defaultText = lib.literalExpression ''
{
host = "0.0.0.0";
port = if enableHTTPS then 443 else 80;
}
'';
};
restrictTo = lib.mkOption {
description = ''
Accepted traffic will be forwarded only to this service.
'';
type = lib.types.listOf (lib.types.submodule hostPortSubmodule);
default = [ ];
example = [{
host = "127.0.0.1";
port = 51820;
}];
};
restrictTo = lib.mkOption {
description = ''
Accepted traffic will be forwarded only to this service.
'';
type = lib.types.listOf (lib.types.submodule hostPortSubmodule);
default = [ ];
example = [
{
host = "127.0.0.1";
port = 51820;
}
];
};
enableHTTPS = lib.mkOption {
description = "Use HTTPS for the tunnel server.";
type = lib.types.bool;
default = true;
};
enableHTTPS = lib.mkOption {
description = "Use HTTPS for the tunnel server.";
type = lib.types.bool;
default = true;
};
tlsCertificate = lib.mkOption {
description = ''
TLS certificate to use instead of the hardcoded one in case of HTTPS connections.
Use together with `tlsKey`.
'';
type = lib.types.nullOr lib.types.path;
default = null;
example = "/var/lib/secrets/cert.pem";
};
tlsCertificate = lib.mkOption {
description = ''
TLS certificate to use instead of the hardcoded one in case of HTTPS connections.
Use together with `tlsKey`.
'';
type = lib.types.nullOr lib.types.path;
default = null;
example = "/var/lib/secrets/cert.pem";
};
tlsKey = lib.mkOption {
description = ''
TLS key to use instead of the hardcoded on in case of HTTPS connections.
Use together with `tlsCertificate`.
'';
type = lib.types.nullOr lib.types.path;
default = null;
example = "/var/lib/secrets/key.pem";
};
tlsKey = lib.mkOption {
description = ''
TLS key to use instead of the hardcoded on in case of HTTPS connections.
Use together with `tlsCertificate`.
'';
type = lib.types.nullOr lib.types.path;
default = null;
example = "/var/lib/secrets/key.pem";
};
useACMEHost = lib.mkOption {
description = ''
Use a certificate generated by the NixOS ACME module for the given host.
Note that this will not generate a new certificate - you will need to do so with `security.acme.certs`.
'';
type = lib.types.nullOr lib.types.str;
default = null;
example = "example.com";
};
};
};
clientSubmodule = { config, ... }: {
options = commonOptions // {
connectTo = lib.mkOption {
description = "Server address and port to connect to.";
type = lib.types.str;
example = "https://wstunnel.server.com:8443";
};
localToRemote = lib.mkOption {
description = ''Listen on local and forwards traffic from remote.'';
type = lib.types.listOf (lib.types.str);
default = [ ];
example = [
"tcp://1212:google.com:443"
"unix:///tmp/wstunnel.sock:g.com:443"
];
};
remoteToLocal = lib.mkOption {
description = "Listen on remote and forwards traffic from local. Only tcp is supported";
type = lib.types.listOf lib.types.str;
default = [ ];
example = [
"tcp://1212:google.com:443"
"unix://wstunnel.sock:g.com:443"
];
};
addNetBind = lib.mkEnableOption "Whether add CAP_NET_BIND_SERVICE to the tunnel service, this should be enabled if you want to bind port < 1024";
httpProxy = lib.mkOption {
description = ''
Proxy to use to connect to the wstunnel server (`USER:PASS@HOST:PORT`).
::: {.warning}
Passwords specified here will be world-readable in the Nix store!
To pass a password to the service, point the `environmentFile` option
to a file containing `PROXY_PASSWORD=<your-password-here>` and set
this option to `<user>:$PROXY_PASSWORD@<host>:<port>`.
Note however that this will also locally leak the passwords at
runtime via e.g. /proc/<pid>/cmdline.
:::
'';
type = lib.types.nullOr lib.types.str;
default = null;
};
soMark = lib.mkOption {
description = ''
Mark network packets with the SO_MARK sockoption with the specified value.
Setting this option will also enable the required `CAP_NET_ADMIN` capability
for the systemd service.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
upgradePathPrefix = lib.mkOption {
description = ''
Use a specific HTTP path prefix that will show up in the upgrade
request to the `wstunnel` server.
Useful when running `wstunnel` behind a reverse proxy.
'';
type = lib.types.nullOr lib.types.str;
default = null;
example = "wstunnel";
};
tlsSNI = lib.mkOption {
description = "Use this as the SNI while connecting via TLS. Useful for circumventing hostname-based firewalls.";
type = lib.types.nullOr lib.types.str;
default = null;
};
tlsVerifyCertificate = lib.mkOption {
description = "Whether to verify the TLS certificate of the server. It might be useful to set this to `false` when working with the `tlsSNI` option.";
type = lib.types.bool;
default = true;
};
# The original argument name `websocketPingFrequency` is a misnomer, as the frequency is the inverse of the interval.
websocketPingInterval = lib.mkOption {
description = "Frequency at which the client will send websocket ping to the server.";
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
upgradeCredentials = lib.mkOption {
description = ''
Use these credentials to authenticate during the HTTP upgrade request
(Basic authorization type, `USER:[PASS]`).
::: {.warning}
Passwords specified here will be world-readable in the Nix store!
To pass a password to the service, point the `environmentFile` option
to a file containing `HTTP_PASSWORD=<your-password-here>` and set this
option to `<user>:$HTTP_PASSWORD`.
Note however that this will also locally leak the passwords at runtime
via e.g. /proc/<pid>/cmdline.
:::
'';
type = lib.types.nullOr lib.types.str;
default = null;
};
customHeaders = lib.mkOption {
description = "Custom HTTP headers to send during the upgrade request.";
type = lib.types.attrsOf lib.types.str;
default = { };
example = {
"X-Some-Header" = "some-value";
useACMEHost = lib.mkOption {
description = ''
Use a certificate generated by the NixOS ACME module for the given host.
Note that this will not generate a new certificate - you will need to do so with `security.acme.certs`.
'';
type = lib.types.nullOr lib.types.str;
default = null;
example = "example.com";
};
};
};
clientSubmodule =
{ config, ... }:
{
options = commonOptions // {
connectTo = lib.mkOption {
description = "Server address and port to connect to.";
type = lib.types.str;
example = "https://wstunnel.server.com:8443";
};
localToRemote = lib.mkOption {
description = ''Listen on local and forwards traffic from remote.'';
type = lib.types.listOf (lib.types.str);
default = [ ];
example = [
"tcp://1212:google.com:443"
"unix:///tmp/wstunnel.sock:g.com:443"
];
};
remoteToLocal = lib.mkOption {
description = "Listen on remote and forwards traffic from local. Only tcp is supported";
type = lib.types.listOf lib.types.str;
default = [ ];
example = [
"tcp://1212:google.com:443"
"unix://wstunnel.sock:g.com:443"
];
};
addNetBind = lib.mkEnableOption "Whether add CAP_NET_BIND_SERVICE to the tunnel service, this should be enabled if you want to bind port < 1024";
httpProxy = lib.mkOption {
description = ''
Proxy to use to connect to the wstunnel server (`USER:PASS@HOST:PORT`).
::: {.warning}
Passwords specified here will be world-readable in the Nix store!
To pass a password to the service, point the `environmentFile` option
to a file containing `PROXY_PASSWORD=<your-password-here>` and set
this option to `<user>:$PROXY_PASSWORD@<host>:<port>`.
Note however that this will also locally leak the passwords at
runtime via e.g. /proc/<pid>/cmdline.
:::
'';
type = lib.types.nullOr lib.types.str;
default = null;
};
soMark = lib.mkOption {
description = ''
Mark network packets with the SO_MARK sockoption with the specified value.
Setting this option will also enable the required `CAP_NET_ADMIN` capability
for the systemd service.
'';
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
upgradePathPrefix = lib.mkOption {
description = ''
Use a specific HTTP path prefix that will show up in the upgrade
request to the `wstunnel` server.
Useful when running `wstunnel` behind a reverse proxy.
'';
type = lib.types.nullOr lib.types.str;
default = null;
example = "wstunnel";
};
tlsSNI = lib.mkOption {
description = "Use this as the SNI while connecting via TLS. Useful for circumventing hostname-based firewalls.";
type = lib.types.nullOr lib.types.str;
default = null;
};
tlsVerifyCertificate = lib.mkOption {
description = "Whether to verify the TLS certificate of the server. It might be useful to set this to `false` when working with the `tlsSNI` option.";
type = lib.types.bool;
default = true;
};
# The original argument name `websocketPingFrequency` is a misnomer, as the frequency is the inverse of the interval.
websocketPingInterval = lib.mkOption {
description = "Frequency at which the client will send websocket ping to the server.";
type = lib.types.nullOr lib.types.ints.unsigned;
default = null;
};
upgradeCredentials = lib.mkOption {
description = ''
Use these credentials to authenticate during the HTTP upgrade request
(Basic authorization type, `USER:[PASS]`).
::: {.warning}
Passwords specified here will be world-readable in the Nix store!
To pass a password to the service, point the `environmentFile` option
to a file containing `HTTP_PASSWORD=<your-password-here>` and set this
option to `<user>:$HTTP_PASSWORD`.
Note however that this will also locally leak the passwords at runtime
via e.g. /proc/<pid>/cmdline.
:::
'';
type = lib.types.nullOr lib.types.str;
default = null;
};
customHeaders = lib.mkOption {
description = "Custom HTTP headers to send during the upgrade request.";
type = lib.types.attrsOf lib.types.str;
default = { };
example = {
"X-Some-Header" = "some-value";
};
};
};
};
};
generateServerUnit = name: serverCfg: {
name = "wstunnel-server-${name}";
@ -270,22 +276,25 @@ let
in
{
description = "wstunnel server - ${name}";
requires = [ "network.target" "network-online.target" ];
after = [ "network.target" "network-online.target" ];
requires = [
"network.target"
"network-online.target"
];
after = [
"network.target"
"network-online.target"
];
wantedBy = lib.optional serverCfg.autoStart "multi-user.target";
environment.RUST_LOG = serverCfg.loggingLevel;
serviceConfig = {
Type = "exec";
EnvironmentFile =
lib.optional (serverCfg.environmentFile != null) serverCfg.environmentFile;
EnvironmentFile = lib.optional (serverCfg.environmentFile != null) serverCfg.environmentFile;
DynamicUser = true;
SupplementaryGroups =
lib.optional (serverCfg.useACMEHost != null) certConfig.group;
SupplementaryGroups = lib.optional (serverCfg.useACMEHost != null) certConfig.group;
PrivateTmp = true;
AmbientCapabilities =
lib.optionals (serverCfg.listen.port < 1024) [ "CAP_NET_BIND_SERVICE" ];
AmbientCapabilities = lib.optionals (serverCfg.listen.port < 1024) [ "CAP_NET_BIND_SERVICE" ];
NoNewPrivileges = true;
RestrictNamespaces = "uts ipc pid user cgroup";
ProtectSystem = "strict";
@ -305,19 +314,16 @@ let
script = with serverCfg; ''
${lib.getExe package} \
server \
${lib.cli.toGNUCommandLineShell { } (
lib.recursiveUpdate
{
restrict-to = map hostPortToString restrictTo;
tls-certificate = if useACMEHost != null
then "${certConfig.directory}/fullchain.pem"
else "${tlsCertificate}";
tls-private-key = if useACMEHost != null
then "${certConfig.directory}/key.pem"
else "${tlsKey}";
}
extraArgs
)} \
${
lib.cli.toGNUCommandLineShell { } (
lib.recursiveUpdate {
restrict-to = map hostPortToString restrictTo;
tls-certificate =
if useACMEHost != null then "${certConfig.directory}/fullchain.pem" else "${tlsCertificate}";
tls-private-key = if useACMEHost != null then "${certConfig.directory}/key.pem" else "${tlsKey}";
} extraArgs
)
} \
${lib.escapeShellArg "${if enableHTTPS then "wss" else "ws"}://${hostPortToString listen}"}
'';
};
@ -327,21 +333,26 @@ let
name = "wstunnel-client-${name}";
value = {
description = "wstunnel client - ${name}";
requires = [ "network.target" "network-online.target" ];
after = [ "network.target" "network-online.target" ];
requires = [
"network.target"
"network-online.target"
];
after = [
"network.target"
"network-online.target"
];
wantedBy = lib.optional clientCfg.autoStart "multi-user.target";
environment.RUST_LOG = clientCfg.loggingLevel;
serviceConfig = {
Type = "exec";
EnvironmentFile =
lib.optional (clientCfg.environmentFile != null) clientCfg.environmentFile;
EnvironmentFile = lib.optional (clientCfg.environmentFile != null) clientCfg.environmentFile;
DynamicUser = true;
PrivateTmp = true;
AmbientCapabilities =
(lib.optionals clientCfg.addNetBind [ "CAP_NET_BIND_SERVICE" ]) ++
(lib.optionals (clientCfg.soMark != null) [ "CAP_NET_ADMIN" ]);
(lib.optionals clientCfg.addNetBind [ "CAP_NET_BIND_SERVICE" ])
++ (lib.optionals (clientCfg.soMark != null) [ "CAP_NET_ADMIN" ]);
NoNewPrivileges = true;
RestrictNamespaces = "uts ipc pid user cgroup";
ProtectSystem = "strict";
@ -361,22 +372,22 @@ let
script = with clientCfg; ''
${lib.getExe package} \
client \
${lib.cli.toGNUCommandLineShell { } (
lib.recursiveUpdate
{
local-to-remote = localToRemote;
remote-to-local = remoteToLocal;
http-headers = lib.mapAttrsToList (n: v: "${n}:${v}") customHeaders;
http-proxy = httpProxy;
socket-so-mark = soMark;
http-upgrade-path-prefix = upgradePathPrefix;
tls-sni-override = tlsSNI;
tls-verify-certificate = tlsVerifyCertificate;
websocket-ping-frequency-sec = websocketPingInterval;
http-upgrade-credentials = upgradeCredentials;
}
extraArgs
)} \
${
lib.cli.toGNUCommandLineShell { } (
lib.recursiveUpdate {
local-to-remote = localToRemote;
remote-to-local = remoteToLocal;
http-headers = lib.mapAttrsToList (n: v: "${n}:${v}") customHeaders;
http-proxy = httpProxy;
socket-so-mark = soMark;
http-upgrade-path-prefix = upgradePathPrefix;
tls-sni-override = tlsSNI;
tls-verify-certificate = tlsVerifyCertificate;
websocket-ping-frequency-sec = websocketPingInterval;
http-upgrade-credentials = upgradeCredentials;
} extraArgs
)
} \
${lib.escapeShellArg connectTo}
'';
};
@ -399,10 +410,12 @@ in
enableHTTPS = true;
tlsCertificate = "/var/lib/secrets/fullchain.pem";
tlsKey = "/var/lib/secrets/key.pem";
restrictTo = [{
host = "127.0.0.1";
port = 51820;
}];
restrictTo = [
{
host = "127.0.0.1";
port = 51820;
}
];
};
};
};
@ -429,40 +442,39 @@ in
config = lib.mkIf cfg.enable {
systemd.services =
(lib.mapAttrs' generateServerUnit (lib.filterAttrs (n: v: v.enable) cfg.servers)) //
(lib.mapAttrs' generateClientUnit (lib.filterAttrs (n: v: v.enable) cfg.clients));
(lib.mapAttrs' generateServerUnit (lib.filterAttrs (n: v: v.enable) cfg.servers))
// (lib.mapAttrs' generateClientUnit (lib.filterAttrs (n: v: v.enable) cfg.clients));
assertions =
(lib.mapAttrsToList
(name: serverCfg: {
assertion =
!(serverCfg.useACMEHost != null && serverCfg.tlsCertificate != null);
message = ''
Options services.wstunnel.servers."${name}".useACMEHost and services.wstunnel.servers."${name}".{tlsCertificate, tlsKey} are mutually exclusive.
'';
})
cfg.servers) ++
(lib.mapAttrsToList (name: serverCfg: {
assertion = !(serverCfg.useACMEHost != null && serverCfg.tlsCertificate != null);
message = ''
Options services.wstunnel.servers."${name}".useACMEHost and services.wstunnel.servers."${name}".{tlsCertificate, tlsKey} are mutually exclusive.
'';
}) cfg.servers)
++
(lib.mapAttrsToList
(name: serverCfg: {
(lib.mapAttrsToList (name: serverCfg: {
assertion =
(serverCfg.tlsCertificate == null && serverCfg.tlsKey == null) ||
(serverCfg.tlsCertificate != null && serverCfg.tlsKey != null);
(serverCfg.tlsCertificate == null && serverCfg.tlsKey == null)
|| (serverCfg.tlsCertificate != null && serverCfg.tlsKey != null);
message = ''
services.wstunnel.servers."${name}".tlsCertificate and services.wstunnel.servers."${name}".tlsKey need to be set together.
'';
})
cfg.servers) ++
}) cfg.servers)
++
(lib.mapAttrsToList
(name: clientCfg: {
(lib.mapAttrsToList (name: clientCfg: {
assertion = !(clientCfg.localToRemote == [ ] && clientCfg.remoteToLocal == [ ]);
message = ''
Either one of services.wstunnel.clients."${name}".localToRemote or services.wstunnel.clients."${name}".remoteToLocal must be set.
'';
})
cfg.clients);
}) cfg.clients);
};
meta.maintainers = with lib.maintainers; [ alyaeanyx rvdp neverbehave ];
meta.maintainers = with lib.maintainers; [
alyaeanyx
rvdp
neverbehave
];
}

View File

@ -0,0 +1,301 @@
{
pkgs,
config,
lib,
...
}:
let
cfg = config.services.firefly-iii-data-importer;
user = cfg.user;
group = cfg.group;
defaultUser = "firefly-iii-data-importer";
defaultGroup = "firefly-iii-data-importer";
artisan = "${cfg.package}/artisan";
env-file-values = lib.attrsets.mapAttrs' (
n: v: lib.attrsets.nameValuePair (lib.strings.removeSuffix "_FILE" n) v
) (lib.attrsets.filterAttrs (n: v: lib.strings.hasSuffix "_FILE" n) cfg.settings);
env-nonfile-values = lib.attrsets.filterAttrs (n: v: !lib.strings.hasSuffix "_FILE" n) cfg.settings;
data-importer-maintenance = pkgs.writeShellScript "data-importer-maintenance.sh" ''
set -a
${lib.strings.toShellVars env-nonfile-values}
${lib.strings.concatLines (
lib.attrsets.mapAttrsToList (n: v: "${n}=\"$(< ${v})\"") env-file-values
)}
set +a
${artisan} package:discover
${artisan} cache:clear
${artisan} config:cache
'';
commonServiceConfig = {
Type = "oneshot";
User = user;
Group = group;
StateDirectory = "firefly-iii-data-importer";
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.firefly-iii-data-importer = {
enable = lib.mkEnableOption "Firefly III Data Importer";
user = lib.mkOption {
type = lib.types.str;
default = defaultUser;
description = "User account under which firefly-iii-data-importer runs.";
};
group = lib.mkOption {
type = lib.types.str;
default = if cfg.enableNginx then "nginx" else defaultGroup;
defaultText = "If `services.firefly-iii-data-importer.enableNginx` is true then `nginx` else ${defaultGroup}";
description = ''
Group under which firefly-iii-data-importer 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/firefly-iii-data-importer";
description = ''
The place where firefly-iii data importer stores its state.
'';
};
package = lib.mkOption {
type = lib.types.package;
default = pkgs.firefly-iii-data-importer;
defaultText = lib.literalExpression "pkgs.firefly-iii-data-importer";
description = ''
The firefly-iii-data-importer package served by php-fpm and the webserver of choice.
This option can be used to point the webserver to the correct root. It
may also be used to set the package to a different version, say a
development version.
'';
apply =
firefly-iii-data-importer:
firefly-iii-data-importer.override (prev: {
dataDir = cfg.dataDir;
});
};
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 firefly-iii data importer. If not enabled, then you may use
`''${config.services.firefly-iii-data-importer.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 firefly-iii-data-importer to be served. If you have
enabled nginx using `services.firefly-iii-data-importer.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 = lib.literalExpression ''
{
"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 Firefly III Data Importer PHP pool. See the documentation on <literal>php-fpm.conf</literal>
for details on configuration directives.
'';
};
settings = lib.mkOption {
default = { };
description = ''
Options for firefly-iii data importer configuration. Refer to
<https://github.com/firefly-iii/data-importer/blob/main/.env.example> for
details on supported values. All <option>_FILE values supported by
upstream are supported here.
APP_URL will be the same as `services.firefly-iii-data-importer.virtualHost` if the
former is unset in `services.firefly-iii-data-importer.settings`.
'';
example = lib.literalExpression ''
{
APP_ENV = "local";
LOG_CHANNEL = "syslog";
FIREFLY_III_ACCESS_TOKEN= = "/var/secrets/firefly-iii-access-token.txt";
}
'';
type = lib.types.submodule {
freeformType = lib.types.attrsOf (
lib.types.oneOf [
lib.types.str
lib.types.int
lib.types.bool
]
);
};
};
};
config = lib.mkIf cfg.enable {
services.phpfpm.pools.firefly-iii-data-importer = {
inherit user group;
phpPackage = cfg.package.phpPackage;
phpOptions = ''
log_errors = on
'';
settings = {
"listen.mode" = "0660";
"listen.owner" = user;
"listen.group" = 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.firefly-iii-data-importer-setup = {
requiredBy = [ "phpfpm-firefly-iii-data-importer.service" ];
before = [ "phpfpm-firefly-iii-data-importer.service" ];
serviceConfig = {
ExecStart = data-importer-maintenance;
RemainAfterExit = true;
} // commonServiceConfig;
unitConfig.JoinsNamespaceOf = "phpfpm-firefly-iii-data-importer.service";
restartTriggers = [ cfg.package ];
};
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.firefly-iii-data-importer.socket};
'';
};
};
};
};
systemd.tmpfiles.settings."10-firefly-iii-data-importer" =
lib.attrsets.genAttrs
[
"${cfg.dataDir}/storage"
"${cfg.dataDir}/storage/app"
"${cfg.dataDir}/storage/app/public"
"${cfg.dataDir}/storage/configurations"
"${cfg.dataDir}/storage/conversion-routines"
"${cfg.dataDir}/storage/debugbar"
"${cfg.dataDir}/storage/framework"
"${cfg.dataDir}/storage/framework/cache"
"${cfg.dataDir}/storage/framework/sessions"
"${cfg.dataDir}/storage/framework/testing"
"${cfg.dataDir}/storage/framework/views"
"${cfg.dataDir}/storage/jobs"
"${cfg.dataDir}/storage/logs"
"${cfg.dataDir}/storage/submission-routines"
"${cfg.dataDir}/storage/uploads"
"${cfg.dataDir}/cache"
]
(n: {
d = {
group = group;
mode = "0710";
user = user;
};
})
// {
"${cfg.dataDir}".d = {
group = group;
mode = "0700";
user = user;
};
};
users = {
users = lib.mkIf (user == defaultUser) {
${defaultUser} = {
description = "Firefly-iii Data Importer service user";
inherit group;
isSystemUser = true;
home = cfg.dataDir;
};
};
groups = lib.mkIf (group == defaultGroup) { ${defaultGroup} = { }; };
};
};
}

View File

@ -135,6 +135,8 @@ in
default = "freshrss";
description = ''
Name of the nginx virtualhost to use and setup. If null, do not setup any virtualhost.
You may need to configure the virtualhost further through services.nginx.virtualHosts.<virtualhost>,
for example to enable SSL.
'';
};

View File

@ -47,18 +47,20 @@ in
environment = lib.mapAttrs (_: toString) cfg.environment;
# following https://github.com/Stirling-Tools/Stirling-PDF#locally
path = with pkgs; [
unpaper
libreoffice
ocrmypdf
poppler_utils
unoconv
opencv
pngquant
tesseract
python3Packages.weasyprint
calibre
];
path =
with pkgs;
[
unpaper
libreoffice
ocrmypdf
poppler_utils
unoconv
opencv
pngquant
tesseract
python3Packages.weasyprint
]
++ lib.optional (cfg.environment.INSTALL_BOOK_AND_ADVANCED_HTML_OPS or "false" == "true") calibre;
wantedBy = [ "multi-user.target" ];

View File

@ -0,0 +1,164 @@
{
lib,
pkgs,
config,
...
}:
let
cfg = config.services.wakapi;
settingsFormat = pkgs.formats.yaml { };
settingsFile = settingsFormat.generate "wakapi-settings" cfg.settings;
inherit (lib)
getExe
mkOption
mkEnableOption
mkPackageOption
types
mkIf
optional
mkMerge
singleton
;
in
{
options.services.wakapi = {
enable = mkEnableOption "Wakapi";
package = mkPackageOption pkgs "wakapi" { };
settings = mkOption {
inherit (settingsFormat) type;
default = { };
description = ''
Settings for Wakapi.
See [config.default.yml](https://github.com/muety/wakapi/blob/master/config.default.yml) for a list of all possible options.
'';
};
passwordSalt = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The password salt to use for Wakapi.
'';
};
passwordSaltFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
The path to a file containing the password salt to use for Wakapi.
'';
};
smtpPassword = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The password used for the smtp mailed to used by Wakapi.
'';
};
smtpPasswordFile = mkOption {
type = types.nullOr types.path;
default = null;
description = ''
The path to a file containing the password for the smtp mailer used by Wakapi.
'';
};
};
config = mkIf cfg.enable {
systemd.services.wakapi = {
description = "Wakapi (self-hosted WakaTime-compatible backend)";
wants = [
"network-online.target"
] ++ optional (cfg.settings.db.dialect == "postgres") "postgresql.service";
after = [
"network-online.target"
] ++ optional (cfg.settings.db.dialect == "postgres") "postgresql.service";
wantedBy = [ "multi-user.target" ];
script = ''
exec ${getExe cfg.package} -config ${settingsFile}
'';
serviceConfig = {
Environment = mkMerge [
(mkIf (cfg.passwordSalt != null) "WAKAPI_PASSWORD_SALT=${cfg.passwordSalt}")
(mkIf (cfg.smtpPassword != null) "WAKAPI_MAIL_SMTP_PASS=${cfg.smtpPassword}")
];
EnvironmentFile = [
(optional (cfg.passwordSaltFile != null) cfg.passwordSaltFile)
(optional (cfg.smtpPasswordFile != null) cfg.smtpPasswordFile)
];
User = config.users.users.wakapi.name;
Group = config.users.users.wakapi.group;
DynamicUser = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
StateDirectoryMode = "0700";
Restart = "always";
};
};
services.wakapi.settings = {
env = lib.mkDefault "production";
};
assertions = [
{
assertion = cfg.passwordSalt != null || cfg.passwordSaltFile != null;
message = "Either `services.wakapi.passwordSalt` or `services.wakapi.passwordSaltFile` must be set.";
}
{
assertion = cfg.passwordSalt != null -> cfg.passwordSaltFile != null;
message = "Both `services.wakapi.passwordSalt` `services.wakapi.passwordSaltFile` should not be set at the same time.";
}
{
assertion = cfg.smtpPassword != null -> cfg.smtpPasswordFile != null;
message = "Both `services.wakapi.smtpPassword` `services.wakapi.smtpPasswordFile` should not be set at the same time.";
}
];
users = {
users.wakapi = {
group = "wakapi";
createHome = false;
isSystemUser = true;
};
groups.wakapi = { };
};
services.postgresql = mkIf (cfg.settings.db.dialect == "postgres") {
enable = true;
ensureDatabases = singleton cfg.settings.db.name;
ensureUsers = singleton {
name = cfg.settings.db.user;
ensureDBOwnership = true;
};
authentication = ''
host ${cfg.settings.db.name} ${cfg.settings.db.user} 127.0.0.1/32 trust
'';
};
};
meta.maintainers = with lib.maintainers; [ isabelroses ];
}

View File

@ -33,6 +33,7 @@ CAN_TOUCH_EFI_VARIABLES = "@canTouchEfiVariables@"
GRACEFUL = "@graceful@"
COPY_EXTRA_FILES = "@copyExtraFiles@"
CHECK_MOUNTPOINTS = "@checkMountpoints@"
STORE_DIR = "@storeDir@"
@dataclass
class BootSpec:
@ -106,7 +107,7 @@ def write_loader_conf(profile: str | None, generation: int, specialisation: str
if not EDITOR:
f.write("editor 0\n")
if REBOOT_FOR_BITLOCKER:
f.write("reboot-for-bitlocker yes\n");
f.write("reboot-for-bitlocker yes\n")
f.write(f"console-mode {CONSOLE_MODE}\n")
f.flush()
os.fsync(f.fileno())
@ -150,12 +151,13 @@ def bootspec_from_json(bootspec_json: dict[str, Any]) -> BootSpec:
def copy_from_file(file: str, dry_run: bool = False) -> str:
store_file_path = os.path.realpath(file)
suffix = os.path.basename(store_file_path)
store_dir = os.path.basename(os.path.dirname(store_file_path))
efi_file_path = f"{NIXOS_DIR}/{store_dir}-{suffix}.efi"
store_subdir = os.path.relpath(store_file_path, start=STORE_DIR).split(os.path.sep)[0]
efi_file_path = f"{NIXOS_DIR}/{suffix}.efi" if suffix == store_subdir else f"{NIXOS_DIR}/{store_subdir}-{suffix}.efi"
if not dry_run:
copy_if_not_exists(store_file_path, f"{BOOT_MOUNT_POINT}{efi_file_path}")
return efi_file_path
def write_entry(profile: str | None, generation: int, specialisation: str | None,
machine_id: str, bootspec: BootSpec, current: bool) -> None:
if specialisation:

View File

@ -28,6 +28,8 @@ let
isExecutable = true;
inherit (builtins) storeDir;
inherit (pkgs) python3;
systemd = config.systemd.package;

View File

@ -23,6 +23,8 @@ in
'';
};
unprivilegedContainers = lib.mkEnableOption "support for unprivileged users to launch containers";
systemConfig =
lib.mkOption {
type = lib.types.lines;
@ -53,6 +55,15 @@ in
administration access in LXC. See {manpage}`lxc-usernet(5)`.
'';
};
bridgeConfig =
lib.mkOption {
type = lib.types.lines;
default = "";
description = ''
This is the config file for override lxc-net bridge default settings.
'';
};
};
###### implementation
@ -62,6 +73,8 @@ in
environment.etc."lxc/lxc.conf".text = cfg.systemConfig;
environment.etc."lxc/lxc-usernet".text = cfg.usernetConfig;
environment.etc."lxc/default.conf".text = cfg.defaultConfig;
environment.etc."lxc/lxc-net".text = cfg.bridgeConfig;
environment.pathsToLink = [ "/share/lxc" ];
systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
security.apparmor.packages = [ cfg.package ];
@ -73,5 +86,30 @@ in
include ${cfg.package}/etc/apparmor.d/lxc-containers
'';
};
# We don't need the `lxc-user` group, unless the unprivileged containers are enabled.
users.groups = lib.mkIf cfg.unprivilegedContainers { lxc-user = {}; };
# `lxc-user-nic` needs suid to attach to bridge for unpriv containers.
security.wrappers = lib.mkIf cfg.unprivilegedContainers {
lxcUserNet = {
source = "${pkgs.lxc}/libexec/lxc/lxc-user-nic";
setuid = true;
owner = "root";
group = "lxc-user";
program = "lxc-user-nic";
permissions = "u+rx,g+x,o-rx";
};
};
# Add lxc-net service if unpriv mode is enabled.
systemd.packages = lib.mkIf cfg.unprivilegedContainers [ pkgs.lxc ];
systemd.services = lib.mkIf cfg.unprivilegedContainers {
lxc-net = {
enable = true;
wantedBy = [ "multi-user.target" ];
path = [ pkgs.iproute2 pkgs.iptables pkgs.getent pkgs.dnsmasq ];
};
};
};
}

View File

@ -326,6 +326,7 @@ in {
filesender = handleTest ./filesender.nix {};
filesystems-overlayfs = runTest ./filesystems-overlayfs.nix;
firefly-iii = handleTest ./firefly-iii.nix {};
firefly-iii-data-importer = handleTest ./firefly-iii-data-importer.nix {};
firefox = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox; };
firefox-beta = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-beta; };
firefox-devedition = handleTest ./firefox.nix { firefoxPackage = pkgs.firefox-devedition; };
@ -538,6 +539,7 @@ in {
loki = handleTest ./loki.nix {};
luks = handleTest ./luks.nix {};
lvm2 = handleTest ./lvm2 {};
lxc = handleTest ./lxc {};
lxd = pkgs.recurseIntoAttrs (handleTest ./lxd { inherit handleTestOn; });
lxd-image-server = handleTest ./lxd-image-server.nix {};
#logstash = handleTest ./logstash.nix {};

View File

@ -0,0 +1,27 @@
import ./make-test-python.nix (
{ lib, ... }:
{
name = "firefly-iii-data-importer";
meta.maintainers = [ lib.maintainers.savyajha ];
nodes.dataImporter =
{ ... }:
{
services.firefly-iii-data-importer = {
enable = true;
enableNginx = true;
settings = {
LOG_CHANNEL = "stdout";
USE_CACHE = true;
};
};
};
testScript = ''
dataImporter.wait_for_unit("phpfpm-firefly-iii-data-importer.service")
dataImporter.wait_for_unit("nginx.service")
dataImporter.succeed("curl -fvvv -Ls http://localhost/token | grep 'Firefly III Data Import Tool'")
'';
}
)

View File

@ -11,8 +11,8 @@ let
extra;
};
container-image-metadata = releases.incusContainerMeta.${pkgs.stdenv.hostPlatform.system};
container-image-rootfs = releases.incusContainerImage.${pkgs.stdenv.hostPlatform.system};
container-image-metadata = "${releases.incusContainerMeta.${pkgs.stdenv.hostPlatform.system}}/tarball/nixos-system-${pkgs.stdenv.hostPlatform.system}.tar.xz";
container-image-rootfs = "${releases.incusContainerImage.${pkgs.stdenv.hostPlatform.system}}/nixos-lxc-image-${pkgs.stdenv.hostPlatform.system}.squashfs";
in
{
inherit name;
@ -61,7 +61,7 @@ in
machine.succeed("incus admin init --minimal")
with subtest("Container image can be imported"):
machine.succeed("incus image import ${container-image-metadata}/*/*.tar.xz ${container-image-rootfs} --alias nixos")
machine.succeed("incus image import ${container-image-metadata} ${container-image-rootfs} --alias nixos")
with subtest("Container can be launched and managed"):
machine.succeed("incus launch nixos container")

View File

@ -16,8 +16,12 @@ import ../make-test-python.nix (
};
};
container-image-metadata = releases.incusContainerMeta.${pkgs.stdenv.hostPlatform.system};
container-image-rootfs = releases.incusContainerImage.${pkgs.stdenv.hostPlatform.system};
container-image-metadata = "${
releases.incusContainerMeta.${pkgs.stdenv.hostPlatform.system}
}/tarball/nixos-system-${pkgs.stdenv.hostPlatform.system}.tar.xz";
container-image-rootfs = "${
releases.incusContainerImage.${pkgs.stdenv.hostPlatform.system}
}/nixos-lxc-image-${pkgs.stdenv.hostPlatform.system}.squashfs";
in
{
name = "incusd-options";
@ -87,7 +91,7 @@ import ../make-test-python.nix (
machine.wait_for_unit("incus-preseed.service")
with subtest("Container image can be imported"):
machine.succeed("incus image import ${container-image-metadata}/*/*.tar.xz ${container-image-rootfs} --alias nixos")
machine.succeed("incus image import ${container-image-metadata} ${container-image-rootfs} --alias nixos")
with subtest("Container can be launched and managed"):
machine.succeed("incus launch nixos container")

124
nixos/tests/lxc/default.nix Normal file
View File

@ -0,0 +1,124 @@
import ../make-test-python.nix (
{ pkgs, lib, ... }:
let
releases = import ../../release.nix {
configuration = {
# Building documentation makes the test unnecessarily take a longer time:
documentation.enable = lib.mkForce false;
};
};
lxc-image-metadata = releases.lxdContainerMeta.${pkgs.stdenv.hostPlatform.system};
lxc-image-rootfs = releases.lxdContainerImage.${pkgs.stdenv.hostPlatform.system};
in
{
name = "lxc-container-unprivileged";
meta = {
maintainers = lib.teams.lxc.members;
};
nodes.machine =
{ lib, pkgs, ... }:
{
virtualisation = {
diskSize = 6144;
cores = 2;
memorySize = 512;
writableStore = true;
lxc = {
enable = true;
unprivilegedContainers = true;
systemConfig = ''
lxc.lxcpath = /tmp/lxc
'';
defaultConfig = ''
lxc.net.0.type = veth
lxc.net.0.link = lxcbr0
lxc.net.0.flags = up
lxc.net.0.hwaddr = 00:16:3e:xx:xx:xx
lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536
'';
# Permit user alice to connect to bridge
usernetConfig = ''
@lxc-user veth lxcbr0 10
'';
bridgeConfig = ''
LXC_IPV6_ADDR=""
LXC_IPV6_MASK=""
LXC_IPV6_NETWORK=""
LXC_IPV6_NAT="false"
'';
};
};
# Needed for lxc
environment.systemPackages = with pkgs; [
pkgs.wget
pkgs.dnsmasq
];
# Create user for test
users.users.alice = {
isNormalUser = true;
password = "test";
description = "Lxc unprivileged user with access to lxcbr0";
extraGroups = [ "lxc-user" ];
subGidRanges = [
{
startGid = 100000;
count = 65536;
}
];
subUidRanges = [
{
startUid = 100000;
count = 65536;
}
];
};
users.users.bob = {
isNormalUser = true;
password = "test";
description = "Lxc unprivileged user without access to lxcbr0";
subGidRanges = [
{
startGid = 100000;
count = 65536;
}
];
subUidRanges = [
{
startUid = 100000;
count = 65536;
}
];
};
};
testScript = ''
machine.wait_for_unit("lxc-net.service")
# Copy config files for alice
machine.execute("su -- alice -c 'mkdir -p ~/.config/lxc'")
machine.execute("su -- alice -c 'cp /etc/lxc/default.conf ~/.config/lxc/'")
machine.execute("su -- alice -c 'cp /etc/lxc/lxc.conf ~/.config/lxc/'")
machine.succeed("su -- alice -c 'lxc-create -t local -n test -- --metadata ${lxc-image-metadata}/*/*.tar.xz --fstree ${lxc-image-rootfs}/*/*.tar.xz'")
machine.succeed("su -- alice -c 'lxc-start test'")
machine.succeed("su -- alice -c 'lxc-stop test'")
# Copy config files for bob
machine.execute("su -- bob -c 'mkdir -p ~/.config/lxc'")
machine.execute("su -- bob -c 'cp /etc/lxc/default.conf ~/.config/lxc/'")
machine.execute("su -- bob -c 'cp /etc/lxc/lxc.conf ~/.config/lxc/'")
machine.fail("su -- bob -c 'lxc-start test'")
'';
}
)

View File

@ -64,7 +64,7 @@ in {
with subtest("Squashfs image is functional"):
machine.succeed(
"lxc image import ${lxd-image-metadata}/*/*.tar.xz ${lxd-image-rootfs-squashfs} --alias nixos-squashfs"
"lxc image import ${lxd-image-metadata}/*/*.tar.xz ${lxd-image-rootfs-squashfs}/nixos-lxc-image-${pkgs.stdenv.hostPlatform.system}.squashfs --alias nixos-squashfs"
)
machine.succeed("lxc launch nixos-squashfs container")
with machine.nested("Waiting for instance to start and be usable"):

View File

@ -200,7 +200,7 @@ in
)
'' + pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isAarch64 ''
machine.succeed(
"grep 'devicetree .*dummy' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
r"grep 'devicetree /EFI/nixos/[a-z0-9]\{32\}.*dummy' /boot/loader/entries/nixos-generation-1-specialisation-something.conf"
)
'';
};

View File

@ -7,7 +7,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }: {
nodes.machine = { pkgs, ... }: {
environment.systemPackages = with pkgs; [
glxinfo
mesa-demos
procps # for `pkill`, `pidof` in the test
scrot # for screenshotting Xorg
turbovnc

View File

@ -60,37 +60,34 @@ in
clients.my-client = {
autoStart = false;
connectTo = "wss://${domain}:443";
localToRemote = [
"tcp://8080:localhost:2080"
];
remoteToLocal = [
"tcp://2081:localhost:8081"
];
localToRemote = [ "tcp://8080:localhost:2080" ];
remoteToLocal = [ "tcp://2081:localhost:8081" ];
};
};
};
};
testScript = /* python */ ''
start_all()
server.wait_for_unit("wstunnel-server-my-server.service")
client.wait_for_open_port(443, "10.0.0.1")
testScript = # python
''
start_all()
server.wait_for_unit("wstunnel-server-my-server.service")
client.wait_for_open_port(443, "10.0.0.1")
client.systemctl("start wstunnel-client-my-client.service")
client.wait_for_unit("wstunnel-client-my-client.service")
client.systemctl("start wstunnel-client-my-client.service")
client.wait_for_unit("wstunnel-client-my-client.service")
with subtest("connection from client to server"):
server.succeed("nc -l 2080 >/tmp/msg &")
client.sleep(1)
client.succeed('nc -w1 localhost 8080 <<<"Hello from client"')
server.succeed('grep "Hello from client" /tmp/msg')
with subtest("connection from client to server"):
server.succeed("nc -l 2080 >/tmp/msg &")
client.sleep(1)
client.succeed('nc -w1 localhost 8080 <<<"Hello from client"')
server.succeed('grep "Hello from client" /tmp/msg')
with subtest("connection from server to client"):
client.succeed("nc -l 8081 >/tmp/msg &")
server.sleep(1)
server.succeed('nc -w1 localhost 2081 <<<"Hello from server"')
client.succeed('grep "Hello from server" /tmp/msg')
with subtest("connection from server to client"):
client.succeed("nc -l 8081 >/tmp/msg &")
server.sleep(1)
server.succeed('nc -w1 localhost 2081 <<<"Hello from server"')
client.succeed('grep "Hello from server" /tmp/msg')
client.systemctl("stop wstunnel-client-my-client.service")
'';
client.systemctl("stop wstunnel-client-my-client.service")
'';
}

View File

@ -33,13 +33,13 @@ stdenv.mkDerivation (finalAttrs: {
ELECTRON_SKIP_BINARY_DOWNLOAD = 1;
postBuild = lib.optionalString stdenv.isDarwin ''
cp -R ${electron}/Applications/Electron.app Electron.app
cp -R ${electron.dist}/Electron.app Electron.app
chmod -R u+w Electron.app
'' + ''
pnpm build
./node_modules/.bin/electron-builder \
--dir \
-c.electronDist=${if stdenv.isDarwin then "." else "${electron}/libexec/electron"} \
-c.electronDist=${if stdenv.isDarwin then "." else electron.dist} \
-c.electronVersion=${electron.version}
'';

View File

@ -13,7 +13,6 @@
, file
, fontsConf
, git
, glxinfo
, gnugrep
, gnused
, gnutar
@ -30,6 +29,7 @@
, libX11
, libxcb
, libxkbcommon
, mesa-demos
, xcbutilwm
, xcbutilrenderutil
, xcbutilkeysyms
@ -107,7 +107,7 @@ let
# For Android emulator
file
glxinfo
mesa-demos
pciutils
setxkbmap

View File

@ -1,7 +1,7 @@
{
lib,
consult,
embark,
embark-consult,
fetchFromGitHub,
forge,
gh,
@ -12,24 +12,26 @@
melpaBuild {
pname = "consult-gh";
version = "1.0-unstable-2024-08-11";
version = "1.0-unstable-2024-08-24";
src = fetchFromGitHub {
owner = "armindarvish";
repo = "consult-gh";
rev = "640d4b9c71aa6dfff4f29c0207cc02316f1d61c8";
hash = "sha256-hFHex4cUAP1U5aK1bfa+va1jiWS8tRqtnMGxr17NWio=";
rev = "b1d85d179438e4b6469e1b78906a7dde8f07c822";
hash = "sha256-VmxuXvO0nl0h9IKU+XWfjW90KG/1B+qHoOVhvYJ8XTs=";
};
packageRequires = [
consult
embark
embark-consult
forge
markdown-mode
];
propagatedUserEnvPkgs = [ gh ];
ignoreCompilationError = false;
passthru.updateScript = unstableGitUpdater { };
meta = {

View File

@ -10,16 +10,16 @@ let
in
rustPlatform.buildRustPackage {
pname = "lspce-module";
version = "1.1.0-unstable-2024-07-14";
version = "1.1.0-unstable-2024-07-29";
src = fetchFromGitHub {
owner = "zbelial";
repo = "lspce";
rev = "fd320476df89cfd5d10f1b70303c891d3b1e3c81";
hash = "sha256-KnERYq/CvJhJIdQkpH/m82t9KFMapPl+CyZkYyujslU=";
rev = "e954e4d77aeb45deb14182631f3d5aa9bcc9e587";
hash = "sha256-9AUffkdgvVbHRIrHQPVl36plIfGxf3vsN9JCuFe0P6Q=";
};
cargoHash = "sha256-I2OobRu1hc6xc4bRrIO1FImPYBbFy1jXPcTsivbbskk=";
cargoHash = "sha256-wrrdXX/rEVxmHdyblm4I9iHD3bPoDd1KlBe3ODeGFeM=";
checkFlags = [
# flaky test

View File

@ -1,77 +0,0 @@
{ lib
, python3
, fetchFromGitHub
, meson
, ninja
, gettext
, appstream
, appstream-glib
, wrapGAppsHook4
, desktop-file-utils
, gobject-introspection
, gtk4
, gtksourceview5
, libadwaita
, libportal
, librsvg
, poppler_gi
, webkitgtk_6_0
}:
python3.pkgs.buildPythonApplication rec {
pname = "setzer";
version = "65";
src = fetchFromGitHub {
owner = "cvfosammmm";
repo = "Setzer";
rev = "v${version}";
hash = "sha256-5Hpj/RkD11bNcr9/gQG0Y7BNMsh1BGZQiN4IMbI4osc=";
};
format = "other";
nativeBuildInputs = [
meson
ninja
gettext
appstream # for appstreamcli
appstream-glib
wrapGAppsHook4
desktop-file-utils
gobject-introspection
];
buildInputs = [
gtk4
gtksourceview5
libadwaita
libportal
librsvg
poppler_gi
webkitgtk_6_0
];
propagatedBuildInputs = with python3.pkgs; [
bibtexparser
numpy
pdfminer-six
pexpect
pillow
pycairo
pygobject3
pyxdg
];
checkPhase = ''
meson test --print-errorlogs
'';
meta = with lib; {
description = "LaTeX editor written in Python with Gtk";
mainProgram = "setzer";
homepage = src.meta.homepage;
license = licenses.gpl3Plus;
maintainers = with maintainers; [ dotlambda ];
};
}

View File

@ -4851,8 +4851,8 @@ let
mktplcRef = {
name = "uiua-vscode";
publisher = "uiua-lang";
version = "0.0.52";
hash = "sha256-zFtu3AYnDxb/aMtkpiaItQtwLpynTVbSRGuqKv3SueM=";
version = "0.0.53";
hash = "sha256-5CHAX1jGyJ2VVEBTh5G1JM8+L9paryBa2zJoTkZ+G7Q=";
};
meta = {
description = "VSCode language extension for Uiua";

View File

@ -23,6 +23,12 @@
libslirp,
wayland,
wayland-scanner,
libsndfile,
flac,
libogg,
libvorbis,
libopus,
libmpg123,
enableDynarec ? with stdenv.hostPlatform; isx86 || isAarch,
enableNewDynarec ? enableDynarec && stdenv.hostPlatform.isAarch,
@ -34,13 +40,13 @@
stdenv.mkDerivation (finalAttrs: {
pname = "86Box";
version = "4.1.1";
version = "4.2";
src = fetchFromGitHub {
owner = "86Box";
repo = "86Box";
rev = "v${finalAttrs.version}";
hash = "sha256-ioE0EVIXv/biXXvLqwhmtZ/RJM0nLqcE+i+CU+WXBY4=";
hash = "sha256-hXupMQ+i27sw3XOweZGatdRCUlp7weGR/PqCLAw/8fo=";
};
patches = [ ./darwin.patch ];
@ -75,6 +81,12 @@ stdenv.mkDerivation (finalAttrs: {
libslirp
qt5.qtbase
qt5.qttools
libsndfile
flac.dev
libogg.dev
libvorbis.dev
libopus.dev
libmpg123.dev
]
++ lib.optional stdenv.isLinux alsa-lib
++ lib.optional enableWayland wayland
@ -107,7 +119,7 @@ stdenv.mkDerivation (finalAttrs: {
owner = "86Box";
repo = "roms";
rev = "v${finalAttrs.version}";
hash = "sha256-58nNTOLund/KeDlNwzwwihjFVigs/P0K8SN07zExE2c=";
hash = "sha256-WdQebSBuw2Wtz8ggMnGuxGoi2EKtNub3S8JKa6ZmdU8=";
};
updateScript = ./update.sh;
};

View File

@ -0,0 +1,68 @@
# RetroArch
This directory includes [RetroArch](https://www.retroarch.com/), [libretro
cores](https://docs.libretro.com/guides/core-list/) and related packages.
## Adding new cores
The basic steps to add a new core are:
1. Add the core repository to [update_cores.py](./update_cores.py) inside the
`CORES` map.
- The minimum required parameter is `repo`
- If the repository owner is not `libretro`, set `owner` parameter
- If the core needs submodules, set `fetch_submodules` parameter to `True`
- To pin the core to a specific release, set `rev` parameter
2. Run `./pkgs/applications/emulators/retroarch/update_cores.py <emulator>` to
generate [`hashes.json`](./hashes.json) file
3. Add your new core to [`cores.nix`](./cores.nix) file, using
[`mkLibretroCore`](./mkLibretroCore.nix) function
- In general, the attribute name should be the same as the repo name, unless
there is a good reason not to
- Check the core repo and [Libretro
documentation](https://docs.libretro.com/) for the core you're trying to add
for instructions on how to build
- Also check the examples inside [`cores.nix`](./cores.nix)
- If your core is recently released, there is a good chance that you may
need to update [`libretro-core-info`](./libretro-core-info.nix) for things
to work inside RetroArch
4. Try to build your core with `nix-build -A libretro.<core>`
## Updating cores
Just run:
```console
# From the root of your nixpkgs directory
./pkgs/applications/emulators/retroarch/update_cores.nix
```
Keep in mind that because of the huge amount of cores that we package here, it
is recommended to set `GITHUB_TOKEN` to your GitHub's [Personal Access
Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
(PAT), otherwise the update will probably fail due to GitHub's API rate limit.
## Using RetroArch with cores
To create a custom RetroArch derivation with the cores you want (instead of
using `retroarchFull` that includes all cores), you can use `.override` like
this:
```nix
{ pkgs, ... }:
let
retroarchWithCores = (pkgs.retroarch.override {
cores = with pkgs.libretro; [
bsnes
mgba
quicknes
];
});
in
{
environment.systemPackages = [
retroarchWithCores
];
}
```

View File

@ -63,14 +63,14 @@ stdenv.mkDerivation rec {
runHook preBuild
'' + lib.optionalString stdenv.isDarwin ''
cp -R ${electron}/Applications/Electron.app Electron.app
cp -R ${electron.dist}/Electron.app Electron.app
chmod -R u+w Electron.app
export CSC_IDENTITY_AUTO_DISCOVERY=false
sed -i "/afterSign/d" electron-builder-linux-mac.json
'' + ''
yarn --offline run electron-builder --dir \
${if stdenv.isDarwin then "--config electron-builder-linux-mac.json" else ""} \
-c.electronDist=${if stdenv.isDarwin then "." else "${electron}/libexec/electron"} \
${lib.optionalString stdenv.isDarwin "--config electron-builder-linux-mac.json"} \
-c.electronDist=${if stdenv.isDarwin then "." else electron.dist} \
-c.electronVersion=${electron.version}
runHook postBuild

View File

@ -6,7 +6,7 @@
, kauth
, libdrm
, hwdata
, glxinfo
, mesa-demos
, polkit
, procps
, pugixml
@ -46,7 +46,7 @@ stdenv.mkDerivation rec{
karchive
kauth
libdrm
glxinfo
mesa-demos
polkit
procps
pugixml
@ -68,7 +68,7 @@ stdenv.mkDerivation rec{
"-DPOLKIT_POLICY_INSTALL_DIR=${placeholder "out"}/share/polkit-1/actions"
];
runtimeDeps = [ hwdata glxinfo vulkan-tools util-linux procps ];
runtimeDeps = [ hwdata mesa-demos vulkan-tools util-linux procps ];
binPath = lib.makeBinPath runtimeDeps;
dontWrapQtApps = true;

View File

@ -12,7 +12,7 @@
, wrapGAppsHook4
, gdk-pixbuf
, lsb-release
, glxinfo
, mesa-demos
, vdpauinfo
, clinfo
}:
@ -55,7 +55,7 @@ python3.pkgs.buildPythonApplication rec {
postFixup = ''
makeWrapper ${python3.interpreter} $out/bin/gpu-viewer \
--prefix PATH : "${lib.makeBinPath [ clinfo glxinfo lsb-release vdpauinfo vulkan-tools ]}" \
--prefix PATH : "${lib.makeBinPath [ clinfo lsb-release mesa-demos vdpauinfo vulkan-tools ]}" \
--add-flags "$out/share/gpu-viewer/Files/GPUViewer.py" \
--prefix PYTHONPATH : "$PYTHONPATH" \
--chdir "$out/share/gpu-viewer/Files" \

View File

@ -43,7 +43,7 @@ stdenv.mkDerivation rec {
yarnBuildScript = "electron-builder";
yarnBuildFlags = [
"--dir"
"-c.electronDist=${electron}/libexec/electron"
"-c.electronDist=${electron.dist}"
"-c.electronVersion=${electron.version}"
];

View File

@ -39,7 +39,7 @@
, xrandr
, pciutils
, psmisc
, glxinfo
, mesa-demos
, vulkan-tools
, xboxdrv
, pulseaudio
@ -58,7 +58,7 @@ let
xrandr
pciutils
psmisc
glxinfo
mesa-demos
vulkan-tools
xboxdrv
pulseaudio

View File

@ -172,6 +172,46 @@ in
};
};
firmwareupdater = buildPlugin rec {
pname = "firmwareupdater";
version = "1.14.0";
src = fetchFromGitHub {
owner = "OctoPrint";
repo = "OctoPrint-FirmwareUpdater";
rev = version;
sha256 = "sha256-CUNjM/IJJS/lqccZ2B0mDOzv3k8AgmDreA/X9wNJ7iY=";
};
propagatedBuildInputs = with super; [ pyserial ];
meta = with lib; {
description = "Printer Firmware Updater";
homepage = "https://github.com/OctoPrint/OctoPrint-FirmwareUpdater";
license = licenses.agpl3Only;
maintainers = with maintainers; [ tri-ler ];
};
};
fullscreen = buildPlugin rec {
pname = "fullscreen";
version = "0.0.6";
src = fetchFromGitHub {
owner = "BillyBlaze";
repo = "OctoPrint-FullScreen";
rev = version;
sha256 = "sha256-Z8twpj+gqgbiWWxNd9I9qflEAln5Obpb3cn34KwSc5A=";
};
meta = with lib; {
description = "Open webcam in fullscreen mode";
homepage = "https://github.com/BillyBlaze/OctoPrint-FullScreen";
license = licenses.agpl3Only;
maintainers = with maintainers; [ tri-ler ];
};
};
gcodeeditor = buildPlugin rec {
pname = "gcodeeditor";
version = "0.2.12";
@ -231,15 +271,102 @@ in
};
};
mqttchambertemperature = buildPlugin rec {
pname = "mqttchambertemperature";
version = "0.0.3";
src = fetchFromGitHub {
owner = "synman";
repo = "OctoPrint-MqttChamberTemperature";
rev = version;
sha256 = "sha256-CvNpi8HcBBUfCs3X8yflbhe0YCU0kW3u2ADSro/qnuI=";
};
propagatedBuildInputs = with super; [ jsonpath-ng ];
meta = with lib; {
description = "Enables Chamber temperature reporting via subscribing to an MQTT topic";
homepage = "https://github.com/synman/OctoPrint-MqttChamberTemperature";
license = licenses.wtfpl;
maintainers = with maintainers; [ tri-ler ];
};
};
navbartemp = buildPlugin rec {
pname = "navbartemp";
version = "0.15";
src = fetchFromGitHub {
owner = "imrahil";
repo = "OctoPrint-NavbarTemp";
rev = version;
sha256 = "sha256-ZPpTx+AadRffUb53sZbMUbCZa7xYGQW/5si7UB8mnVI=";
};
meta = with lib; {
description = "Displays temperatures on navbar";
homepage = "https://github.com/imrahil/OctoPrint-NavbarTemp";
license = licenses.agpl3Only;
maintainers = with maintainers; [ tri-ler ];
};
};
obico = buildPlugin rec {
pname = "obico";
version = "2.5.0";
src = fetchFromGitHub {
owner = "TheSpaghettiDetective";
repo = "OctoPrint-Obico";
rev = version;
sha256 = "sha256-cAUXe/lRTqYuWnrRiNDuDjcayL5yV9/PtTd9oeSC8KA=";
};
propagatedBuildInputs = with super; [
backoff
sentry-sdk
bson
distro
];
meta = with lib; {
description = "Monitor Octoprint-connected printers with Obico";
homepage = "https://www.obico.io/";
license = licenses.agpl3Only;
maintainers = with maintainers; [ tri-ler ];
};
};
octopod = buildPlugin rec {
pname = "octopod";
version = "0.3.16";
src = fetchFromGitHub {
owner = "gdombiak";
repo = "OctoPrint-OctoPod";
rev = version;
sha256 = "sha256-9QKC1MsYO3XihOTAijJUv5i20iMSQHOHPfLiYPV5y8s=";
};
propagatedBuildInputs = with super; [ pillow ];
meta = with lib; {
description = "OctoPod extension for OctoPrint";
homepage = "https://github.com/gdombiak/OctoPrint-OctoPod";
license = licenses.asl20;
maintainers = with maintainers; [ tri-ler ];
};
};
printtimegenius = buildPlugin rec {
pname = "printtimegenius";
version = "2.3.1";
version = "2.3.3";
src = fetchFromGitHub {
owner = "eyal0";
repo = "OctoPrint-PrintTimeGenius";
rev = version;
sha256 = "sha256-2lxaTcmPBSdfMmViIfLEbeYWfXZpNVAO4i5Z678gWy0=";
sha256 = "sha256-hqm8RShCNpsVbrVXquat5VXqcVc7q5tn5+7Ipqmaw4U=";
};
propagatedBuildInputs = with super; [
@ -261,6 +388,27 @@ in
};
};
prusaslicerthumbnails = buildPlugin rec {
pname = "prusaslicerthumbnails";
version = "1.0.7";
src = fetchFromGitHub {
owner = "jneilliii";
repo = "OctoPrint-PrusaSlicerThumbnails";
rev = version;
sha256 = "sha256-waNCTjAZwdBfhHyJCG2La7KTnJ8MDVuX1JLetFB5bS4=";
};
propagatedBuildInputs = with super; [ psutil ];
meta = with lib; {
description = "Plugin that extracts thumbnails from uploaded gcode files sliced by PrusaSlicer";
homepage = "https://github.com/jneilliii/OctoPrint-PrusaSlicerThumbnails";
license = licenses.agpl3Only;
maintainers = with maintainers; [ tri-ler ];
};
};
psucontrol = buildPlugin rec {
pname = "psucontrol";
version = "1.0.6";
@ -289,6 +437,27 @@ in
};
};
resource-monitor = buildPlugin rec {
pname = "resource-monitor";
version = "0.3.16";
src = fetchFromGitHub {
owner = "Renaud11232";
repo = "OctoPrint-Resource-Monitor";
rev = version;
sha256 = "sha256-w1PBxO+Qf7cSSNocu7BiulZE7kesSa+LGV3uJlmd0ao=";
};
propagatedBuildInputs = with super; [ psutil ];
meta = with lib; {
description = "Plugin to view the current CPU and RAM usage on your system";
homepage = "https://github.com/Renaud11232/OctoPrint-Resource-Monitor";
license = licenses.mit;
maintainers = with maintainers; [ tri-ler ];
};
};
simpleemergencystop = buildPlugin rec {
pname = "simpleemergencystop";
version = "1.0.5";
@ -367,6 +536,25 @@ in
};
};
timelapsepurger = buildPlugin rec {
pname = "firmwareupdater";
version = "0.1.4";
src = fetchFromGitHub {
owner = "jneilliii";
repo = "OctoPrint-TimelapsePurger";
rev = version;
sha256 = "sha256-XS4m4KByScGTPfVE4kuRLw829gNE2CdM0RyhRqGGxyw=";
};
meta = with lib; {
description = "Automatically deletes timelapses that are older than configured timeframe";
homepage = "https://github.com/jneilliii/OctoPrint-TimelapsePurger";
license = licenses.agpl3Only;
maintainers = with maintainers; [ tri-ler ];
};
};
titlestatus = buildPlugin rec {
pname = "titlestatus";
version = "0.0.5";

View File

@ -13,13 +13,13 @@
stdenv.mkDerivation rec {
pname = "pgmodeler";
version = "1.1.3";
version = "1.1.4";
src = fetchFromGitHub {
owner = "pgmodeler";
repo = "pgmodeler";
rev = "v${version}";
sha256 = "sha256-LDgRv7Todyy2pnE21Z0O5JQ6mE4ZO3THv6rfEWU66Cc=";
sha256 = "sha256-axw0/QFQfnEc2P8tFRtSY5vVUJTqv+kRn68GXdZ5SeQ=";
};
nativeBuildInputs = [ pkg-config qmake wrapQtAppsHook ];

View File

@ -3,10 +3,10 @@
, fetchurl
, cabextract
, gettext
, glxinfo
, gnupg
, icoutils
, imagemagick
, mesa-demos
, netcat-gnu
, p7zip
, python3
@ -37,10 +37,10 @@ let
cabextract
python
gettext
glxinfo
gnupg
icoutils
imagemagick
mesa-demos
netcat-gnu
p7zip
unzip

View File

@ -73,7 +73,7 @@ stdenv.mkDerivation rec {
yarn run nextron build --no-pack
yarn run electron-builder --dir \
--config electron-builder.yml \
-c.electronDist="${electron}/libexec/electron" \
-c.electronDist="${electron.dist}" \
-c.electronVersion=${electron.version}
runHook postBuild

View File

@ -12,13 +12,13 @@
stdenv.mkDerivation (finalAttrs: {
pname = "xca";
version = "2.6.0";
version = "2.7.0";
src = fetchFromGitHub {
owner = "chris2511";
repo = "xca";
rev = "RELEASE.${finalAttrs.version}";
hash = "sha256-E0Ap+JDK/oYTG+uaRHsdOxyLIywlYJ01T4ANQhNH220=";
hash = "sha256-Ty6j0Fl2smMGxp+1nnD3Fu83bn19gqtRKSA1wDgNZes=";
};
buildInputs = [ openssl qtbase ];

View File

@ -6,13 +6,13 @@
buildGoModule rec {
pname = "arkade";
version = "0.11.20";
version = "0.11.21";
src = fetchFromGitHub {
owner = "alexellis";
repo = "arkade";
rev = version;
hash = "sha256-xjJbO+42PUuRb4vMSKscTf2DEDekSwEF/v2QwKeBtvI=";
hash = "sha256-vNJQLrpPJJG5FjQ73203V/Ky93HawRWgMiPYHU+eXPM=";
};
CGO_ENABLED = 0;

View File

@ -1,16 +1,16 @@
{ buildGoModule, lib, fetchFromGitHub }:
buildGoModule rec {
pname = "tfswitch";
version = "1.0.2";
version = "1.2.2";
src = fetchFromGitHub {
owner = "warrensbox";
repo = "terraform-switcher";
rev = version;
sha256 = "sha256-Gp7+TEE7rmlabZhley/crpYZiqiKcc6uqSr6leZsmgU=";
rev = "v${version}";
sha256 = "sha256-Ym0ypMfoceOvje1z1oCxjnFrl1oosMFSplM7bhI0KXU=";
};
vendorHash = "sha256-DsC9djgt7Er2m2TacUldpJP43jC0IBklPnu41Saf4DY=";
vendorHash = "sha256-44A9fF+HIOJrlxpps6GV3yjPBqfpwOhEZ8Ejnp2o/wk=";
# Disable tests since it requires network access and relies on the
# presence of release.hashicorp.com

View File

@ -35,7 +35,7 @@ stdenv.mkDerivation rec {
npm exec electron-builder -- \
--dir \
-c.electronDist="${electron_30}/libexec/electron" \
-c.electronDist="${electron_30.dist}" \
-c.electronVersion="${electron_30.version}"
runHook postBuild

View File

@ -1,9 +1,9 @@
{
"version" = "1.11.75";
"version" = "1.11.76";
"hashes" = {
"desktopSrcHash" = "sha256-bO23E1xG3FfizBBAWh0kCN+5JYbiX5V/wxLlY6ljWVQ=";
"desktopSrcHash" = "sha256-oG1nzOSXl2vjxvxdVg2o5ssKbAqrYHS4pnLCPJsIBCQ=";
"desktopYarnHash" = "0bl78yd7apd5qbsqyhxnwj7lwrjx5820zh22rzgn9jqkcv25jwgw";
"webSrcHash" = "sha256-cDayCoznbmALOiPg9FUYrfdFjzg0NV1NY9/b2KzTvMs=";
"webYarnHash" = "04si1x663z70nxj6nfaq7m2wcd8r4l3vdpirnjhc13wrj1kb8r8x";
"webSrcHash" = "sha256-1hmSdefNChRcUnwbxS00NYrEexMyg8FIL0BXdEbwm+s=";
"webYarnHash" = "0bnxd7kig2a5scgdsd0yhhmanf7zqi2gd2si6kgnr0v2kc0akc0b";
};
}

View File

@ -68,14 +68,14 @@
stdenv.mkDerivation rec {
pname = "jami";
version = "20240813.0";
version = "20240823.0";
src = fetchFromGitLab {
domain = "git.jami.net";
owner = "savoirfairelinux";
repo = "jami-client-qt";
rev = "stable/${version}";
hash = "sha256-XRWbV1s87niwNiWf2KRpV+wUH6ptw3vnVXCEwqh2r7M=";
hash = "sha256-7jGH54sFiS6qrdEiKSS64lJyJXL1FOJVbesxo/FFmyA=";
fetchSubmodules = true;
};

View File

@ -16,8 +16,6 @@
let
inherit (darwin.apple_sdk.frameworks) Carbon CoreFoundation ApplicationServices OpenGL;
electronDist = electron + (if stdenv.isDarwin then "/Applications" else "/libexec/electron");
in
buildNpmPackage rec {
pname = "jitsi-meet-electron";
@ -70,7 +68,7 @@ buildNpmPackage rec {
'';
postBuild = ''
cp -r ${electronDist} electron-dist
cp -r ${electron.dist} electron-dist
chmod -R u+w electron-dist
# npmRebuild is needed because robotjs won't be built on darwin otherwise

View File

@ -50,7 +50,7 @@ stdenv.mkDerivation (finalAttrs: {
yarn --offline electron-builder \
--dir ${if stdenv.isDarwin then "--macos" else "--linux"} ${if stdenv.hostPlatform.isAarch64 then "--arm64" else "--x64"} \
-c.electronDist=${electron}/libexec/electron \
-c.electronDist=${electron.dist} \
-c.electronVersion=${electron.version}
runHook postBuild

View File

@ -8,6 +8,8 @@ buildGoModule rec {
pname = "rclone";
version = "1.67.0";
outputs = [ "out" "man" ];
src = fetchFromGitHub {
owner = "rclone";
repo = "rclone";
@ -19,15 +21,19 @@ buildGoModule rec {
subPackages = [ "." ];
outputs = [ "out" "man" ];
nativeBuildInputs = [ installShellFiles makeWrapper ];
buildInputs = lib.optional enableCmount (if stdenv.isDarwin then macfuse-stubs else fuse);
nativeBuildInputs = [ installShellFiles makeWrapper ];
tags = lib.optionals enableCmount [ "cmount" ];
ldflags = [ "-s" "-w" "-X github.com/rclone/rclone/fs.Version=${version}" ];
postConfigure = lib.optionalString (!stdenv.isDarwin) ''
substituteInPlace vendor/github.com/winfsp/cgofuse/fuse/host_cgo.go \
--replace-fail '"libfuse.so.2"' '"${lib.getLib fuse}/lib/libfuse.so.2"'
'';
postInstall =
let
rcloneBin =
@ -50,8 +56,7 @@ buildGoModule rec {
# as the setuid wrapper is required as non-root on NixOS.
''
wrapProgram $out/bin/rclone \
--suffix PATH : "${lib.makeBinPath [ fuse3 ] }" \
--prefix LD_LIBRARY_PATH : "${fuse3}/lib"
--suffix PATH : "${lib.makeBinPath [ fuse3 ] }"
'';
passthru.tests = {

View File

@ -33,14 +33,14 @@ let
}.${system} or throwSystem;
hash = {
x86_64-linux = "sha256-KLOI0lG0rZbLS2uiONNlgyCkohzQhytRovAfrjnGuDI=";
x86_64-linux = "sha256-l67oq9Jj2mmxcLsEMI4t+85cKD65xxMNkTNJrrRrwJQ=";
}.${system} or throwSystem;
displayname = "XPipe";
in stdenvNoCC.mkDerivation rec {
pname = "xpipe";
version = "10.2.2";
version = "11.0";
src = fetchzip {
url = "https://github.com/xpipe-io/xpipe/releases/download/${version}/xpipe-portable-linux-${arch}.tar.gz";

View File

@ -10,7 +10,7 @@
}:
let
version = "5.13.22";
version = "5.13.28";
in
rustPlatform.buildRustPackage {
pname = "git-mit";
@ -20,10 +20,10 @@ rustPlatform.buildRustPackage {
owner = "PurpleBooth";
repo = "git-mit";
rev = "v${version}";
hash = "sha256-nYKwf0+Ai6GU9CeRKI7NInmkA4yH41tMWoT9S03m0VI=";
hash = "sha256-zw1yY/vCrxklmIXGHO5cMOQ9L3xfHD24f2JN7ibF/I8=";
};
cargoHash = "sha256-dcTyombQBR0IGkK+2GWedFQf/1a74gVUIqM96xVxlj0=";
cargoHash = "sha256-pnSp6XCVSxCY7b1LHeQM9/KsjG6sGQoMCPcL8Bby4A4=";
nativeBuildInputs = [ pkg-config ];

View File

@ -34,7 +34,7 @@ let
davinci = (
stdenv.mkDerivation rec {
pname = "davinci-resolve${lib.optionalString studioVariant "-studio"}";
version = "18.6.6";
version = "19.0";
nativeBuildInputs = [
(appimage-run.override { buildFHSEnv = buildFHSEnvChroot; } )
@ -55,8 +55,8 @@ let
outputHashAlgo = "sha256";
outputHash =
if studioVariant
then "sha256-9iTdIjHH8uoXlVr6miyqmHuzbbpbqdJPEbPGycsccoI="
else "sha256-WrIQ1FHm65MOGb5HfFl2WzXYJRlqktuZdrtzcjWp1gI=";
then "sha256-KxoUXHMlgWoa00GSq/DLVgyOjuv7k8aUwl20XvDRZvc="
else "sha256-XQP5RL/p/voQePLiBr1Hc+dBUZHW39XxDjyxKJyKXxw=";
impureEnvVars = lib.fetchers.proxyImpureEnvVars;
@ -94,7 +94,7 @@ let
} ''
DOWNLOADID=$(
curl --silent --compressed "$DOWNLOADSURL" \
| jq --raw-output '.downloads[] | select(.name | test("^'"$PRODUCT $VERSION"'( Update)?$")) | .urls.Linux[0].downloadId'
| jq --raw-output '.downloads[] | .urls.Linux?[]? | select(.downloadTitle | test("^'"$PRODUCT $VERSION"'( Update)?$")) | .downloadId'
)
echo "downloadid is $DOWNLOADID"
test -n "$DOWNLOADID"
@ -271,13 +271,13 @@ buildFHSEnv {
currentVersion=${lib.escapeShellArg davinci.version}
downloadsJSON="$(curl --fail --silent https://www.blackmagicdesign.com/api/support/us/downloads.json)"
latestLinuxVersion="$(echo "$downloadsJSON" | jq '[.downloads[] | select(.urls.Linux) | .urls.Linux[] | select(.downloadTitle | test("DaVinci Resolve")) | .downloadTitle]' | grep -oP 'DaVinci Resolve \K\d+\.\d+\.\d+' | sort | tail -n 1)"
latestLinuxVersion="$(echo "$downloadsJSON" | jq '[.downloads[] | select(.urls.Linux) | .urls.Linux[] | select(.downloadTitle | test("DaVinci Resolve")) | .downloadTitle]' | grep -oP 'DaVinci Resolve \K\d+\.\d+(\.\d+)?' | sort | tail -n 1)"
update-source-version davinci-resolve "$latestLinuxVersion" --source-key=davinci.src
# Since the standard and studio both use the same version we need to reset it before updating studio
sed -i -e "s/""$latestLinuxVersion""/""$currentVersion""/" "$drv"
latestStudioLinuxVersion="$(echo "$downloadsJSON" | jq '[.downloads[] | select(.urls.Linux) | .urls.Linux[] | select(.downloadTitle | test("DaVinci Resolve")) | .downloadTitle]' | grep -oP 'DaVinci Resolve Studio \K\d+\.\d+\.\d+' | sort | tail -n 1)"
latestStudioLinuxVersion="$(echo "$downloadsJSON" | jq '[.downloads[] | select(.urls.Linux) | .urls.Linux[] | select(.downloadTitle | test("DaVinci Resolve")) | .downloadTitle]' | grep -oP 'DaVinci Resolve Studio \K\d+\.\d+(\.\d+)?' | sort | tail -n 1)"
update-source-version davinci-resolve-studio "$latestStudioLinuxVersion" --source-key=davinci.src
'';
});

View File

@ -1,30 +0,0 @@
{ lib
, buildPythonApplication
, fetchPypi
, ffmpeg
, ffmpeg-progress-yield
}:
buildPythonApplication rec {
pname = "ffmpeg-normalize";
version = "1.26.1";
src = fetchPypi {
inherit pname version;
hash = "sha256-OwREpfWaP0tdAjMGjGpVIAQn8rlTTjSfT+0t5g/2yjQ=";
};
propagatedBuildInputs = [ ffmpeg ffmpeg-progress-yield ];
checkPhase = ''
$out/bin/ffmpeg-normalize --help > /dev/null
'';
meta = with lib; {
description = "Normalize audio via ffmpeg";
homepage = "https://github.com/slhck/ffmpeg-normalize";
license = with licenses; [ mit ];
maintainers = with maintainers; [ prusnak ];
mainProgram = "ffmpeg-normalize";
};
}

View File

@ -13,7 +13,7 @@
, libogg, libvorbis, flac, libxslt
, lzo, libcdio, libmodplug, libass, libbluray, libudfread
, sqlite, libmysqlclient, nasm, gnutls, libva, libdrm
, curl, bzip2, zip, unzip, glxinfo
, curl, bzip2, zip, unzip, mesa-demos
, libcec, libcec_platform, dcadec, libuuid
, libcrossguid, libmicrohttpd
, bluez, doxygen, giflib, glib, harfbuzz, lcms2, libidn2, libpthreadstubs, libtasn1
@ -119,7 +119,7 @@ in stdenv.mkDerivation (finalAttrs: {
libogg libvorbis flac libxslt systemd
lzo libcdio libmodplug libass libbluray libudfread
sqlite libmysqlclient avahi lame
curl bzip2 zip unzip glxinfo
curl bzip2 zip unzip mesa-demos
libcec libcec_platform dcadec libuuid
libxcrypt libgcrypt libgpg-error libunistring
libcrossguid libplist
@ -229,7 +229,7 @@ in stdenv.mkDerivation (finalAttrs: {
# TODO: figure out which binaries should be wrapped this way and which shouldn't
for p in $(ls --ignore=kodi-send $out/bin/) ; do
wrapProgram $out/bin/$p \
--prefix PATH ":" "${lib.makeBinPath ([ python3Packages.python glxinfo ]
--prefix PATH ":" "${lib.makeBinPath ([ python3Packages.python mesa-demos ]
++ lib.optional x11Support xdpyinfo ++ lib.optional sambaSupport samba)}" \
--prefix LD_LIBRARY_PATH ":" "${lib.makeLibraryPath
([ curl systemd libmad libcec libcec_platform libass ]

View File

@ -3,13 +3,13 @@
stdenv.mkDerivation rec {
pname = "motion";
version = "4.6.0";
version = "4.7.0";
src = fetchFromGitHub {
owner = "Motion-Project";
repo = "motion";
rev = "release-${version}";
sha256 = "sha256-f23glk91HWSEW/Glq/DdEikTQeg1eELEg4XG9zTsU78=";
sha256 = "sha256-bGjiO14a7xKRgoeo5JlexXlKggE+agRMmQViBXagmt8=";
};
nativeBuildInputs = [ autoreconfHook pkg-config ];

View File

@ -1,5 +1,5 @@
{ stdenv, nixosTests, lib, edk2, util-linux, nasm, acpica-tools, llvmPackages
, fetchurl, python3, pexpect, xorriso, qemu, dosfstools, mtools
, fetchFromGitLab, python3, pexpect, xorriso, qemu, dosfstools, mtools
, fdSize2MB ? false
, fdSize4MB ? secureBoot
, secureBoot ? false
@ -12,7 +12,7 @@
# to use as the PK and first KEK for the keystore.
#
# By default, we use Debian's cert. This default
# should chnage to a NixOS cert once we have our
# should change to a NixOS cert once we have our
# own secure boot signing infrastructure.
#
# Ignored if msVarsTemplate is false.
@ -66,9 +66,18 @@ let
OvmfPkKek1AppPrefix = "4e32566d-8e9e-4f52-81d3-5bb9715f9727";
debian-edk-src = fetchurl {
url = "http://deb.debian.org/debian/pool/main/e/edk2/edk2_2023.11-5.debian.tar.xz";
sha256 = "1yxlab4md30pxvjadr6b4xn6cyfw0c292q63pyfv4vylvhsb24g4";
debian-edk-src = fetchFromGitLab {
domain = "salsa.debian.org";
owner = "qemu-team";
repo = "edk2";
nonConeMode = true;
sparseCheckout = [
"debian/edk2-vars-generator.py"
"debian/python"
"debian/PkKek-1-*.pem"
];
rev = "refs/tags/debian/2024.05-1";
hash = "sha256-uAjXJaHOVh944ZxcA2IgCsrsncxuhc0JKlsXs0E03s0=";
};
buildPrefix = "Build/*/*";
@ -111,7 +120,7 @@ edk2.mkDerivation projectDscPath (finalAttrs: {
env.PYTHON_COMMAND = "python3";
postUnpack = lib.optionalDrvAttr msVarsTemplate ''
unpackFile ${debian-edk-src}
ln -s ${debian-edk-src}/debian
'';
postConfigure = lib.optionalDrvAttr msVarsTemplate ''
@ -138,7 +147,8 @@ edk2.mkDerivation projectDscPath (finalAttrs: {
'' + lib.optionalString msVarsTemplate ''
(
cd ${buildPrefix}
python3 $NIX_BUILD_TOP/debian/edk2-vars-generator.py \
# locale must be set on Darwin for invocations of mtools to work correctly
LC_ALL=C python3 $NIX_BUILD_TOP/debian/edk2-vars-generator.py \
--flavor ${msVarsArgs.flavor} \
--enrolldefaultkeys ${msVarsArgs.archDir}/EnrollDefaultKeys.efi \
--shell ${msVarsArgs.archDir}/Shell.efi \
@ -165,7 +175,7 @@ edk2.mkDerivation projectDscPath (finalAttrs: {
ln -sv $fd/FV/${fwPrefix}_CODE{,.ms}.fd
'' + lib.optionalString stdenv.hostPlatform.isAarch ''
mv -v $out/FV/QEMU_{EFI,VARS}.fd $fd/FV
# Add symlinks for Fedora dir layout: https://src.fedoraproject.org/cgit/rpms/edk2.git/tree/edk2.spec
# Add symlinks for Fedora dir layout: https://src.fedoraproject.org/rpms/edk2/blob/main/f/edk2.spec
mkdir -vp $fd/AAVMF
ln -s $fd/FV/AAVMF_CODE.fd $fd/AAVMF/QEMU_EFI-pflash.raw
ln -s $fd/FV/AAVMF_VARS.fd $fd/AAVMF/vars-template-pflash.raw
@ -179,6 +189,9 @@ edk2.mkDerivation projectDscPath (finalAttrs: {
in {
firmware = "${prefix}_CODE.fd";
variables = "${prefix}_VARS.fd";
variablesMs =
assert msVarsTemplate;
"${prefix}_VARS.ms.fd";
# This will test the EFI firmware for the host platform as part of the NixOS Tests setup.
tests.basic-systemd-boot = nixosTests.systemd-boot.basic;
tests.secureBoot-systemd-boot = nixosTests.systemd-boot.secureBoot;
@ -190,7 +203,7 @@ edk2.mkDerivation projectDscPath (finalAttrs: {
homepage = "https://github.com/tianocore/tianocore.github.io/wiki/OVMF";
license = lib.licenses.bsd2;
platforms = metaPlatforms;
maintainers = with lib.maintainers; [ adamcstephens raitobezarius ];
broken = stdenv.isDarwin;
maintainers = with lib.maintainers; [ adamcstephens raitobezarius mjoerg ];
broken = stdenv.isDarwin && stdenv.isAarch64;
};
})

View File

@ -73,7 +73,7 @@ stdenv.mkDerivation (finalAttrs: {
yarn --offline run build
yarn --offline run electron-builder --dir \
--config .electron-builder.config.cjs \
-c.electronDist=${electron}/libexec/electron \
-c.electronDist=${electron.dist} \
-c.electronVersion=${electron.version}
runHook postBuild

View File

@ -134,7 +134,7 @@ stdenv.mkDerivation (finalAttrs: {
# error: unknown type name 'NSUInteger'
postPatch = ''
substituteInPlace src/dialog_colorpicker.cpp \
--replace "NSUInteger" "size_t"
--replace-fail "NSUInteger" "size_t"
'';
env = {

View File

@ -12,7 +12,7 @@ let
self = python3;
packageOverrides = _: super: { tree-sitter = super.tree-sitter_0_21; };
};
version = "0.51.0";
version = "0.53.0";
in
python3.pkgs.buildPythonApplication {
pname = "aider-chat";
@ -23,7 +23,7 @@ python3.pkgs.buildPythonApplication {
owner = "paul-gauthier";
repo = "aider";
rev = "refs/tags/v${version}";
hash = "sha256-vomRXWL3++1R8jpjMKbsGrB+B1FWQxVbLKxuPttnspw=";
hash = "sha256-KQp4qqQKm++oB9RVQZhAWQJs7Nbyssc9eKKRH1VZbRU=";
};
build-system = with python3.pkgs; [ setuptools ];

View File

@ -7,13 +7,13 @@
stdenvNoCC.mkDerivation {
pname = "ananicy-rules-cachyos";
version = "0-unstable-2024-07-27";
version = "0-unstable-2024-08-26";
src = fetchFromGitHub {
owner = "CachyOS";
repo = "ananicy-rules";
rev = "c6153c9e909475bbb08b4e56af152179ff7f171f";
hash = "sha256-sAWHm3PK9mM+AtHdDhq3RIQBo58eEZtD1l7QfCTpl0s=";
rev = "a78b76536246898045fd1844aced381d01b7f1c6";
hash = "sha256-bDfvWg5r4LmWI8tPrx9qzgEnJuMSYBm6MDf6yOaPqkY=";
};
dontConfigure = true;

View File

@ -7,16 +7,16 @@
rustPlatform.buildRustPackage rec {
pname = "ast-grep";
version = "0.24.1";
version = "0.26.3";
src = fetchFromGitHub {
owner = "ast-grep";
repo = "ast-grep";
rev = version;
hash = "sha256-kNPmtaUb5rMbdTlNKD3PrInuxGQt/JamMDx8BwBxVd8=";
hash = "sha256-i2M3QSwLj2px6tiYyW8jz/WZ2z+IETrSoxis+BgHGXg=";
};
cargoHash = "sha256-iV2GXH7opNIyWsgi0EnRIXDhJd3s66qFhnZWawBPb6g=";
cargoHash = "sha256-6CXttQ+r2Ye5tz1V7XgLLnKQg7LHUVUtqpThETrwtzQ=";
nativeBuildInputs = [ installShellFiles ];

View File

@ -11,13 +11,13 @@
buildNpmPackage rec {
pname = "bitwarden-cli";
version = "2024.8.0";
version = "2024.8.1";
src = fetchFromGitHub {
owner = "bitwarden";
repo = "clients";
rev = "cli-v${version}";
hash = "sha256-vosEc8HCMHEaaQadzA+jDjQA1liEtD8sS1Zndz/Iv00=";
hash = "sha256-l9fLh1YFivVcMs688vM0pHoN0Um2r/EDpo7dvwvZFwY=";
};
postPatch = ''
@ -27,10 +27,10 @@ buildNpmPackage rec {
nodejs = nodejs_20;
npmDepsHash = "sha256-5neEpU7ZhVO5OR181owsvAnFfl7lr0MymvqbRFCPs3M=";
npmDepsHash = "sha256-/6yWdTy6/GvYy8u5eZB+x5KRG6vhPVE0DIn+RUAO5MI=";
nativeBuildInputs = [
python3
(python3.withPackages (ps: with ps; [ setuptools ]))
] ++ lib.optionals stdenv.isDarwin [
cctools
xcbuild.xcrun
@ -38,7 +38,19 @@ buildNpmPackage rec {
makeCacheWritable = true;
env.ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
env = {
ELECTRON_SKIP_BINARY_DOWNLOAD = "1";
npm_config_build_from_source = "true";
};
# node-argon2 builds with LTO, but that causes missing symbols. So disable it
# and rebuild. See https://github.com/ranisalt/node-argon2/pull/415
preConfigure = ''
pushd node_modules/argon2
substituteInPlace binding.gyp --replace-fail '"-flto", ' ""
"$npm_config_node_gyp" rebuild
popd
'';
npmBuildScript = "build:oss:prod";

View File

@ -120,7 +120,7 @@ in buildNpmPackage rec {
npm exec electron-builder -- \
--dir \
-c.electronDist=${electron}/libexec/electron \
-c.electronDist=${electron.dist} \
-c.electronVersion=${electron.version}
popd

View File

@ -10,9 +10,6 @@
electron,
}:
let
electronDist = "${electron}/${if stdenv.isDarwin then "Applications" else "libexec/electron"}";
in
buildNpmPackage rec {
pname = "blockbench";
version = "4.10.4";
@ -45,7 +42,7 @@ buildNpmPackage rec {
postBuild = ''
# electronDist needs to be modifiable on Darwin
cp -r ${electronDist} electron-dist
cp -r ${electron.dist} electron-dist
chmod -R u+w electron-dist
npm exec electron-builder -- \

View File

@ -103,7 +103,7 @@ buildNpmPackage' rec {
${
if stdenv.isDarwin then
''
cp -r ${electron}/Applications/Electron.app ./
cp -r ${electron.dist}/Electron.app ./
find ./Electron.app -name 'Info.plist' | xargs -d '\n' chmod +rw
substituteInPlace electron-builder-config.js \
@ -121,7 +121,7 @@ buildNpmPackage' rec {
''
npm exec electron-builder -- \
--dir \
-c.electronDist=${electron}/libexec/electron \
-c.electronDist=${electron.dist} \
-c.electronVersion=${electron.version} \
-c.npmRebuild=false
''

View File

@ -8,9 +8,6 @@
electron,
}:
let
electronDist = electron + (if stdenv.isDarwin then "/Applications" else "/libexec/electron");
in
buildNpmPackage rec {
pname = "caprine";
version = "2.60.1";
@ -29,7 +26,7 @@ buildNpmPackage rec {
nativeBuildInputs = [ copyDesktopItems ];
postBuild = ''
cp -r ${electronDist} electron-dist
cp -r ${electron.dist} electron-dist
chmod -R u+w electron-dist
npm exec electron-builder -- \

File diff suppressed because it is too large Load Diff

View File

@ -15,27 +15,31 @@
rustPlatform.buildRustPackage rec {
pname = "cosmic-notifications";
version = "unstable-2024-01-05";
version = "1.0.0-alpha.1";
src = fetchFromGitHub {
owner = "pop-os";
repo = pname;
rev = "3b07cf550a54b757a5f136e4d8fde74d09afe3fd";
hash = "sha256-+S8bPorarSJQwIQfTmo4qK+B1kKAlQvllUuZ2UBL0eY=";
repo = "cosmic-notifications";
rev = "epoch-${version}";
hash = "sha256-tCizZePze94tbJbR91N9rfUhrLFTAMW2oL9ByKOeDAU=";
};
cargoLock = {
lockFile = ./Cargo.lock;
outputHashes = {
"accesskit-0.11.0" = "sha256-xVhe6adUb8VmwIKKjHxwCwOo5Y1p3Or3ylcJJdLDrrE=";
"accesskit-0.12.2" = "sha256-1UwgRyUe0PQrZrpS7574oNLi13fg5HpgILtZGW6JNtQ=";
"atomicwrites-0.4.2" = "sha256-QZSuGPrJXh+svMeFWqAXoqZQxLq/WfIiamqvjJNVhxA=";
"cosmic-client-toolkit-0.1.0" = "sha256-AEgvF7i/OWPdEMi8WUaAg99igBwE/AexhAXHxyeJMdc=";
"cosmic-config-0.1.0" = "sha256-DmuUvFjhoqI5lneiWFFYF3WM3mACx5ZfZqeKpsyL7Ss=";
"cosmic-text-0.10.0" = "sha256-kIBhh6CakQaWGfBWu5qaV8LAbJENX7GW+BStJK/P4iA=";
"cosmic-settings-daemon-0.1.0" = "sha256-z/dvRyc3Zc1fAQh2HKk6NI6QSDpNqarqslwszjU+0nc=";
"glyphon-0.3.0" = "sha256-JGkNIfj1HjOF8kGxqJPNq/JO+NhZD6XrZ4KmkXEP6Xc=";
"smithay-client-toolkit-0.18.0" = "sha256-2WbDKlSGiyVmi7blNBr2Aih9FfF2dq/bny57hoA4BrE=";
"softbuffer-0.3.3" = "sha256-eKYFVr6C1+X6ulidHIu9SP591rJxStxwL9uMiqnXx4k=";
"clipboard_macos-0.1.0" = "sha256-cG5vnkiyDlQnbEfV2sPbmBYKv1hd3pjJrymfZb8ziKk=";
"cosmic-client-toolkit-0.1.0" = "sha256-1XtyEvednEMN4MApxTQid4eed19dEN5ZBDt/XRjuda0=";
"cosmic-config-0.1.0" = "sha256-DgMh0gqWUmXjBhBySR0CMnv/8O3XbS2BwomU9eNt+4o=";
"cosmic-panel-config-0.1.0" = "sha256-bBUSZ3CTLq/DCQ2dMvaIcGcIcjqM/5vny5kTE3Jclj8=";
"cosmic-settings-daemon-0.1.0" = "sha256-+1XB7r45Uc71fLnNR4U0DUF2EB8uzKeE4HIrdvKhFXo=";
"cosmic-text-0.12.1" = "sha256-x0XTxzbmtE2d4XCG/Nuq3DzBpz15BbnjRRlirfNJEiU=";
"cosmic-time-0.4.0" = "sha256-w4yY1fc4r1+pSv93dy/Hu3AD+I1+sozIPbbCoaVQj7w=";
"d3d12-0.19.0" = "sha256-usrxQXWLGJDjmIdw1LBXtBvX+CchZDvE8fHC0LjvhD4=";
"glyphon-0.5.0" = "sha256-j1HrbEpUBqazWqNfJhpyjWuxYAxkvbXzRKeSouUoPWg=";
"smithay-clipboard-0.8.0" = "sha256-4InFXm0ahrqFrtNLeqIuE3yeOpxKZJZx+Bc0yQDtv34=";
"softbuffer-0.4.1" = "sha256-a0bUFz6O8CWRweNt/OxTvflnPYwO5nm6vsyc/WcXyNg=";
"taffy-0.3.11" = "sha256-SCx9GEIJjWdoNVyq+RZAGn0N71qraKZxf9ZWhvyzLaI=";
};
};

View File

@ -6,13 +6,13 @@
stdenv.mkDerivation rec {
pname = "cosmic-protocols";
version = "0-unstable-2024-01-11";
version = "0-unstable-2024-07-31";
src = fetchFromGitHub {
owner = "pop-os";
repo = pname;
rev = "e65fa5e2bb47e51656221657049bd3f88ae9dae5";
hash = "sha256-vj7Wm1uJ5ULvGNEwKznNhujCZQiuntsWMyKQbIVaO/Q=";
rev = "de2fead49d6af3a221db153642e4d7c2235aafc4";
hash = "sha256-qgo8FMKo/uCbhUjfykRRN8KSavbyhZpu82M8npLcIPI=";
};
makeFlags = [ "PREFIX=${placeholder "out"}" ];
@ -20,7 +20,7 @@ stdenv.mkDerivation rec {
meta = with lib; {
homepage = "https://github.com/pop-os/cosmic-protocols";
description = "Addtional wayland-protocols used by the COSMIC desktop environment";
description = "Additional wayland-protocols used by the COSMIC desktop environment";
license = [ licenses.mit licenses.gpl3Only ];
maintainers = with maintainers; [ nyanbinary ];
platforms = platforms.linux;

View File

@ -8,16 +8,16 @@
rustPlatform.buildRustPackage rec {
pname = "cosmic-screenshot";
version = "unstable-2023-11-08";
version = "1.0.0-alpha.1";
src = fetchFromGitHub {
owner = "pop-os";
repo = pname;
rev = "b413a7128ddcdfb3c63e84bdade5c5b90b163a9a";
hash = "sha256-SDxBBhmnqNDX95Rb7QiI46sAxrfodB5tSq8AbXAU480=";
rev = "epoch-${version}";
hash = "sha256-+yHpRbK+AWnpcGrC5U0wKbt0u8tm3CFGjKTCDQpb3G0=";
};
cargoHash = "sha256-ZRsAhIWPm38Ys9jM/3yVJLW818lUGLCcSfFZb+UTbnU=";
cargoHash = "sha256-d56y35npMPrQM0yF0ytNcOdMKBz9IQvEz37DNvKBBSk=";
nativeBuildInputs = [ just pkg-config ];

View File

@ -0,0 +1,34 @@
{
lib,
stdenvNoCC,
fetchzip,
}:
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "departure-mono";
version = "1.346";
src = fetchzip {
url = "https://departuremono.com/assets/DepartureMono-${finalAttrs.version}.zip";
stripRoot = false;
hash = "sha256-xJVVtLnukcWQKVC3QiHvrfIA3W9EYt/iiphbLYT1iMg=";
};
installPhase = ''
runHook preInstall
install -D -m 444 *.otf -t $out/share/fonts/otf
install -D -m 444 *.woff -t $out/share/fonts/woff
install -D -m 444 *.woff2 -t $out/share/fonts/woff2
runHook postInstall
'';
meta = {
description = "Departure Mono is a monospaced pixel font with a lo-fi technical vibe";
homepage = "https://departuremono.com/";
license = lib.licenses.ofl;
platforms = lib.platforms.all;
maintainers = with lib.maintainers; [ drupol ];
};
})

View File

@ -1,12 +1,12 @@
{ stdenv
, fetchFromGitHub
, fetchpatch
, applyPatches
, libuuid
, bc
, lib
, buildPackages
, nixosTests
, runCommand
, writeScript
}:
@ -31,45 +31,68 @@ buildType = if stdenv.isDarwin then
else
"GCC5";
edk2 = stdenv.mkDerivation rec {
edk2 = stdenv.mkDerivation {
pname = "edk2";
version = "202402";
patches = [
# pass targetPrefix as an env var
(fetchpatch {
url = "https://src.fedoraproject.org/rpms/edk2/raw/08f2354cd280b4ce5a7888aa85cf520e042955c3/f/0021-Tweak-the-tools_def-to-support-cross-compiling.patch";
hash = "sha256-E1/fiFNVx0aB1kOej2DJ2DlBIs9tAAcxoedym2Zhjxw=";
})
# https://github.com/tianocore/edk2/pull/5658
(fetchpatch {
url = "https://github.com/tianocore/edk2/commit/a34ff4a8f69a7b8a52b9b299153a8fac702c7df1.patch";
hash = "sha256-u+niqwjuLV5tNPykW4xhb7PW2XvUmXhx5uvftG1UIbU=";
})
];
version = "202408";
srcWithVendoring = fetchFromGitHub {
owner = "tianocore";
repo = "edk2";
rev = "edk2-stable${edk2.version}";
fetchSubmodules = true;
hash = "sha256-Nurm6QNKCyV6wvbj0ELdYAL7mbZ0yg/tTwnEJ+N18ng=";
hash = "sha256-2odaTqiAZD5xduT0dwIYWj3gY/aFPVsTFbblIsEhBiA=";
};
# We don't want EDK2 to keep track of OpenSSL,
# they're frankly bad at it.
src = runCommand "edk2-unvendored-src" { } ''
cp --no-preserve=mode -r ${srcWithVendoring} $out
rm -rf $out/CryptoPkg/Library/OpensslLib/openssl
mkdir -p $out/CryptoPkg/Library/OpensslLib/openssl
tar --strip-components=1 -xf ${buildPackages.openssl.src} -C $out/CryptoPkg/Library/OpensslLib/openssl
chmod -R +w $out/
src = applyPatches {
name = "edk2-${edk2.version}-unvendored-src";
src = edk2.srcWithVendoring;
# Fix missing INT64_MAX include that edk2 explicitly does not provide
# via it's own <stdint.h>. Let's pull in openssl's definition instead:
sed -i $out/CryptoPkg/Library/OpensslLib/openssl/crypto/property/property_parse.c \
-e '1i #include "internal/numbers.h"'
'';
patches = [
# pass targetPrefix as an env var
(fetchpatch {
url = "https://src.fedoraproject.org/rpms/edk2/raw/08f2354cd280b4ce5a7888aa85cf520e042955c3/f/0021-Tweak-the-tools_def-to-support-cross-compiling.patch";
hash = "sha256-E1/fiFNVx0aB1kOej2DJ2DlBIs9tAAcxoedym2Zhjxw=";
})
# https://github.com/tianocore/edk2/pull/5658
(fetchpatch {
name = "fix-cross-compilation-antlr-dlg.patch";
url = "https://github.com/tianocore/edk2/commit/a34ff4a8f69a7b8a52b9b299153a8fac702c7df1.patch";
hash = "sha256-u+niqwjuLV5tNPykW4xhb7PW2XvUmXhx5uvftG1UIbU=";
})
];
postPatch = ''
# We don't want EDK2 to keep track of OpenSSL, they're frankly bad at it.
rm -r CryptoPkg/Library/OpensslLib/openssl
mkdir -p CryptoPkg/Library/OpensslLib/openssl
(
cd CryptoPkg/Library/OpensslLib/openssl
tar --strip-components=1 -xf ${buildPackages.openssl.src}
# Apply OpenSSL patches.
${lib.pipe buildPackages.openssl.patches [
(builtins.filter (
patch:
!builtins.elem (baseNameOf patch) [
# Exclude patches not required in this context.
"nix-ssl-cert-file.patch"
"openssl-disable-kernel-detection.patch"
"use-etc-ssl-certs-darwin.patch"
"use-etc-ssl-certs.patch"
]
))
(map (patch: "patch -p1 < ${patch}\n"))
lib.concatStrings
]}
)
# enable compilation using Clang
# https://bugzilla.tianocore.org/show_bug.cgi?id=4620
substituteInPlace BaseTools/Conf/tools_def.template --replace-fail \
'DEFINE CLANGPDB_WARNING_OVERRIDES = ' \
'DEFINE CLANGPDB_WARNING_OVERRIDES = -Wno-unneeded-internal-declaration '
'';
};
nativeBuildInputs = [ pythonEnv ];
depsBuildBuild = [ buildPackages.stdenv.cc buildPackages.bash ];
@ -100,12 +123,13 @@ edk2 = stdenv.mkDerivation rec {
enableParallelBuilding = true;
meta = with lib; {
meta = {
description = "Intel EFI development kit";
homepage = "https://github.com/tianocore/tianocore.github.io/wiki/EDK-II/";
changelog = "https://github.com/tianocore/edk2/releases/tag/edk2-stable${edk2.version}";
license = licenses.bsd2;
platforms = with platforms; aarch64 ++ arm ++ i686 ++ x86_64 ++ riscv64;
license = lib.licenses.bsd2;
platforms = with lib.platforms; aarch64 ++ arm ++ i686 ++ x86_64 ++ riscv64;
maintainers = [ lib.maintainers.mjoerg ];
};
passthru = {

View File

@ -17,16 +17,16 @@
rustPlatform.buildRustPackage rec {
pname = "eza";
version = "0.19.0";
version = "0.19.1";
src = fetchFromGitHub {
owner = "eza-community";
repo = "eza";
rev = "v${version}";
hash = "sha256-FhtgqfPQRUsnyi/qEe0PPtRfJIUa4UaNbvrkPvZpsQk=";
hash = "sha256-VV8tqVJq+bsgfdNSxSzo1vqYtYT37D2pBX4HydY6cKs=";
};
cargoHash = "sha256-z1jrCUstQk272EEeqcjGhm5b/YaxTFw21F+AbguMdmo=";
cargoHash = "sha256-SUvQxW3STsP1VrPJKK2NYbApuoGfbmfUiywZILvcvj4=";
nativeBuildInputs = [ cmake pkg-config installShellFiles pandoc ];
buildInputs = [ zlib ]

View File

@ -79,7 +79,7 @@ buildNpmPackage {
postBuild =
lib.optionalString stdenv.isDarwin ''
# electron-builder appears to build directly on top of Electron.app, by overwriting the files in the bundle.
cp -r ${electron}/Applications/Electron.app ./
cp -r ${electron.dist}/Electron.app ./
find ./Electron.app -name 'Info.plist' | xargs -d '\n' chmod +rw
# Disable code signing during build on macOS.
@ -90,7 +90,7 @@ buildNpmPackage {
+ ''
npm exec electron-builder -- \
--dir \
-c.electronDist=${if stdenv.isDarwin then "./" else "${electron}/libexec/electron"} \
-c.electronDist=${if stdenv.isDarwin then "./" else electron.dist} \
-c.electronVersion=${electron.version} \
-c.npmRebuild=false
'';

View File

@ -0,0 +1,36 @@
{
lib,
python3Packages,
fetchPypi,
ffmpeg,
}:
python3Packages.buildPythonApplication rec {
pname = "ffmpeg-normalize";
version = "1.28.3";
src = fetchPypi {
inherit pname version;
hash = "sha256-8wNPuVRQRQpFK6opgwqdKYMYmAFRqq8p/T5V9kC8QaY=";
};
propagatedBuildInputs = [
ffmpeg
python3Packages.ffmpeg-progress-yield
];
dependencies = with python3Packages; [ colorlog ];
checkPhase = ''
$out/bin/ffmpeg-normalize --help > /dev/null
'';
meta = {
description = "Normalize audio via ffmpeg";
homepage = "https://github.com/slhck/ffmpeg-normalize";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [
luftmensch-luftmensch
prusnak
];
mainProgram = "ffmpeg-normalize";
};
}

View File

@ -0,0 +1,91 @@
{
lib,
fetchFromGitHub,
stdenvNoCC,
nodejs,
fetchNpmDeps,
buildPackages,
php83,
nixosTests,
nix-update-script,
dataDir ? "/var/lib/firefly-iii-data-importer",
}:
let
pname = "firefly-iii-data-importer";
version = "1.5.4";
src = fetchFromGitHub {
owner = "firefly-iii";
repo = "data-importer";
rev = "v${version}";
hash = "sha256-XnPdoNtUoJpOpKVzQlFirh7u824H4xKAe2VRXfGIKeg=";
};
in
stdenvNoCC.mkDerivation (finalAttrs: {
inherit pname src version;
buildInputs = [ php83 ];
nativeBuildInputs = [
nodejs
nodejs.python
buildPackages.npmHooks.npmConfigHook
php83.composerHooks.composerInstallHook
php83.packages.composer-local-repo-plugin
];
composerNoDev = true;
composerNoPlugins = true;
composerNoScripts = true;
composerStrictValidation = true;
strictDeps = true;
vendorHash = "sha256-EjEco8zBR787eQuPhNsRScfuPQ6eS6TIJmMJOcmZA+Q=";
npmDeps = fetchNpmDeps {
inherit src;
name = "${pname}-npm-deps";
hash = "sha256-VP1wM0+ca17aQU4FJ9gSbT2Np/sxb8wZ4pCJ6FV1V7w=";
};
composerRepository = php83.mkComposerRepository {
inherit (finalAttrs)
pname
src
vendorHash
version
;
composerNoDev = true;
composerNoPlugins = true;
composerNoScripts = true;
composerStrictValidation = true;
};
preInstall = ''
npm run build --workspace=v2
'';
passthru = {
phpPackage = php83;
tests = nixosTests.firefly-iii-data-importer;
updateScript = nix-update-script { };
};
postInstall = ''
rm -R $out/share/php/firefly-iii-data-importer/{storage,bootstrap/cache,node_modules}
mv $out/share/php/firefly-iii-data-importer/* $out/
rm -R $out/share
ln -s ${dataDir}/storage $out/storage
ln -s ${dataDir}/cache $out/bootstrap/cache
'';
meta = {
changelog = "https://github.com/firefly-iii/data-importer/releases/tag/v${version}";
description = "Firefly III Data Importer can import data into Firefly III.";
homepage = "https://github.com/firefly-iii/data-importer";
license = lib.licenses.agpl3Only;
maintainers = [ lib.maintainers.savyajha ];
};
})

View File

@ -5,16 +5,16 @@
buildGoModule rec {
pname = "flarectl";
version = "0.102.0";
version = "0.103.0";
src = fetchFromGitHub {
owner = "cloudflare";
repo = "cloudflare-go";
rev = "v${version}";
hash = "sha256-i/JWbi8itjcFklknFGB23DtYh4+jd+2YMQysHtS3qf8=";
hash = "sha256-mYdZgHJz2Ajrk/JRbaDeghm39PWidnAIZvjJTvl8lpM=";
};
vendorHash = "sha256-4tJATAvWpWq1aTtV4ERTHF6S2D0azC3HlrwxkLIGT7s=";
vendorHash = "sha256-R3By8/cR4pZQgUSyNGDnnvWwcpZqraqk5GRZ8Om9JOU=";
subPackages = [ "cmd/flarectl" ];

View File

@ -1,33 +1,36 @@
{ stdenv
, lib
, fetchFromGitHub
, unstableGitUpdater
, alsa-lib
, libjack2
, pkg-config
, zlib
{
stdenv,
lib,
fetchFromGitHub,
unstableGitUpdater,
alsa-lib,
cmake,
libjack2,
pkg-config,
zlib,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "fmtoy";
version = "0-unstable-2024-06-07";
version = "0-unstable-2024-06-11";
src = fetchFromGitHub {
owner = "vampirefrog";
repo = "fmtoy";
rev = "1339600e2f5a4357f7a50f5c6ad49f3c7635adec";
hash = "sha256-1kjUPEklZyue/DYn0jSfmXLjF22C+im6klY+S5KCvhc=";
rev = "17d69350dcd7e2834e69f65420e5e3a8328b7e18";
fetchSubmodules = true;
hash = "sha256-to842vUWEWGSQkD09Q22whrdtZpbSlwaY5LSS208sP8=";
};
postPatch = ''
substituteInPlace Makefile \
--replace 'pkg-config' "$PKG_CONFIG"
--replace-fail 'pkg-config' "$PKG_CONFIG"
'';
strictDeps = true;
nativeBuildInputs = [
cmake
pkg-config
];
@ -37,6 +40,8 @@ stdenv.mkDerivation (finalAttrs: {
zlib
];
dontUseCmakeConfigure = true;
enableParallelBuilding = true;
buildFlags = [
@ -56,12 +61,12 @@ stdenv.mkDerivation (finalAttrs: {
updateScript = unstableGitUpdater { };
};
meta = with lib; {
meta = {
description = "FM synthesiser based on emulated Yamaha YM chips (OPL, OPM and OPN series)";
homepage = "https://github.com/vampirefrog/fmtoy";
license = licenses.gpl3Only;
license = lib.licenses.gpl3Only;
mainProgram = "fmtoy_jack";
maintainers = with maintainers; [ OPNA2608 ];
platforms = platforms.linux;
maintainers = with lib.maintainers; [ OPNA2608 ];
platforms = lib.platforms.linux;
};
})

View File

@ -28,13 +28,13 @@ let
pieBuild = stdenv.hostPlatform.isMusl;
in buildGoModule rec {
pname = "frankenphp";
version = "1.2.4";
version = "1.2.5";
src = fetchFromGitHub {
owner = "dunglas";
repo = "frankenphp";
rev = "v${version}";
hash = "sha256-ZM8/1u4wIBHUgq2x8zyDJhf+qFQz4u5fhLNLaqAv/54=";
hash = "sha256-X6lWbxgqj0wis/cljoNSh7AsH1zY30GTjSOAGXzUIek=";
};
sourceRoot = "${src.name}/caddy";
@ -42,7 +42,7 @@ in buildGoModule rec {
# frankenphp requires C code that would be removed with `go mod tidy`
# https://github.com/golang/go/issues/26366
proxyVendor = true;
vendorHash = "sha256-3Y5STb521iRois/KLQqdTxxTYdp39PTaiJEBjWrZsyw=";
vendorHash = "sha256-U2B0ok6TgqUPMwlnkzpPkJLG22S3VpoU80bWwZAeaJo=";
buildInputs = [ phpUnwrapped brotli ] ++ phpUnwrapped.buildInputs;
nativeBuildInputs = [ makeBinaryWrapper ] ++ lib.optionals stdenv.isDarwin [ pkg-config cctools darwin.autoSignDarwinBinariesHook ];

View File

@ -56,7 +56,7 @@ stdenv.mkDerivation (finalAttrs: {
npm exec electron-builder -- \
--dir \
-c.electronDist="${electron}/libexec/electron" \
-c.electronDist="${electron.dist}" \
-c.electronVersion="${electron.version}"
runHook postBuild

View File

@ -16,13 +16,13 @@
buildGoModule rec {
pname = "grafana-alloy";
version = "1.3.0";
version = "1.3.1";
src = fetchFromGitHub {
rev = "v${version}";
owner = "grafana";
repo = "alloy";
hash = "sha256-2OpBRSX/t6hwf1fHogrNTuDAmKArVXxwKHXuHyTXnYA=";
hash = "sha256-6YjQUIHZmuguzqTeaLgkrM/WdBPZu/KUXUDOmEB7rNQ=";
};
proxyVendor = true;

View File

@ -0,0 +1,43 @@
{
lib,
stdenv,
fetchurl,
pkg-config,
zstd,
libHX,
}:
stdenv.mkDerivation (finalAttrs: {
pname = "hxtools";
version = "20231224";
src = fetchurl {
url = "https://inai.de/files/hxtools/hxtools-${finalAttrs.version}.tar.zst";
hash = "sha256-TyT9bsp9qqGKQsSyWCfd2lH8ULjqJ5puMTw2TgWHV5c=";
};
nativeBuildInputs = [
pkg-config
zstd
];
buildInputs = [
libHX
];
strictDeps = true;
meta = {
homepage = "https://inai.de/projects/hxtools/";
description = "Collection of small tools over the years by j.eng";
# Taken from https://codeberg.org/jengelh/hxtools/src/branch/master/LICENSES.txt
license = with lib.licenses; [
mit
bsd2Patent
lgpl21Plus
gpl2Plus
];
maintainers = with lib.maintainers; [ meator ];
platforms = lib.platforms.all;
};
})

View File

@ -122,6 +122,9 @@ rustPlatform.buildRustPackage rec {
withSecretProvisioning = kanidm.override { enableSecretProvisioning = true; };
};
# can take over 4 hours on 2 cores and needs 16GB+ RAM
requiredSystemFeatures = [ "big-parallel" ];
meta = with lib; {
changelog = "https://github.com/kanidm/kanidm/releases/tag/v${version}";
description = "Simple, secure and fast identity management platform";

View File

@ -13,9 +13,6 @@
electron,
}:
let
electronDist = electron + (if stdenv.isDarwin then "/Applications" else "/libexec/electron");
in
stdenv.mkDerivation (finalAttrs: {
pname = "koodo-reader";
version = "1.6.7";
@ -52,7 +49,7 @@ stdenv.mkDerivation (finalAttrs: {
env.CSC_IDENTITY_AUTO_DISCOVERY = "false";
postBuild = ''
cp -r ${electronDist} electron-dist
cp -r ${electron.dist} electron-dist
chmod -R u+w electron-dist
yarn --offline run electron-builder --dir \
-c.electronDist=electron-dist \
@ -117,7 +114,7 @@ stdenv.mkDerivation (finalAttrs: {
meta = {
changelog = "https://github.com/troyeguo/koodo-reader/releases/tag/v${finalAttrs.version}";
description = "A cross-platform ebook reader";
description = "Cross-platform ebook reader";
longDescription = ''
A modern ebook manager and reader with sync and backup capacities
for Windows, macOS, Linux and Web

View File

@ -7,11 +7,11 @@
stdenvNoCC.mkDerivation (finalAttrs: {
pname = "loopwm";
version = "1.0.0";
version = "1.1.1";
src = fetchurl {
url = "https://github.com/MrKai77/Loop/releases/download/${finalAttrs.version}/Loop.zip";
hash = "sha256-1DQ6O6QkD04/meS0XaS0+vpr+vd5cfwGSehV8QVgYtI=";
hash = "sha256-eF8B4rmkyTtT0vWTcjdaNaWCHWSlPfS4uVV29L+wXiM=";
};
sourceRoot = ".";

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