Merge branch 'master' into haskell-updates

This commit is contained in:
Malte Brandy 2021-05-04 00:25:54 +02:00
commit 81b5682da3
No known key found for this signature in database
GPG key ID: 226A2D41EF5378C9
318 changed files with 13835 additions and 2196 deletions

View file

@ -513,3 +513,73 @@ If you do need to do create this sort of patch file, one way to do so is with gi
```ShellSession
$ git diff > nixpkgs/pkgs/the/package/0001-changes.patch
```
## Package tests {#sec-package-tests}
Tests are important to ensure quality and make reviews and automatic updates easy.
Nix package tests are a lightweight alternative to [NixOS module tests](https://nixos.org/manual/nixos/stable/#sec-nixos-tests). They can be used to create simple integration tests for packages while the module tests are used to test services or programs with a graphical user interface on a NixOS VM. Unittests that are included in the source code of a package should be executed in the `checkPhase`.
### Writing package tests {#ssec-package-tests-writing}
This is an example using the `phoronix-test-suite` package with the current best practices.
Add the tests in `passthru.tests` to the package definition like this:
```nix
{ stdenv, lib, fetchurl, callPackage }:
stdenv.mkDerivation {
passthru.tests = {
simple-execution = callPackage ./tests.nix { };
};
meta = { … };
}
```
Create `tests.nix` in the package directory:
```nix
{ runCommand, phoronix-test-suite }:
let
inherit (phoronix-test-suite) pname version;
in
runCommand "${pname}-tests" { meta.timeout = 3; }
''
# automatic initial setup to prevent interactive questions
${phoronix-test-suite}/bin/phoronix-test-suite enterprise-setup >/dev/null
# get version of installed program and compare with package version
if [[ `${phoronix-test-suite}/bin/phoronix-test-suite version` != *"${version}"* ]]; then
echo "Error: program version does not match package version"
exit 1
fi
# run dummy command
${phoronix-test-suite}/bin/phoronix-test-suite dummy_module.dummy-command >/dev/null
# needed for Nix to register the command as successful
touch $out
''
```
### Running package tests {#ssec-package-tests-running}
You can run these tests with:
```ShellSession
$ cd path/to/nixpkgs
$ nix-build -A phoronix-test-suite.tests
```
### Examples of package tests {#ssec-package-tests-examples}
Here are examples of package tests:
- [Jasmin compile test](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/compilers/jasmin/test-assemble-hello-world/default.nix)
- [Lobster compile test](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/compilers/lobster/test-can-run-hello-world.nix)
- [Spacy annotation test](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/python-modules/spacy/annotation-test/default.nix)
- [Libtorch test](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/libraries/science/math/libtorch/test/default.nix)
- [Multiple tests for nanopb](https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/libraries/nanopb/default.nix)

View file

@ -606,7 +606,7 @@ rec {
This function will fail if the input string is longer than the
requested length.
Type: fixedWidthString :: int -> string -> string
Type: fixedWidthString :: int -> string -> string -> string
Example:
fixedWidthString 5 "0" (toString 15)

View file

@ -337,7 +337,7 @@ rec {
};
shellPackage = package // {
check = x: (package.check x) && (hasAttr "shellPath" x);
check = x: isDerivation x && hasAttr "shellPath" x;
};
path = mkOptionType {

View file

@ -2177,6 +2177,12 @@
githubId = 990767;
name = "Daniel Olsen";
};
daneads = {
email = "me@daneads.com";
github = "daneads";
githubId = 24708079;
name = "Dan Eads";
};
danharaj = {
email = "dan@obsidian.systems";
github = "danharaj";
@ -2439,6 +2445,12 @@
githubId = 8404455;
name = "Diego Lelis";
};
diogox = {
name = "Diogo Xavier";
email = "13244408+diogox@users.noreply.github.com";
github = "diogox";
githubId = 13244408;
};
dipinhora = {
email = "dipinhora+github@gmail.com";
github = "dipinhora";
@ -3029,6 +3041,12 @@
fingerprint = "F178 B4B4 6165 6D1B 7C15 B55D 4029 3358 C7B9 326B";
}];
};
erikbackman = {
email = "contact@ebackman.net";
github = "erikbackman";
githubId = 46724898;
name = "Erik Backman";
};
erikryb = {
email = "erik.rybakken@math.ntnu.no";
github = "erikryb";
@ -3107,6 +3125,16 @@
githubId = 2147649;
name = "Euan Kemp";
};
evalexpr = {
name = "Jonathan Wilkins";
email = "nixos@wilkins.tech";
github = "evalexpr";
githubId = 23485511;
keys = [{
longkeyid = "rsa4096/0x2D1D402E17763DD6";
fingerprint = "8129 5B85 9C5A F703 C2F4 1E29 2D1D 402E 1776 3DD6";
}];
};
evanjs = {
email = "evanjsx@gmail.com";
github = "evanjs";
@ -4725,6 +4753,12 @@
githubId = 1102396;
name = "Jussi Maki";
};
joaquinito2051 = {
email = "joaquinito2051@gmail.com";
github = "heroku-miraheze";
githubId = 61781343;
name = "Joaquín Rufo Gutierrez";
};
jobojeha = {
email = "jobojeha@jeppener.de";
github = "jobojeha";
@ -6144,11 +6178,11 @@
fingerprint = "B573 5118 0375 A872 FBBF 7770 B629 036B E399 EEE9";
}];
};
mausch = {
email = "mauricioscheffer@gmail.com";
github = "mausch";
githubId = 95194;
name = "Mauricio Scheffer";
masipcat = {
email = "jordi@masip.cat";
github = "masipcat";
githubId = 775189;
name = "Jordi Masip";
};
matejc = {
email = "cotman.matej@gmail.com";
@ -6204,6 +6238,12 @@
githubId = 136037;
name = "Matthew Maurer";
};
mausch = {
email = "mauricioscheffer@gmail.com";
github = "mausch";
githubId = 95194;
name = "Mauricio Scheffer";
};
maxdamantus = {
email = "maxdamantus@gmail.com";
github = "Maxdamantus";
@ -10537,7 +10577,12 @@
githubId = 45292658;
name = "Julius Schmitt";
};
vojta001 = {
email = "vojtech.kane@gmail.com";
github = "vojta001";
githubId = 7038383;
name = "Vojta Káně";
};
volhovm = {
email = "volhovm.cs@gmail.com";
github = "volhovm";

View file

@ -144,6 +144,7 @@ with lib.maintainers; {
mguentner
ekleog
ralith
mjlbach
];
scope = "Maintain the ecosystem around Matrix, a decentralized messenger.";
};

View file

@ -330,7 +330,18 @@
</listitem>
<listitem>
<para>
<literal>vim</literal> switched to Python 3, dropping all Python 2 support.
<literal>vim</literal> and <literal>neovim</literal> switched to Python 3, dropping all Python 2 support.
</para>
</listitem>
<listitem>
<para>
<link linkend="opt-networking.wireguard.interfaces">networking.wireguard.interfaces.&lt;name&gt;.generatePrivateKeyFile</link>,
which is off by default, had a <literal>chmod</literal> race condition
fixed. As an aside, the parent directory's permissions were widened,
and the key files were made owner-writable.
This only affects newly created keys.
However, if the exact permissions are important for your setup, read
<link xlink:href="https://github.com/NixOS/nixpkgs/pull/121294">#121294</link>.
</para>
</listitem>
<listitem>
@ -692,6 +703,17 @@ environment.systemPackages = [
<literal>skip-kernel-setup true</literal> and takes care of setting forwarding and rp_filter sysctls by itself as well
as for each interface in <varname>services.babeld.interfaces</varname>.
</para>
</listitem>
<listitem>
<para>
The <option>services.zigbee2mqtt.config</option> option has been renamed to <option>services.zigbee2mqtt.settings</option> and
now follows <link xlink:href="https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md">RFC 0042</link>.
</para>
</listitem>
<listitem>
<para>
The <package>yadm</package> dotfile manager has been updated from 2.x to 3.x, which has new (XDG) default locations for some data/state files. Most yadm commands will fail and print a legacy path warning (which describes how to upgrade/migrate your repository). If you have scripts, daemons, scheduled jobs, shell profiles, etc. that invoke yadm, expect them to fail or misbehave until you perform this migration and prepare accordingly.
</para>
</listitem>
</itemizedlist>
</section>
@ -807,6 +829,23 @@ environment.systemPackages = [
default in the CLI tooling which in turn enables us to use
<literal>unbound-control</literal> without passing a custom configuration location.
</para>
<para>
The module has also been reworked to be <link
xlink:href="https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md">RFC
0042</link> compliant. As such,
<option>sevices.unbound.extraConfig</option> has been removed and replaced
by <xref linkend="opt-services.unbound.settings"/>. <option>services.unbound.interfaces</option>
has been renamed to <option>services.unbound.settings.server.interface</option>.
</para>
<para>
<option>services.unbound.forwardAddresses</option> and
<option>services.unbound.allowedAccess</option> have also been changed to
use the new settings interface. You can follow the instructions when
executing <literal>nixos-rebuild</literal> to upgrade your configuration to
use the new interface.
</para>
</listitem>
<listitem>
<para>
@ -978,6 +1017,24 @@ environment.systemPackages = [
PostgreSQL 9.5 is scheduled EOL during the 21.05 life cycle and has been removed.
</para>
</listitem>
<listitem>
<para>
<link xlink:href="https://www.xfce.org/">Xfce4</link> relies on
GIO/GVfs for userspace virtual filesystem access in applications
like <link xlink:href="https://docs.xfce.org/xfce/thunar/">thunar</link> and
<link xlink:href="https://docs.xfce.org/apps/gigolo/">gigolo</link>.
For that to work, the gvfs nixos service is enabled by default,
and it can be configured with the specific package that provides
GVfs. Until now Xfce4 was setting it to use a lighter version of
GVfs (without support for samba). To avoid conflicts with other
desktop environments this setting has been dropped. Users that
still want it should add the following to their system
configuration:
<programlisting>
<xref linkend="opt-services.gvfs.package" /> = pkgs.gvfs.override { samba = null; };
</programlisting>
</para>
</listitem>
</itemizedlist>
</section>
</section>

View file

@ -54,8 +54,13 @@ rec {
};
# Run an automated test suite in the given virtual network.
# `driver' is the script that runs the network.
runTests = driver:
runTests = {
# the script that runs the network
driver,
# a source position in the format of builtins.unsafeGetAttrPos
# for meta.position
pos,
}:
stdenv.mkDerivation {
name = "vm-test-run-${driver.testName}";
@ -69,6 +74,8 @@ rec {
'';
passthru = driver.passthru;
inherit pos;
};
@ -79,6 +86,11 @@ rec {
# Skip linting (mainly intended for faster dev cycles)
, skipLint ? false
, passthru ? {}
, # For meta.position
pos ? # position used in error messages and for meta.position
(if t.meta.description or null != null
then builtins.unsafeGetAttrPos "description" t.meta
else builtins.unsafeGetAttrPos "testScript" t)
, ...
} @ t:
let
@ -174,7 +186,7 @@ rec {
driver = mkDriver null;
driverInteractive = mkDriver pkgs.qemu;
test = passMeta (runTests driver);
test = passMeta (runTests { inherit driver pos; });
nodeNames = builtins.attrNames driver.nodes;
invalidNodeNames = lib.filter

View file

@ -41,7 +41,7 @@ in {
sizeMB = mkOption {
type = with types; either (enum [ "auto" ]) int;
default = "auto";
default = if config.ec2.hvm then 2048 else 8192;
example = 8192;
description = "The size in MB of the image";
};

View file

@ -126,6 +126,13 @@ in
'';
};
expandOnBoot = mkOption {
type = types.bool;
default = true;
description = ''
Whether to configure the sd image to expand it's partition on boot.
'';
};
};
config = {
@ -215,7 +222,7 @@ in
'';
}) {};
boot.postBootCommands = ''
boot.postBootCommands = lib.mkIf config.sdImage.expandOnBoot ''
# On the first boot do some maintenance tasks
if [ -f /nix-path-registration ]; then
set -euo pipefail

View file

@ -114,6 +114,9 @@
./programs/autojump.nix
./programs/bandwhich.nix
./programs/bash/bash.nix
./programs/bash/bash-completion.nix
./programs/bash/ls-colors.nix
./programs/bash/undistract-me.nix
./programs/bash-my-aws.nix
./programs/bcc.nix
./programs/browserpass.nix
@ -130,6 +133,7 @@
./programs/droidcam.nix
./programs/environment.nix
./programs/evince.nix
./programs/feedbackd.nix
./programs/file-roller.nix
./programs/firejail.nix
./programs/fish.nix
@ -163,6 +167,7 @@
./programs/partition-manager.nix
./programs/plotinus.nix
./programs/proxychains.nix
./programs/phosh.nix
./programs/qt5ct.nix
./programs/screen.nix
./programs/sedutil.nix
@ -509,6 +514,7 @@
./services/misc/mame.nix
./services/misc/matrix-appservice-discord.nix
./services/misc/matrix-appservice-irc.nix
./services/misc/matrix-dendrite.nix
./services/misc/matrix-synapse.nix
./services/misc/mautrix-telegram.nix
./services/misc/mbpfan.nix
@ -975,6 +981,7 @@
./services/web-servers/shellinabox.nix
./services/web-servers/tomcat.nix
./services/web-servers/traefik.nix
./services/web-servers/trafficserver.nix
./services/web-servers/ttyd.nix
./services/web-servers/uwsgi.nix
./services/web-servers/varnish/default.nix

View file

@ -0,0 +1,37 @@
{ config, lib, pkgs, ... }:
with lib;
let
enable = config.programs.bash.enableCompletion;
in
{
options = {
programs.bash.enableCompletion = mkEnableOption "Bash completion for all interactive bash shells" // {
default = true;
};
};
config = mkIf enable {
programs.bash.promptPluginInit = ''
# Check whether we're running a version of Bash that has support for
# programmable completion. If we do, enable all modules installed in
# the system and user profile in obsolete /etc/bash_completion.d/
# directories. Bash loads completions in all
# $XDG_DATA_DIRS/bash-completion/completions/
# on demand, so they do not need to be sourced here.
if shopt -q progcomp &>/dev/null; then
. "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh"
nullglobStatus=$(shopt -p nullglob)
shopt -s nullglob
for p in $NIX_PROFILES; do
for m in "$p/etc/bash_completion.d/"*; do
. $m
done
done
eval "$nullglobStatus"
unset nullglobStatus p m
fi
'';
};
}

View file

@ -11,31 +11,6 @@ let
cfg = config.programs.bash;
bashCompletion = optionalString cfg.enableCompletion ''
# Check whether we're running a version of Bash that has support for
# programmable completion. If we do, enable all modules installed in
# the system and user profile in obsolete /etc/bash_completion.d/
# directories. Bash loads completions in all
# $XDG_DATA_DIRS/bash-completion/completions/
# on demand, so they do not need to be sourced here.
if shopt -q progcomp &>/dev/null; then
. "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh"
nullglobStatus=$(shopt -p nullglob)
shopt -s nullglob
for p in $NIX_PROFILES; do
for m in "$p/etc/bash_completion.d/"*; do
. $m
done
done
eval "$nullglobStatus"
unset nullglobStatus p m
fi
'';
lsColors = optionalString cfg.enableLsColors ''
eval "$(${pkgs.coreutils}/bin/dircolors -b)"
'';
bashAliases = concatStringsSep "\n" (
mapAttrsFlatten (k: v: "alias ${k}=${escapeShellArg v}")
(filterAttrs (k: v: v != null) cfg.shellAliases)
@ -123,20 +98,13 @@ in
type = types.lines;
};
enableCompletion = mkOption {
default = true;
promptPluginInit = mkOption {
default = "";
description = ''
Enable Bash completion for all interactive bash shells.
Shell script code used to initialise bash prompt plugins.
'';
type = types.bool;
};
enableLsColors = mkOption {
default = true;
description = ''
Enable extra colors in directory listings.
'';
type = types.bool;
type = types.lines;
internal = true;
};
};
@ -167,8 +135,7 @@ in
set +h
${cfg.promptInit}
${bashCompletion}
${lsColors}
${cfg.promptPluginInit}
${bashAliases}
${cfge.interactiveShellInit}

View file

@ -0,0 +1,20 @@
{ config, lib, pkgs, ... }:
with lib;
let
enable = config.programs.bash.enableLsColors;
in
{
options = {
programs.bash.enableLsColors = mkEnableOption "extra colors in directory listings" // {
default = true;
};
};
config = mkIf enable {
programs.bash.promptPluginInit = ''
eval "$(${pkgs.coreutils}/bin/dircolors -b)"
'';
};
}

View file

@ -0,0 +1,36 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.bash.undistractMe;
in
{
options = {
programs.bash.undistractMe = {
enable = mkEnableOption "notifications when long-running terminal commands complete";
playSound = mkEnableOption "notification sounds when long-running terminal commands complete";
timeout = mkOption {
default = 10;
description = ''
Number of seconds it would take for a command to be considered long-running.
'';
type = types.int;
};
};
};
config = mkIf cfg.enable {
programs.bash.promptPluginInit = ''
export LONG_RUNNING_COMMAND_TIMEOUT=${toString cfg.timeout}
export UDM_PLAY_SOUND=${if cfg.playSound then "1" else "0"}
. "${pkgs.undistract-me}/etc/profile.d/undistract-me.sh"
'';
};
meta = {
maintainers = with maintainers; [ metadark ];
};
}

View file

@ -0,0 +1,32 @@
{ pkgs, lib, config, ... }:
with lib;
let
cfg = config.programs.feedbackd;
in {
options = {
programs.feedbackd = {
enable = mkEnableOption ''
Whether to enable the feedbackd D-BUS service and udev rules.
Your user needs to be in the `feedbackd` group to trigger effects.
'';
package = mkOption {
description = ''
Which feedbackd package to use.
'';
type = types.package;
default = pkgs.feedbackd;
};
};
};
config = mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
services.dbus.packages = [ cfg.package ];
services.udev.packages = [ cfg.package ];
users.groups.feedbackd = {};
};
}

View file

@ -0,0 +1,167 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.phosh;
# Based on https://source.puri.sm/Librem5/librem5-base/-/blob/4596c1056dd75ac7f043aede07887990fd46f572/default/sm.puri.OSK0.desktop
oskItem = pkgs.makeDesktopItem {
name = "sm.puri.OSK0";
type = "Application";
desktopName = "On-screen keyboard";
exec = "${pkgs.squeekboard}/bin/squeekboard";
categories = "GNOME;Core;";
extraEntries = ''
OnlyShowIn=GNOME;
NoDisplay=true
X-GNOME-Autostart-Phase=Panel
X-GNOME-Provides=inputmethod
X-GNOME-Autostart-Notify=true
X-GNOME-AutoRestart=true
'';
};
phocConfigType = types.submodule {
options = {
xwayland = mkOption {
description = ''
Whether to enable XWayland support.
To start XWayland immediately, use `immediate`.
'';
type = types.enum [ "true" "false" "immediate" ];
default = "false";
};
cursorTheme = mkOption {
description = ''
Cursor theme to use in Phosh.
'';
type = types.str;
default = "default";
};
outputs = mkOption {
description = ''
Output configurations.
'';
type = types.attrsOf phocOutputType;
default = {
DSI-1 = {
scale = 2;
};
};
};
};
};
phocOutputType = types.submodule {
options = {
modeline = mkOption {
description = ''
One or more modelines.
'';
type = types.either types.str (types.listOf types.str);
default = [];
example = [
"87.25 720 776 848 976 1440 1443 1453 1493 -hsync +vsync"
"65.13 768 816 896 1024 1024 1025 1028 1060 -HSync +VSync"
];
};
mode = mkOption {
description = ''
Default video mode.
'';
type = types.nullOr types.str;
default = null;
example = "768x1024";
};
scale = mkOption {
description = ''
Display scaling factor.
'';
type = types.nullOr types.ints.unsigned;
default = null;
example = 2;
};
rotate = mkOption {
description = ''
Screen transformation.
'';
type = types.enum [
"90" "180" "270" "flipped" "flipped-90" "flipped-180" "flipped-270" null
];
default = null;
};
};
};
optionalKV = k: v: if v == null then "" else "${k} = ${builtins.toString v}";
renderPhocOutput = name: output: let
modelines = if builtins.isList output.modeline
then output.modeline
else [ output.modeline ];
renderModeline = l: "modeline = ${l}";
in ''
[output:${name}]
${concatStringsSep "\n" (map renderModeline modelines)}
${optionalKV "mode" output.mode}
${optionalKV "scale" output.scale}
${optionalKV "rotate" output.rotate}
'';
renderPhocConfig = phoc: let
outputs = mapAttrsToList renderPhocOutput phoc.outputs;
in ''
[core]
xwayland = ${phoc.xwayland}
${concatStringsSep "\n" outputs}
[cursor]
theme = ${phoc.cursorTheme}
'';
in {
options = {
programs.phosh = {
enable = mkEnableOption ''
Whether to enable, Phosh, related packages and default configurations.
'';
phocConfig = mkOption {
description = ''
Configurations for the Phoc compositor.
'';
type = types.oneOf [ types.lines types.path phocConfigType ];
default = {};
};
};
};
config = mkIf cfg.enable {
environment.systemPackages = [
pkgs.phoc
pkgs.phosh
pkgs.squeekboard
oskItem
];
programs.feedbackd.enable = true;
# https://source.puri.sm/Librem5/phosh/-/issues/303
security.pam.services.phosh = {
text = ''
auth requisite pam_nologin.so
auth required pam_succeed_if.so user != root quiet_success
auth required pam_securetty.so
auth requisite pam_nologin.so
'';
};
services.gnome3.core-shell.enable = true;
services.gnome3.core-os-services.enable = true;
services.xserver.displayManager.sessionPackages = [ pkgs.phosh ];
environment.etc."phosh/phoc.ini".source =
if builtins.isPath cfg.phocConfig then cfg.phocConfig
else if builtins.isString cfg.phocConfig then pkgs.writeText "phoc.ini" cfg.phocConfig
else pkgs.writeText "phoc.ini" (renderPhocConfig cfg.phocConfig);
};
}

View file

@ -145,7 +145,7 @@ in
extraOpts = mkOption {
description = "Kubernetes apiserver extra command line options.";
default = "";
type = str;
type = separatedString " ";
};
extraSANs = mkOption {

View file

@ -38,7 +38,7 @@ in
extraOpts = mkOption {
description = "Kubernetes controller manager extra command line options.";
default = "";
type = str;
type = separatedString " ";
};
featureGates = mkOption {

View file

@ -142,7 +142,7 @@ in
extraOpts = mkOption {
description = "Kubernetes kubelet extra command line options.";
default = "";
type = str;
type = separatedString " ";
};
featureGates = mkOption {

View file

@ -25,7 +25,7 @@ in
extraOpts = mkOption {
description = "Kubernetes proxy extra command line options.";
default = "";
type = str;
type = separatedString " ";
};
featureGates = mkOption {

View file

@ -21,7 +21,7 @@ in
extraOpts = mkOption {
description = "Kubernetes scheduler extra command line options.";
default = "";
type = str;
type = separatedString " ";
};
featureGates = mkOption {

View file

@ -76,7 +76,7 @@ let
};
tags = mkOption {
type = types.attrsOf types.str;
type = types.attrsOf (types.either types.str (types.listOf types.str));
default = {};
example = { queue = "default"; docker = "true"; ruby2 ="true"; };
description = ''
@ -230,7 +230,11 @@ in
## don't end up in the Nix store.
preStart = let
sshDir = "${cfg.dataDir}/.ssh";
tagStr = lib.concatStringsSep "," (lib.mapAttrsToList (name: value: "${name}=${value}") cfg.tags);
tagStr = name: value:
if lib.isList value
then lib.concatStringsSep "," (builtins.map (v: "${name}=${v}") value)
else "${name}=${value}";
tagsStr = lib.concatStringsSep "," (lib.mapAttrsToList tagStr cfg.tags);
in
optionalString (cfg.privateSshKeyPath != null) ''
mkdir -m 0700 -p "${sshDir}"
@ -241,7 +245,7 @@ in
token="$(cat ${toString cfg.tokenPath})"
name="${cfg.name}"
shell="${cfg.shell}"
tags="${tagStr}"
tags="${tagsStr}"
build-path="${cfg.dataDir}/builds"
hooks-path="${cfg.hooksPath}"
${cfg.extraConfig}

View file

@ -1,79 +1,108 @@
{ config, lib, pkgs, ... }:
with lib;
let
inherit (lib)
concatStringsSep
flip
literalExample
optionalAttrs
optionals
recursiveUpdate
mkEnableOption
mkIf
mkOption
types
versionAtLeast
;
cfg = config.services.cassandra;
defaultUser = "cassandra";
cassandraConfig = flip recursiveUpdate cfg.extraConfig
({ commitlog_sync = "batch";
commitlog_sync_batch_window_in_ms = 2;
start_native_transport = cfg.allowClients;
cluster_name = cfg.clusterName;
partitioner = "org.apache.cassandra.dht.Murmur3Partitioner";
endpoint_snitch = "SimpleSnitch";
data_file_directories = [ "${cfg.homeDir}/data" ];
commitlog_directory = "${cfg.homeDir}/commitlog";
saved_caches_directory = "${cfg.homeDir}/saved_caches";
} // (lib.optionalAttrs (cfg.seedAddresses != []) {
seed_provider = [{
class_name = "org.apache.cassandra.locator.SimpleSeedProvider";
parameters = [ { seeds = concatStringsSep "," cfg.seedAddresses; } ];
}];
}) // (lib.optionalAttrs (lib.versionAtLeast cfg.package.version "3") {
hints_directory = "${cfg.homeDir}/hints";
})
);
cassandraConfigWithAddresses = cassandraConfig //
( if cfg.listenAddress == null
then { listen_interface = cfg.listenInterface; }
else { listen_address = cfg.listenAddress; }
) // (
if cfg.rpcAddress == null
then { rpc_interface = cfg.rpcInterface; }
else { rpc_address = cfg.rpcAddress; }
);
cassandraEtc = pkgs.stdenv.mkDerivation
{ name = "cassandra-etc";
cassandraYaml = builtins.toJSON cassandraConfigWithAddresses;
cassandraEnvPkg = "${cfg.package}/conf/cassandra-env.sh";
cassandraLogbackConfig = pkgs.writeText "logback.xml" cfg.logbackConfig;
passAsFile = [ "extraEnvSh" ];
inherit (cfg) extraEnvSh;
buildCommand = ''
mkdir -p "$out"
echo "$cassandraYaml" > "$out/cassandra.yaml"
ln -s "$cassandraLogbackConfig" "$out/logback.xml"
cassandraConfig = flip recursiveUpdate cfg.extraConfig (
{
commitlog_sync = "batch";
commitlog_sync_batch_window_in_ms = 2;
start_native_transport = cfg.allowClients;
cluster_name = cfg.clusterName;
partitioner = "org.apache.cassandra.dht.Murmur3Partitioner";
endpoint_snitch = "SimpleSnitch";
data_file_directories = [ "${cfg.homeDir}/data" ];
commitlog_directory = "${cfg.homeDir}/commitlog";
saved_caches_directory = "${cfg.homeDir}/saved_caches";
} // optionalAttrs (cfg.seedAddresses != [ ]) {
seed_provider = [
{
class_name = "org.apache.cassandra.locator.SimpleSeedProvider";
parameters = [{ seeds = concatStringsSep "," cfg.seedAddresses; }];
}
];
} // optionalAttrs (versionAtLeast cfg.package.version "3") {
hints_directory = "${cfg.homeDir}/hints";
}
);
( cat "$cassandraEnvPkg"
echo "# lines from services.cassandra.extraEnvSh: "
cat "$extraEnvShPath"
) > "$out/cassandra-env.sh"
cassandraConfigWithAddresses = cassandraConfig // (
if cfg.listenAddress == null
then { listen_interface = cfg.listenInterface; }
else { listen_address = cfg.listenAddress; }
) // (
if cfg.rpcAddress == null
then { rpc_interface = cfg.rpcInterface; }
else { rpc_address = cfg.rpcAddress; }
);
# Delete default JMX Port, otherwise we can't set it using env variable
sed -i '/JMX_PORT="7199"/d' "$out/cassandra-env.sh"
cassandraEtc = pkgs.stdenv.mkDerivation {
name = "cassandra-etc";
# Delete default password file
sed -i '/-Dcom.sun.management.jmxremote.password.file=\/etc\/cassandra\/jmxremote.password/d' "$out/cassandra-env.sh"
'';
};
defaultJmxRolesFile = builtins.foldl'
(left: right: left + right) ""
(map (role: "${role.username} ${role.password}") cfg.jmxRoles);
fullJvmOptions = cfg.jvmOpts
++ lib.optionals (cfg.jmxRoles != []) [
cassandraYaml = builtins.toJSON cassandraConfigWithAddresses;
cassandraEnvPkg = "${cfg.package}/conf/cassandra-env.sh";
cassandraLogbackConfig = pkgs.writeText "logback.xml" cfg.logbackConfig;
passAsFile = [ "extraEnvSh" ];
inherit (cfg) extraEnvSh;
buildCommand = ''
mkdir -p "$out"
echo "$cassandraYaml" > "$out/cassandra.yaml"
ln -s "$cassandraLogbackConfig" "$out/logback.xml"
( cat "$cassandraEnvPkg"
echo "# lines from services.cassandra.extraEnvSh: "
cat "$extraEnvShPath"
) > "$out/cassandra-env.sh"
# Delete default JMX Port, otherwise we can't set it using env variable
sed -i '/JMX_PORT="7199"/d' "$out/cassandra-env.sh"
# Delete default password file
sed -i '/-Dcom.sun.management.jmxremote.password.file=\/etc\/cassandra\/jmxremote.password/d' "$out/cassandra-env.sh"
'';
};
defaultJmxRolesFile =
builtins.foldl'
(left: right: left + right) ""
(map (role: "${role.username} ${role.password}") cfg.jmxRoles);
fullJvmOptions =
cfg.jvmOpts
++ optionals (cfg.jmxRoles != [ ]) [
"-Dcom.sun.management.jmxremote.authenticate=true"
"-Dcom.sun.management.jmxremote.password.file=${cfg.jmxRolesFile}"
]
++ lib.optionals cfg.remoteJmx [
] ++ optionals cfg.remoteJmx [
"-Djava.rmi.server.hostname=${cfg.rpcAddress}"
];
in {
in
{
options.services.cassandra = {
enable = mkEnableOption ''
Apache Cassandra Scalable and highly available database.
'';
clusterName = mkOption {
type = types.str;
default = "Test Cluster";
@ -83,16 +112,19 @@ in {
another. All nodes in a cluster must have the same value.
'';
};
user = mkOption {
type = types.str;
default = defaultUser;
description = "Run Apache Cassandra under this user.";
};
group = mkOption {
type = types.str;
default = defaultUser;
description = "Run Apache Cassandra under this group.";
};
homeDir = mkOption {
type = types.path;
default = "/var/lib/cassandra";
@ -100,6 +132,7 @@ in {
Home directory for Apache Cassandra.
'';
};
package = mkOption {
type = types.package;
default = pkgs.cassandra;
@ -109,17 +142,19 @@ in {
The Apache Cassandra package to use.
'';
};
jvmOpts = mkOption {
type = types.listOf types.str;
default = [];
default = [ ];
description = ''
Populate the JVM_OPT environment variable.
'';
};
listenAddress = mkOption {
type = types.nullOr types.str;
default = "127.0.0.1";
example = literalExample "null";
example = null;
description = ''
Address or interface to bind to and tell other Cassandra nodes
to connect to. You _must_ change this if you want multiple
@ -136,6 +171,7 @@ in {
Setting listen_address to 0.0.0.0 is always wrong.
'';
};
listenInterface = mkOption {
type = types.nullOr types.str;
default = null;
@ -146,10 +182,11 @@ in {
supported.
'';
};
rpcAddress = mkOption {
type = types.nullOr types.str;
default = "127.0.0.1";
example = literalExample "null";
example = null;
description = ''
The address or interface to bind the native transport server to.
@ -167,6 +204,7 @@ in {
internet. Firewall it if needed.
'';
};
rpcInterface = mkOption {
type = types.nullOr types.str;
default = null;
@ -176,6 +214,7 @@ in {
correspond to a single address, IP aliasing is not supported.
'';
};
logbackConfig = mkOption {
type = types.lines;
default = ''
@ -197,6 +236,7 @@ in {
XML logback configuration for cassandra
'';
};
seedAddresses = mkOption {
type = types.listOf types.str;
default = [ "127.0.0.1" ];
@ -207,6 +247,7 @@ in {
Set to 127.0.0.1 for a single node cluster.
'';
};
allowClients = mkOption {
type = types.bool;
default = true;
@ -219,16 +260,19 @@ in {
<literal>extraConfig</literal>.
'';
};
extraConfig = mkOption {
type = types.attrs;
default = {};
default = { };
example =
{ commitlog_sync_batch_window_in_ms = 3;
{
commitlog_sync_batch_window_in_ms = 3;
};
description = ''
Extra options to be merged into cassandra.yaml as nix attribute set.
'';
};
extraEnvSh = mkOption {
type = types.lines;
default = "";
@ -237,48 +281,53 @@ in {
Extra shell lines to be appended onto cassandra-env.sh.
'';
};
fullRepairInterval = mkOption {
type = types.nullOr types.str;
default = "3w";
example = literalExample "null";
example = null;
description = ''
Set the interval how often full repairs are run, i.e.
<literal>nodetool repair --full</literal> is executed. See
https://cassandra.apache.org/doc/latest/operating/repair.html
for more information.
Set the interval how often full repairs are run, i.e.
<literal>nodetool repair --full</literal> is executed. See
https://cassandra.apache.org/doc/latest/operating/repair.html
for more information.
Set to <literal>null</literal> to disable full repairs.
'';
Set to <literal>null</literal> to disable full repairs.
'';
};
fullRepairOptions = mkOption {
type = types.listOf types.str;
default = [];
default = [ ];
example = [ "--partitioner-range" ];
description = ''
Options passed through to the full repair command.
'';
Options passed through to the full repair command.
'';
};
incrementalRepairInterval = mkOption {
type = types.nullOr types.str;
default = "3d";
example = literalExample "null";
example = null;
description = ''
Set the interval how often incremental repairs are run, i.e.
<literal>nodetool repair</literal> is executed. See
https://cassandra.apache.org/doc/latest/operating/repair.html
for more information.
Set the interval how often incremental repairs are run, i.e.
<literal>nodetool repair</literal> is executed. See
https://cassandra.apache.org/doc/latest/operating/repair.html
for more information.
Set to <literal>null</literal> to disable incremental repairs.
'';
Set to <literal>null</literal> to disable incremental repairs.
'';
};
incrementalRepairOptions = mkOption {
type = types.listOf types.str;
default = [];
default = [ ];
example = [ "--partitioner-range" ];
description = ''
Options passed through to the incremental repair command.
'';
Options passed through to the incremental repair command.
'';
};
maxHeapSize = mkOption {
type = types.nullOr types.str;
default = null;
@ -299,6 +348,7 @@ in {
expensive GC will be (usually).
'';
};
heapNewSize = mkOption {
type = types.nullOr types.str;
default = null;
@ -322,6 +372,7 @@ in {
100 MB per physical CPU core.
'';
};
mallocArenaMax = mkOption {
type = types.nullOr types.int;
default = null;
@ -330,6 +381,7 @@ in {
Set this to control the amount of arenas per-thread in glibc.
'';
};
remoteJmx = mkOption {
type = types.bool;
default = false;
@ -341,6 +393,7 @@ in {
See: https://wiki.apache.org/cassandra/JmxSecurity
'';
};
jmxPort = mkOption {
type = types.int;
default = 7199;
@ -351,8 +404,9 @@ in {
Firewall it if needed.
'';
};
jmxRoles = mkOption {
default = [];
default = [ ];
description = ''
Roles that are allowed to access the JMX (e.g. nodetool)
BEWARE: The passwords will be stored world readable in the nix-store.
@ -375,11 +429,13 @@ in {
};
});
};
jmxRolesFile = mkOption {
type = types.nullOr types.path;
default = if (lib.versionAtLeast cfg.package.version "3.11")
then pkgs.writeText "jmx-roles-file" defaultJmxRolesFile
else null;
default =
if versionAtLeast cfg.package.version "3.11"
then pkgs.writeText "jmx-roles-file" defaultJmxRolesFile
else null;
example = "/var/lib/cassandra/jmx.password";
description = ''
Specify your own jmx roles file.
@ -391,102 +447,115 @@ in {
};
config = mkIf cfg.enable {
assertions =
[ { assertion = (cfg.listenAddress == null) != (cfg.listenInterface == null);
message = "You have to set either listenAddress or listenInterface";
}
{ assertion = (cfg.rpcAddress == null) != (cfg.rpcInterface == null);
message = "You have to set either rpcAddress or rpcInterface";
}
{ assertion = (cfg.maxHeapSize == null) == (cfg.heapNewSize == null);
message = "If you set either of maxHeapSize or heapNewSize you have to set both";
}
{ assertion = cfg.remoteJmx -> cfg.jmxRolesFile != null;
message = ''
If you want JMX available remotely you need to set a password using
<literal>jmxRoles</literal> or <literal>jmxRolesFile</literal> if
using Cassandra older than v3.11.
'';
}
];
assertions = [
{
assertion = (cfg.listenAddress == null) != (cfg.listenInterface == null);
message = "You have to set either listenAddress or listenInterface";
}
{
assertion = (cfg.rpcAddress == null) != (cfg.rpcInterface == null);
message = "You have to set either rpcAddress or rpcInterface";
}
{
assertion = (cfg.maxHeapSize == null) == (cfg.heapNewSize == null);
message = "If you set either of maxHeapSize or heapNewSize you have to set both";
}
{
assertion = cfg.remoteJmx -> cfg.jmxRolesFile != null;
message = ''
If you want JMX available remotely you need to set a password using
<literal>jmxRoles</literal> or <literal>jmxRolesFile</literal> if
using Cassandra older than v3.11.
'';
}
];
users = mkIf (cfg.user == defaultUser) {
extraUsers.${defaultUser} =
{ group = cfg.group;
home = cfg.homeDir;
createHome = true;
uid = config.ids.uids.cassandra;
description = "Cassandra service user";
};
extraGroups.${defaultUser}.gid = config.ids.gids.cassandra;
users.${defaultUser} = {
group = cfg.group;
home = cfg.homeDir;
createHome = true;
uid = config.ids.uids.cassandra;
description = "Cassandra service user";
};
groups.${defaultUser}.gid = config.ids.gids.cassandra;
};
systemd.services.cassandra =
{ description = "Apache Cassandra service";
after = [ "network.target" ];
environment =
{ CASSANDRA_CONF = "${cassandraEtc}";
JVM_OPTS = builtins.concatStringsSep " " fullJvmOptions;
MAX_HEAP_SIZE = toString cfg.maxHeapSize;
HEAP_NEWSIZE = toString cfg.heapNewSize;
MALLOC_ARENA_MAX = toString cfg.mallocArenaMax;
LOCAL_JMX = if cfg.remoteJmx then "no" else "yes";
JMX_PORT = toString cfg.jmxPort;
};
wantedBy = [ "multi-user.target" ];
serviceConfig =
{ User = cfg.user;
Group = cfg.group;
ExecStart = "${cfg.package}/bin/cassandra -f";
SuccessExitStatus = 143;
};
systemd.services.cassandra = {
description = "Apache Cassandra service";
after = [ "network.target" ];
environment = {
CASSANDRA_CONF = "${cassandraEtc}";
JVM_OPTS = builtins.concatStringsSep " " fullJvmOptions;
MAX_HEAP_SIZE = toString cfg.maxHeapSize;
HEAP_NEWSIZE = toString cfg.heapNewSize;
MALLOC_ARENA_MAX = toString cfg.mallocArenaMax;
LOCAL_JMX = if cfg.remoteJmx then "no" else "yes";
JMX_PORT = toString cfg.jmxPort;
};
wantedBy = [ "multi-user.target" ];
serviceConfig = {
User = cfg.user;
Group = cfg.group;
ExecStart = "${cfg.package}/bin/cassandra -f";
SuccessExitStatus = 143;
};
};
systemd.services.cassandra-full-repair =
{ description = "Perform a full repair on this Cassandra node";
after = [ "cassandra.service" ];
requires = [ "cassandra.service" ];
serviceConfig =
{ User = cfg.user;
Group = cfg.group;
ExecStart =
lib.concatStringsSep " "
([ "${cfg.package}/bin/nodetool" "repair" "--full"
] ++ cfg.fullRepairOptions);
};
systemd.services.cassandra-full-repair = {
description = "Perform a full repair on this Cassandra node";
after = [ "cassandra.service" ];
requires = [ "cassandra.service" ];
serviceConfig = {
User = cfg.user;
Group = cfg.group;
ExecStart =
concatStringsSep " "
([
"${cfg.package}/bin/nodetool"
"repair"
"--full"
] ++ cfg.fullRepairOptions);
};
};
systemd.timers.cassandra-full-repair =
mkIf (cfg.fullRepairInterval != null) {
description = "Schedule full repairs on Cassandra";
wantedBy = [ "timers.target" ];
timerConfig =
{ OnBootSec = cfg.fullRepairInterval;
OnUnitActiveSec = cfg.fullRepairInterval;
Persistent = true;
};
timerConfig = {
OnBootSec = cfg.fullRepairInterval;
OnUnitActiveSec = cfg.fullRepairInterval;
Persistent = true;
};
};
systemd.services.cassandra-incremental-repair =
{ description = "Perform an incremental repair on this cassandra node.";
after = [ "cassandra.service" ];
requires = [ "cassandra.service" ];
serviceConfig =
{ User = cfg.user;
Group = cfg.group;
ExecStart =
lib.concatStringsSep " "
([ "${cfg.package}/bin/nodetool" "repair"
] ++ cfg.incrementalRepairOptions);
};
systemd.services.cassandra-incremental-repair = {
description = "Perform an incremental repair on this cassandra node.";
after = [ "cassandra.service" ];
requires = [ "cassandra.service" ];
serviceConfig = {
User = cfg.user;
Group = cfg.group;
ExecStart =
concatStringsSep " "
([
"${cfg.package}/bin/nodetool"
"repair"
] ++ cfg.incrementalRepairOptions);
};
};
systemd.timers.cassandra-incremental-repair =
mkIf (cfg.incrementalRepairInterval != null) {
description = "Schedule incremental repairs on Cassandra";
wantedBy = [ "timers.target" ];
timerConfig =
{ OnBootSec = cfg.incrementalRepairInterval;
OnUnitActiveSec = cfg.incrementalRepairInterval;
Persistent = true;
};
timerConfig = {
OnBootSec = cfg.incrementalRepairInterval;
OnUnitActiveSec = cfg.incrementalRepairInterval;
Persistent = true;
};
};
};
meta.maintainers = with lib.maintainers; [ roberth ];
}

View file

@ -50,6 +50,7 @@ in
environment.etc."reader.conf".source = cfgFile;
environment.systemPackages = [ pkgs.pcsclite ];
systemd.packages = [ (getBin pkgs.pcsclite) ];
systemd.sockets.pcscd.wantedBy = [ "sockets.target" ];

View file

@ -134,7 +134,7 @@ in {
ReadWritePaths = [ cfg.keyPath ];
AmbientCapabilities = [];
CapabilityBoundingSet = [];
CapabilityBoundingSet = "";
DevicePolicy = "closed";
LockPersonality = true;
MemoryDenyWriteExecute = true;

View file

@ -773,7 +773,7 @@ in
};
services.postfix.config = (mapAttrs (_: v: mkDefault v) {
compatibility_level = "9999";
compatibility_level = pkgs.postfix.version;
mail_owner = cfg.user;
default_privs = "nobody";

View file

@ -410,7 +410,7 @@ in
StateDirectoryMode = "0700";
AmbientCapabilities = [];
CapabilityBoundingSet = [];
CapabilityBoundingSet = "";
DevicePolicy = "closed";
LockPersonality = true;
NoNewPrivileges = true;

View file

@ -118,7 +118,7 @@ in {
'';
serviceConfig = {
ExecStart = ''
${pkgs.jre}/bin/java -Xmx${toString cfg.maxMemory}m \
${pkgs.jre8}/bin/java -Xmx${toString cfg.maxMemory}m \
-Dairsonic.home=${cfg.home} \
-Dserver.address=${cfg.listenAddress} \
-Dserver.port=${toString cfg.port} \

View file

@ -477,47 +477,49 @@ in
in ''
# copy custom configuration and generate a random secret key if needed
${optionalString (cfg.useWizard == false) ''
cp -f ${configFile} ${runConfig}
function gitea_setup {
cp -f ${configFile} ${runConfig}
if [ ! -e ${secretKey} ]; then
${gitea}/bin/gitea generate secret SECRET_KEY > ${secretKey}
fi
if [ ! -e ${secretKey} ]; then
${gitea}/bin/gitea generate secret SECRET_KEY > ${secretKey}
fi
# Migrate LFS_JWT_SECRET filename
if [[ -e ${oldLfsJwtSecret} && ! -e ${lfsJwtSecret} ]]; then
mv ${oldLfsJwtSecret} ${lfsJwtSecret}
fi
# Migrate LFS_JWT_SECRET filename
if [[ -e ${oldLfsJwtSecret} && ! -e ${lfsJwtSecret} ]]; then
mv ${oldLfsJwtSecret} ${lfsJwtSecret}
fi
if [ ! -e ${oauth2JwtSecret} ]; then
${gitea}/bin/gitea generate secret JWT_SECRET > ${oauth2JwtSecret}
fi
if [ ! -e ${oauth2JwtSecret} ]; then
${gitea}/bin/gitea generate secret JWT_SECRET > ${oauth2JwtSecret}
fi
if [ ! -e ${lfsJwtSecret} ]; then
${gitea}/bin/gitea generate secret LFS_JWT_SECRET > ${lfsJwtSecret}
fi
if [ ! -e ${lfsJwtSecret} ]; then
${gitea}/bin/gitea generate secret LFS_JWT_SECRET > ${lfsJwtSecret}
fi
if [ ! -e ${internalToken} ]; then
${gitea}/bin/gitea generate secret INTERNAL_TOKEN > ${internalToken}
fi
if [ ! -e ${internalToken} ]; then
${gitea}/bin/gitea generate secret INTERNAL_TOKEN > ${internalToken}
fi
SECRETKEY="$(head -n1 ${secretKey})"
DBPASS="$(head -n1 ${cfg.database.passwordFile})"
OAUTH2JWTSECRET="$(head -n1 ${oauth2JwtSecret})"
LFSJWTSECRET="$(head -n1 ${lfsJwtSecret})"
INTERNALTOKEN="$(head -n1 ${internalToken})"
${if (cfg.mailerPasswordFile == null) then ''
MAILERPASSWORD="#mailerpass#"
'' else ''
MAILERPASSWORD="$(head -n1 ${cfg.mailerPasswordFile} || :)"
''}
sed -e "s,#secretkey#,$SECRETKEY,g" \
-e "s,#dbpass#,$DBPASS,g" \
-e "s,#oauth2jwtsecret#,$OAUTH2JWTSECRET,g" \
-e "s,#lfsjwtsecret#,$LFSJWTSECRET,g" \
-e "s,#internaltoken#,$INTERNALTOKEN,g" \
-e "s,#mailerpass#,$MAILERPASSWORD,g" \
-i ${runConfig}
chmod 640 ${runConfig} ${secretKey} ${oauth2JwtSecret} ${lfsJwtSecret} ${internalToken}
SECRETKEY="$(head -n1 ${secretKey})"
DBPASS="$(head -n1 ${cfg.database.passwordFile})"
OAUTH2JWTSECRET="$(head -n1 ${oauth2JwtSecret})"
LFSJWTSECRET="$(head -n1 ${lfsJwtSecret})"
INTERNALTOKEN="$(head -n1 ${internalToken})"
${if (cfg.mailerPasswordFile == null) then ''
MAILERPASSWORD="#mailerpass#"
'' else ''
MAILERPASSWORD="$(head -n1 ${cfg.mailerPasswordFile} || :)"
''}
sed -e "s,#secretkey#,$SECRETKEY,g" \
-e "s,#dbpass#,$DBPASS,g" \
-e "s,#oauth2jwtsecret#,$OAUTH2JWTSECRET,g" \
-e "s,#lfsjwtsecret#,$LFSJWTSECRET,g" \
-e "s,#internaltoken#,$INTERNALTOKEN,g" \
-e "s,#mailerpass#,$MAILERPASSWORD,g" \
-i ${runConfig}
}
(umask 027; gitea_setup)
''}
# update all hooks' binary paths

View file

@ -245,22 +245,85 @@ in {
rm -f "${cfg.configDir}/ui-lovelace.yaml"
ln -s ${lovelaceConfigFile} "${cfg.configDir}/ui-lovelace.yaml"
'');
serviceConfig = {
ExecStart = "${package}/bin/hass --config '${cfg.configDir}'";
serviceConfig = let
# List of capabilities to equip home-assistant with, depending on configured components
capabilities = [
# Empty string first, so we will never accidentally have an empty capability bounding set
# https://github.com/NixOS/nixpkgs/issues/120617#issuecomment-830685115
""
] ++ (unique (optionals (useComponent "bluetooth_tracker" || useComponent "bluetooth_le_tracker") [
# Required for interaction with hci devices and bluetooth sockets
# https://www.home-assistant.io/integrations/bluetooth_le_tracker/#rootless-setup-on-core-installs
"CAP_NET_ADMIN"
"CAP_NET_RAW"
] ++ lib.optionals (useComponent "emulated_hue") [
# Alexa looks for the service on port 80
# https://www.home-assistant.io/integrations/emulated_hue
"CAP_NET_BIND_SERVICE"
] ++ lib.optionals (useComponent "nmap_tracker") [
# https://www.home-assistant.io/integrations/nmap_tracker#linux-capabilities
"CAP_NET_ADMIN"
"CAP_NET_BIND_SERVICE"
"CAP_NET_RAW"
]));
in {
ExecStart = "${package}/bin/hass --runner --config '${cfg.configDir}'";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
User = "hass";
Group = "hass";
Restart = "on-failure";
RestartForceExitStatus = "100";
SuccessExitStatus = "100";
KillSignal = "SIGINT";
# Hardening
AmbientCapabilities = capabilities;
CapabilityBoundingSet = capabilities;
DeviceAllow = [
"char-ttyACM rw"
"char-ttyAMA rw"
"char-ttyUSB rw"
];
DevicePolicy = "closed";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateTmp = true;
PrivateUsers = false; # prevents gaining capabilities in the host namespace
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProcSubset = "pid";
ProtectSystem = "strict";
RemoveIPC = true;
ReadWritePaths = let
# Allow rw access to explicitly configured paths
cfgPath = [ "config" "homeassistant" "allowlist_external_dirs" ];
value = attrByPath cfgPath [] cfg;
allowPaths = if isList value then value else singleton value;
in [ "${cfg.configDir}" ] ++ allowPaths;
KillSignal = "SIGINT";
PrivateTmp = true;
RemoveIPC = true;
AmbientCapabilities = "cap_net_raw,cap_net_admin+eip";
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
] ++ optionals (useComponent "bluetooth_tracker" || useComponent "bluetooth_le_tracker") [
"AF_BLUETOOTH"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SupplementaryGroups = [ "dialout" ];
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
];
UMask = "0077";
};
path = [
"/run/wrappers" # needed for ping
@ -278,7 +341,6 @@ in {
home = cfg.configDir;
createHome = true;
group = "hass";
extraGroups = [ "dialout" ];
uid = config.ids.uids.hass;
};

View file

@ -0,0 +1,181 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.matrix-dendrite;
settingsFormat = pkgs.formats.yaml { };
configurationYaml = settingsFormat.generate "dendrite.yaml" cfg.settings;
workingDir = "/var/lib/matrix-dendrite";
in
{
options.services.matrix-dendrite = {
enable = lib.mkEnableOption "matrix.org dendrite";
httpPort = lib.mkOption {
type = lib.types.nullOr lib.types.port;
default = 8008;
description = ''
The port to listen for HTTP requests on.
'';
};
httpsPort = lib.mkOption {
type = lib.types.nullOr lib.types.port;
default = null;
description = ''
The port to listen for HTTPS requests on.
'';
};
tlsCert = lib.mkOption {
type = lib.types.nullOr lib.types.path;
example = "/var/lib/matrix-dendrite/server.cert";
default = null;
description = ''
The path to the TLS certificate.
<programlisting>
nix-shell -p matrix-dendrite --command "generate-keys --tls-cert server.crt --tls-key server.key"
</programlisting>
'';
};
tlsKey = lib.mkOption {
type = lib.types.nullOr lib.types.path;
example = "/var/lib/matrix-dendrite/server.key";
default = null;
description = ''
The path to the TLS key.
<programlisting>
nix-shell -p matrix-dendrite --command "generate-keys --tls-cert server.crt --tls-key server.key"
</programlisting>
'';
};
environmentFile = lib.mkOption {
type = lib.types.nullOr lib.types.path;
example = "/var/lib/matrix-dendrite/registration_secret";
default = null;
description = ''
Environment file as defined in <citerefentry>
<refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum>
</citerefentry>.
Secrets may be passed to the service without adding them to the world-readable
Nix store, by specifying placeholder variables as the option value in Nix and
setting these variables accordingly in the environment file. Currently only used
for the registration secret to allow secure registration when
client_api.registration_disabled is true.
<programlisting>
# snippet of dendrite-related config
services.matrix-dendrite.settings.client_api.registration_shared_secret = "$REGISTRATION_SHARED_SECRET";
</programlisting>
<programlisting>
# content of the environment file
REGISTRATION_SHARED_SECRET=verysecretpassword
</programlisting>
Note that this file needs to be available on the host on which
<literal>dendrite</literal> is running.
'';
};
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = settingsFormat.type;
options.global = {
server_name = lib.mkOption {
type = lib.types.str;
example = "example.com";
description = ''
The domain name of the server, with optional explicit port.
This is used by remote servers to connect to this server.
This is also the last part of your UserID.
'';
};
private_key = lib.mkOption {
type = lib.types.path;
example = "${workingDir}/matrix_key.pem";
description = ''
The path to the signing private key file, used to sign
requests and events.
<programlisting>
nix-shell -p matrix-dendrite --command "generate-keys --private-key matrix_key.pem"
</programlisting>
'';
};
trusted_third_party_id_servers = lib.mkOption {
type = lib.types.listOf lib.types.str;
example = [ "matrix.org" ];
default = [ "matrix.org" "vector.im" ];
description = ''
Lists of domains that the server will trust as identity
servers to verify third party identifiers such as phone
numbers and email addresses
'';
};
};
options.client_api = {
registration_disabled = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Whether to disable user registration to the server
without the shared secret.
'';
};
};
};
default = { };
description = ''
Configuration for dendrite, see:
<link xlink:href="https://github.com/matrix-org/dendrite/blob/master/dendrite-config.yaml"/>
for available options with which to populate settings.
'';
};
};
config = lib.mkIf cfg.enable {
assertions = [{
assertion = cfg.httpsPort != null -> (cfg.tlsCert != null && cfg.tlsKey != null);
message = ''
If Dendrite is configured to use https, tlsCert and tlsKey must be provided.
nix-shell -p matrix-dendrite --command "generate-keys --tls-cert server.crt --tls-key server.key"
'';
}];
systemd.services.matrix-dendrite = {
description = "Dendrite Matrix homeserver";
after = [
"network.target"
];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
DynamicUser = true;
StateDirectory = "matrix-dendrite";
WorkingDirectory = workingDir;
RuntimeDirectory = "matrix-dendrite";
RuntimeDirectoryMode = "0700";
EnvironmentFile = lib.mkIf (cfg.environmentFile != null) cfg.environmentFile;
ExecStartPre =
if (cfg.environmentFile != null) then ''
${pkgs.envsubst}/bin/envsubst \
-i ${configurationYaml} \
-o /run/matrix-dendrite/dendrite.yaml
'' else ''
${pkgs.coreutils}/bin/cp ${configurationYaml} /run/matrix-dendrite/dendrite.yaml
'';
ExecStart = lib.strings.concatStringsSep " " ([
"${pkgs.matrix-dendrite}/bin/dendrite-monolith-server"
"--config /run/matrix-dendrite/dendrite.yaml"
] ++ lib.optionals (cfg.httpPort != null) [
"--http-bind-address :${builtins.toString cfg.httpPort}"
] ++ lib.optionals (cfg.httpsPort != null) [
"--https-bind-address :${builtins.toString cfg.httpsPort}"
"--tls-cert ${cfg.tlsCert}"
"--tls-key ${cfg.tlsKey}"
]);
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
Restart = "on-failure";
};
};
};
meta.maintainers = lib.teams.matrix.members;
}

View file

@ -24,55 +24,80 @@ in
Your <filename>pinnwand.toml</filename> as a Nix attribute set. Look up
possible options in the <link xlink:href="https://github.com/supakeen/pinnwand/blob/master/pinnwand.toml-example">pinnwand.toml-example</link>.
'';
default = {
# https://github.com/supakeen/pinnwand/blob/master/pinnwand.toml-example
database_uri = "sqlite:///var/lib/pinnwand/pinnwand.db";
preferred_lexeres = [];
paste_size = 262144;
paste_help = ''
<p>Welcome to pinnwand, this site is a pastebin. It allows you to share code with others. If you write code in the text area below and press the paste button you will be given a link you can share with others so they can view your code as well.</p><p>People with the link can view your pasted code, only you can remove your paste and it expires automatically. Note that anyone could guess the URI to your paste so don't rely on it being private.</p>
'';
footer = ''
View <a href="//github.com/supakeen/pinnwand" target="_BLANK">source code</a>, the <a href="/removal">removal</a> or <a href="/expiry">expiry</a> stories, or read the <a href="/about">about</a> page.
'';
};
default = {};
};
};
config = mkIf cfg.enable {
systemd.services.pinnwand = {
description = "Pinnwannd HTTP Server";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
services.pinnwand.settings = {
database_uri = mkDefault "sqlite:////var/lib/pinnwand/pinnwand.db";
paste_size = mkDefault 262144;
paste_help = mkDefault ''
<p>Welcome to pinnwand, this site is a pastebin. It allows you to share code with others. If you write code in the text area below and press the paste button you will be given a link you can share with others so they can view your code as well.</p><p>People with the link can view your pasted code, only you can remove your paste and it expires automatically. Note that anyone could guess the URI to your paste so don't rely on it being private.</p>
'';
footer = mkDefault ''
View <a href="//github.com/supakeen/pinnwand" target="_BLANK">source code</a>, the <a href="/removal">removal</a> or <a href="/expiry">expiry</a> stories, or read the <a href="/about">about</a> page.
'';
};
systemd.services = let
hardeningOptions = {
User = "pinnwand";
DynamicUser = true;
unitConfig.Documentation = "https://pinnwand.readthedocs.io/en/latest/";
serviceConfig = {
ExecStart = "${pkgs.pinnwand}/bin/pinnwand --configuration-path ${configFile} http --port ${toString(cfg.port)}";
StateDirectory = "pinnwand";
StateDirectoryMode = "0700";
AmbientCapabilities = [];
CapabilityBoundingSet = "";
DevicePolicy = "closed";
DynamicUser = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
PrivateDevices = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectKernelLogs = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
ProtectProc = "invisible";
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
SystemCallArchitectures = "native";
SystemCallFilter = "@system-service";
UMask = "0077";
};
command = "${pkgs.pinnwand}/bin/pinnwand --configuration-path ${configFile}";
in {
pinnwand = {
description = "Pinnwannd HTTP Server";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
unitConfig.Documentation = "https://pinnwand.readthedocs.io/en/latest/";
serviceConfig = {
ExecStart = "${command} http --port ${toString(cfg.port)}";
} // hardeningOptions;
};
pinnwand-reaper = {
description = "Pinnwand Reaper";
startAt = "daily";
serviceConfig = {
ExecStart = "${command} -vvvv reap"; # verbosity increased to show number of deleted pastes
} // hardeningOptions;
};
};
};
}

View file

@ -5,29 +5,17 @@ with lib;
let
cfg = config.services.zigbee2mqtt;
configJSON = pkgs.writeText "configuration.json"
(builtins.toJSON (recursiveUpdate defaultConfig cfg.config));
configFile = pkgs.runCommand "configuration.yaml" { preferLocalBuild = true; } ''
${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out
'';
format = pkgs.formats.yaml { };
configFile = format.generate "zigbee2mqtt.yaml" cfg.settings;
# the default config contains all required settings,
# so the service starts up without crashing.
defaultConfig = {
homeassistant = false;
permit_join = false;
mqtt = {
base_topic = "zigbee2mqtt";
server = "mqtt://localhost:1883";
};
serial.port = "/dev/ttyACM0";
# put device configuration into separate file because configuration.yaml
# is copied from the store on startup
devices = "devices.yaml";
};
in
{
meta.maintainers = with maintainers; [ sweber ];
meta.maintainers = with maintainers; [ sweber hexa ];
imports = [
# Remove warning before the 21.11 release
(mkRenamedOptionModule [ "services" "zigbee2mqtt" "config" ] [ "services" "zigbee2mqtt" "settings" ])
];
options.services.zigbee2mqtt = {
enable = mkEnableOption "enable zigbee2mqtt service";
@ -37,7 +25,11 @@ in
default = pkgs.zigbee2mqtt.override {
dataDir = cfg.dataDir;
};
defaultText = "pkgs.zigbee2mqtt";
defaultText = literalExample ''
pkgs.zigbee2mqtt {
dataDir = services.zigbee2mqtt.dataDir
}
'';
type = types.package;
};
@ -47,9 +39,9 @@ in
type = types.path;
};
config = mkOption {
settings = mkOption {
type = format.type;
default = {};
type = with types; nullOr attrs;
example = literalExample ''
{
homeassistant = config.services.home-assistant.enable;
@ -61,11 +53,28 @@ in
'';
description = ''
Your <filename>configuration.yaml</filename> as a Nix attribute set.
Check the <link xlink:href="https://www.zigbee2mqtt.io/information/configuration.html">documentation</link>
for possible options.
'';
};
};
config = mkIf (cfg.enable) {
# preset config values
services.zigbee2mqtt.settings = {
homeassistant = mkDefault config.services.home-assistant.enable;
permit_join = mkDefault false;
mqtt = {
base_topic = mkDefault "zigbee2mqtt";
server = mkDefault "mqtt://localhost:1883";
};
serial.port = mkDefault "/dev/ttyACM0";
# reference device configuration, that is kept in a separate file
# to prevent it being overwritten in the units ExecStartPre script
devices = mkDefault "devices.yaml";
};
systemd.services.zigbee2mqtt = {
description = "Zigbee2mqtt Service";
wantedBy = [ "multi-user.target" ];
@ -76,10 +85,48 @@ in
User = "zigbee2mqtt";
WorkingDirectory = cfg.dataDir;
Restart = "on-failure";
# Hardening
CapabilityBoundingSet = "";
DeviceAllow = [
config.services.zigbee2mqtt.settings.serial.port
];
DevicePolicy = "closed";
LockPersonality = true;
MemoryDenyWriteExecute = false;
NoNewPrivileges = true;
PrivateDevices = false; # prevents access to /dev/serial, because it is set 0700 root:root
PrivateUsers = true;
PrivateTmp = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProcSubset = "pid";
ProtectSystem = "strict";
ReadWritePaths = cfg.dataDir;
PrivateTmp = true;
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SupplementaryGroups = [
"dialout"
];
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0077";
};
preStart = ''
cp --no-preserve=mode ${configFile} "${cfg.dataDir}/configuration.yaml"
@ -90,7 +137,6 @@ in
home = cfg.dataDir;
createHome = true;
group = "zigbee2mqtt";
extraGroups = [ "dialout" ];
uid = config.ids.uids.zigbee2mqtt;
};

View file

@ -32,6 +32,8 @@ in
{
meta.maintainers = with maintainers; [ hexa ];
###### interface
options = {

View file

@ -8,32 +8,37 @@ let
bindUser = "named";
bindZoneOptions = {
name = mkOption {
type = types.str;
description = "Name of the zone.";
};
master = mkOption {
description = "Master=false means slave server";
type = types.bool;
};
file = mkOption {
type = types.either types.str types.path;
description = "Zone file resource records contain columns of data, separated by whitespace, that define the record.";
};
masters = mkOption {
type = types.listOf types.str;
description = "List of servers for inclusion in stub and secondary zones.";
};
slaves = mkOption {
type = types.listOf types.str;
description = "Addresses who may request zone transfers.";
default = [];
};
extraConfig = mkOption {
type = types.str;
description = "Extra zone config to be appended at the end of the zone section.";
default = "";
bindZoneCoerce = list: builtins.listToAttrs (lib.forEach list (zone: { name = zone.name; value = zone; }));
bindZoneOptions = { name, config, ... }: {
options = {
name = mkOption {
type = types.str;
default = name;
description = "Name of the zone.";
};
master = mkOption {
description = "Master=false means slave server";
type = types.bool;
};
file = mkOption {
type = types.either types.str types.path;
description = "Zone file resource records contain columns of data, separated by whitespace, that define the record.";
};
masters = mkOption {
type = types.listOf types.str;
description = "List of servers for inclusion in stub and secondary zones.";
};
slaves = mkOption {
type = types.listOf types.str;
description = "Addresses who may request zone transfers.";
default = [];
};
extraConfig = mkOption {
type = types.str;
description = "Extra zone config to be appended at the end of the zone section.";
default = "";
};
};
};
@ -84,7 +89,7 @@ let
${extraConfig}
};
'')
cfg.zones }
(attrValues cfg.zones) }
'';
in
@ -153,18 +158,19 @@ in
zones = mkOption {
default = [];
type = types.listOf (types.submodule [ { options = bindZoneOptions; } ]);
type = with types; coercedTo (listOf attrs) bindZoneCoerce (attrsOf (types.submodule bindZoneOptions));
description = "
List of zones we claim authority over.
";
example = [{
name = "example.com";
master = false;
file = "/var/dns/example.com";
masters = ["192.168.0.1"];
slaves = [];
extraConfig = "";
}];
example = {
"example.com" = {
master = false;
file = "/var/dns/example.com";
masters = ["192.168.0.1"];
slaves = [];
extraConfig = "";
};
};
};
extraConfig = mkOption {

View file

@ -20,8 +20,7 @@ let
acl_file ${aclFile}
persistence true
allow_anonymous ${boolToString cfg.allowAnonymous}
bind_address ${cfg.host}
port ${toString cfg.port}
listener ${toString cfg.port} ${cfg.host}
${passwordConf}
${listenerConf}
${cfg.extraConf}
@ -233,15 +232,50 @@ in
ExecStart = "${pkgs.mosquitto}/bin/mosquitto -c ${mosquittoConf}";
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
ProtectSystem = "strict";
ProtectHome = true;
# Hardening
CapabilityBoundingSet = "";
DevicePolicy = "closed";
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
ReadWritePaths = "${cfg.dataDir}";
PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
NoNewPrivileges = true;
ProtectProc = "invisible";
ProcSubset = "pid";
ProtectSystem = "strict";
ReadWritePaths = [
cfg.dataDir
"/tmp" # mosquitto_passwd creates files in /tmp before moving them
];
ReadOnlyPaths = with cfg.ssl; lib.optionals (enable) [
certfile
keyfile
cafile
];
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_UNIX" # for sd_notify() call
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0077";
};
preStart = ''
rm -f ${cfg.dataDir}/passwd

View file

@ -4,51 +4,28 @@ with lib;
let
cfg = config.services.unbound;
stateDir = "/var/lib/unbound";
yesOrNo = v: if v then "yes" else "no";
access = concatMapStringsSep "\n " (x: "access-control: ${x} allow") cfg.allowedAccess;
toOption = indent: n: v: "${indent}${toString n}: ${v}";
interfaces = concatMapStringsSep "\n " (x: "interface: ${x}") cfg.interfaces;
toConf = indent: n: v:
if builtins.isFloat v then (toOption indent n (builtins.toJSON v))
else if isInt v then (toOption indent n (toString v))
else if isBool v then (toOption indent n (yesOrNo v))
else if isString v then (toOption indent n v)
else if isList v then (concatMapStringsSep "\n" (toConf indent n) v)
else if isAttrs v then (concatStringsSep "\n" (
["${indent}${n}:"] ++ (
mapAttrsToList (toConf "${indent} ") v
)
))
else throw (traceSeq v "services.unbound.settings: unexpected type");
isLocalAddress = x: substring 0 3 x == "::1" || substring 0 9 x == "127.0.0.1";
confFile = pkgs.writeText "unbound.conf" (concatStringsSep "\n" ((mapAttrsToList (toConf "") cfg.settings) ++ [""]));
forward =
optionalString (any isLocalAddress cfg.forwardAddresses) ''
do-not-query-localhost: no
''
+ optionalString (cfg.forwardAddresses != []) ''
forward-zone:
name: .
''
+ concatMapStringsSep "\n" (x: " forward-addr: ${x}") cfg.forwardAddresses;
rootTrustAnchorFile = "${cfg.stateDir}/root.key";
rootTrustAnchorFile = "${stateDir}/root.key";
trustAnchor = optionalString cfg.enableRootTrustAnchor
"auto-trust-anchor-file: ${rootTrustAnchorFile}";
confFile = pkgs.writeText "unbound.conf" ''
server:
ip-freebind: yes
directory: "${stateDir}"
username: unbound
chroot: ""
pidfile: ""
# when running under systemd there is no need to daemonize
do-daemonize: no
${interfaces}
${access}
${trustAnchor}
${lib.optionalString (cfg.localControlSocketPath != null) ''
remote-control:
control-enable: yes
control-interface: ${cfg.localControlSocketPath}
''}
${cfg.extraConfig}
${forward}
'';
in
{
in {
###### interface
@ -64,27 +41,32 @@ in
description = "The unbound package to use";
};
allowedAccess = mkOption {
default = [ "127.0.0.0/24" ];
type = types.listOf types.str;
description = "What networks are allowed to use unbound as a resolver.";
user = mkOption {
type = types.str;
default = "unbound";
description = "User account under which unbound runs.";
};
interfaces = mkOption {
default = [ "127.0.0.1" ] ++ optional config.networking.enableIPv6 "::1";
type = types.listOf types.str;
description = ''
What addresses the server should listen on. This supports the interface syntax documented in
<citerefentry><refentrytitle>unbound.conf</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
group = mkOption {
type = types.str;
default = "unbound";
description = "Group under which unbound runs.";
};
stateDir = mkOption {
default = "/var/lib/unbound";
description = "Directory holding all state for unbound to run.";
};
resolveLocalQueries = mkOption {
type = types.bool;
default = true;
description = ''
Whether unbound should resolve local queries (i.e. add 127.0.0.1 to
/etc/resolv.conf).
'';
};
forwardAddresses = mkOption {
default = [];
type = types.listOf types.str;
description = "What servers to forward queries to.";
};
enableRootTrustAnchor = mkOption {
default = true;
type = types.bool;
@ -106,23 +88,66 @@ in
and group will be <literal>nogroup</literal>.
Users that should be permitted to access the socket must be in the
<literal>unbound</literal> group.
<literal>config.services.unbound.group</literal> group.
If this option is <literal>null</literal> remote control will not be
configured at all. Unbounds default values apply.
enabled. Unbounds default values apply.
'';
};
extraConfig = mkOption {
default = "";
type = types.lines;
settings = mkOption {
default = {};
type = with types; submodule {
freeformType = let
validSettingsPrimitiveTypes = oneOf [ int str bool float ];
validSettingsTypes = oneOf [ validSettingsPrimitiveTypes (listOf validSettingsPrimitiveTypes) ];
settingsType = (attrsOf validSettingsTypes);
in attrsOf (oneOf [ string settingsType (listOf settingsType) ])
// { description = ''
unbound.conf configuration type. The format consist of an attribute
set of settings. Each settings can be either one value, a list of
values or an attribute set. The allowed values are integers,
strings, booleans or floats.
'';
};
options = {
remote-control.control-enable = mkOption {
type = bool;
default = false;
internal = true;
};
};
};
example = literalExample ''
{
server = {
interface = [ "127.0.0.1" ];
};
forward-zone = [
{
name = ".";
forward-addr = "1.1.1.1@853#cloudflare-dns.com";
}
{
name = "example.org.";
forward-addr = [
"1.1.1.1@853#cloudflare-dns.com"
"1.0.0.1@853#cloudflare-dns.com"
];
}
];
remote-control.control-enable = true;
};
'';
description = ''
Extra unbound config. See
<citerefentry><refentrytitle>unbound.conf</refentrytitle><manvolnum>8
</manvolnum></citerefentry>.
Declarative Unbound configuration
See the <citerefentry><refentrytitle>unbound.conf</refentrytitle>
<manvolnum>5</manvolnum></citerefentry> manpage for a list of
available options.
'';
};
};
};
@ -130,23 +155,56 @@ in
config = mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
users.users.unbound = {
description = "unbound daemon user";
isSystemUser = true;
group = lib.mkIf (cfg.localControlSocketPath != null) (lib.mkDefault "unbound");
services.unbound.settings = {
server = {
directory = mkDefault cfg.stateDir;
username = cfg.user;
chroot = ''""'';
pidfile = ''""'';
# when running under systemd there is no need to daemonize
do-daemonize = false;
interface = mkDefault ([ "127.0.0.1" ] ++ (optional config.networking.enableIPv6 "::1"));
access-control = mkDefault ([ "127.0.0.0/8 allow" ] ++ (optional config.networking.enableIPv6 "::1/128 allow"));
auto-trust-anchor-file = mkIf cfg.enableRootTrustAnchor rootTrustAnchorFile;
tls-cert-bundle = mkDefault "/etc/ssl/certs/ca-certificates.crt";
# prevent race conditions on system startup when interfaces are not yet
# configured
ip-freebind = mkDefault true;
};
remote-control = {
control-enable = mkDefault false;
control-interface = mkDefault ([ "127.0.0.1" ] ++ (optional config.networking.enableIPv6 "::1"));
server-key-file = mkDefault "${cfg.stateDir}/unbound_server.key";
server-cert-file = mkDefault "${cfg.stateDir}/unbound_server.pem";
control-key-file = mkDefault "${cfg.stateDir}/unbound_control.key";
control-cert-file = mkDefault "${cfg.stateDir}/unbound_control.pem";
} // optionalAttrs (cfg.localControlSocketPath != null) {
control-enable = true;
control-interface = cfg.localControlSocketPath;
};
};
# We need a group so that we can give users access to the configured
# control socket. Unbound allows access to the socket only to the unbound
# user and the primary group.
users.groups = lib.mkIf (cfg.localControlSocketPath != null) {
environment.systemPackages = [ cfg.package ];
users.users = mkIf (cfg.user == "unbound") {
unbound = {
description = "unbound daemon user";
isSystemUser = true;
group = cfg.group;
};
};
users.groups = mkIf (cfg.group == "unbound") {
unbound = {};
};
networking.resolvconf.useLocalResolver = mkDefault true;
networking = mkIf cfg.resolveLocalQueries {
resolvconf = {
useLocalResolver = mkDefault true;
};
networkmanager.dns = "unbound";
};
environment.etc."unbound/unbound.conf".source = confFile;
@ -156,8 +214,15 @@ in
before = [ "nss-lookup.target" ];
wantedBy = [ "multi-user.target" "nss-lookup.target" ];
preStart = lib.mkIf cfg.enableRootTrustAnchor ''
${cfg.package}/bin/unbound-anchor -a ${rootTrustAnchorFile} || echo "Root anchor updated!"
path = mkIf cfg.settings.remote-control.control-enable [ pkgs.openssl ];
preStart = ''
${optionalString cfg.enableRootTrustAnchor ''
${cfg.package}/bin/unbound-anchor -a ${rootTrustAnchorFile} || echo "Root anchor updated!"
''}
${optionalString cfg.settings.remote-control.control-enable ''
${cfg.package}/bin/unbound-control-setup -d ${cfg.stateDir}
''}
'';
restartTriggers = [
@ -181,8 +246,8 @@ in
"CAP_SYS_RESOURCE"
];
User = "unbound";
Group = lib.mkIf (cfg.localControlSocketPath != null) (lib.mkDefault "unbound");
User = cfg.user;
Group = cfg.group;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
@ -211,9 +276,29 @@ in
RestrictNamespaces = true;
LockPersonality = true;
RestrictSUIDSGID = true;
Restart = "on-failure";
RestartSec = "5s";
};
};
# If networkmanager is enabled, ask it to interface with unbound.
networking.networkmanager.dns = "unbound";
};
imports = [
(mkRenamedOptionModule [ "services" "unbound" "interfaces" ] [ "services" "unbound" "settings" "server" "interface" ])
(mkChangedOptionModule [ "services" "unbound" "allowedAccess" ] [ "services" "unbound" "settings" "server" "access-control" ] (
config: map (value: "${value} allow") (getAttrFromPath [ "services" "unbound" "allowedAccess" ] config)
))
(mkRemovedOptionModule [ "services" "unbound" "forwardAddresses" ] ''
Add a new setting:
services.unbound.settings.forward-zone = [{
name = ".";
forward-addr = [ # Your current services.unbound.forwardAddresses ];
}];
If any of those addresses are local addresses (127.0.0.1 or ::1), you must
also set services.unbound.settings.server.do-not-query-localhost to false.
'')
(mkRemovedOptionModule [ "services" "unbound" "extraConfig" ] ''
You can use services.unbound.settings to add any configuration you want.
'')
];
}

View file

@ -246,12 +246,15 @@ let
};
script = ''
mkdir --mode 0644 -p "${dirOf values.privateKeyFile}"
set -e
# If the parent dir does not already exist, create it.
# Otherwise, does nothing, keeping existing permisions intact.
mkdir -p --mode 0755 "${dirOf values.privateKeyFile}"
if [ ! -f "${values.privateKeyFile}" ]; then
touch "${values.privateKeyFile}"
chmod 0600 "${values.privateKeyFile}"
wg genkey > "${values.privateKeyFile}"
chmod 0400 "${values.privateKeyFile}"
# Write private key file with atomically-correct permissions.
(set -e; umask 077; wg genkey > "${values.privateKeyFile}")
fi
'';
};

View file

@ -62,6 +62,22 @@ in
description = "The firewall package used by fail2ban service.";
};
extraPackages = mkOption {
default = [];
type = types.listOf types.package;
example = lib.literalExample "[ pkgs.ipset ]";
description = ''
Extra packages to be made available to the fail2ban service. The example contains
the packages needed by the `iptables-ipset-proto6` action.
'';
};
maxretry = mkOption {
default = 3;
type = types.ints.unsigned;
description = "Number of failures before a host gets banned.";
};
banaction = mkOption {
default = "iptables-multiport";
type = types.str;
@ -243,7 +259,7 @@ in
restartTriggers = [ fail2banConf jailConf pathsConf ];
reloadIfChanged = true;
path = [ cfg.package cfg.packageFirewall pkgs.iproute2 ];
path = [ cfg.package cfg.packageFirewall pkgs.iproute2 ] ++ cfg.extraPackages;
unitConfig.Documentation = "man:fail2ban(1)";
@ -291,7 +307,7 @@ in
''}
# Miscellaneous options
ignoreip = 127.0.0.1/8 ${optionalString config.networking.enableIPv6 "::1"} ${concatStringsSep " " cfg.ignoreIP}
maxretry = 3
maxretry = ${toString cfg.maxretry}
backend = systemd
# Actions
banaction = ${cfg.banaction}

View file

@ -23,7 +23,8 @@ in
config.services.oauth2_proxy = mkIf (cfg.virtualHosts != [] && (hasPrefix "127.0.0.1:" cfg.proxy)) {
enable = true;
};
config.services.nginx = mkMerge ((optional (cfg.virtualHosts != []) {
config.services.nginx = mkIf config.services.oauth2_proxy.enable (mkMerge
((optional (cfg.virtualHosts != []) {
recommendedProxySettings = true; # needed because duplicate headers
}) ++ (map (vhost: {
virtualHosts.${vhost} = {
@ -60,5 +61,5 @@ in
'';
};
}) cfg.virtualHosts));
}) cfg.virtualHosts)));
}

View file

@ -819,28 +819,38 @@ in
# Logs directory and mode
LogsDirectory = "nginx";
LogsDirectoryMode = "0750";
# Proc filesystem
ProcSubset = "pid";
ProtectProc = "invisible";
# New file permissions
UMask = "0027"; # 0640 / 0750
# Capabilities
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" "CAP_SYS_RESOURCE" ];
# Security
NoNewPrivileges = true;
# Sandboxing
# Sandboxing (sorted by occurrence in https://www.freedesktop.org/software/systemd/man/systemd.exec.html)
ProtectSystem = "strict";
ProtectHome = mkDefault true;
PrivateTmp = true;
PrivateDevices = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
LockPersonality = true;
MemoryDenyWriteExecute = !(builtins.any (mod: (mod.allowMemoryWriteExecute or false)) cfg.package.modules);
RestrictRealtime = true;
RestrictSUIDSGID = true;
RemoveIPC = true;
PrivateMounts = true;
# System Call Filtering
SystemCallArchitectures = "native";
SystemCallFilter = "~@chown @cpu-emulation @debug @keyring @ipc @module @mount @obsolete @privileged @raw-io @reboot @setuid @swap";
};
};

View file

@ -0,0 +1,318 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.trafficserver;
user = config.users.users.trafficserver.name;
group = config.users.groups.trafficserver.name;
getManualUrl = name: "https://docs.trafficserver.apache.org/en/latest/admin-guide/files/${name}.en.html";
getConfPath = name: "${pkgs.trafficserver}/etc/trafficserver/${name}";
yaml = pkgs.formats.yaml { };
fromYAML = f:
let
jsonFile = pkgs.runCommand "in.json"
{
nativeBuildInputs = [ pkgs.remarshal ];
} ''
yaml2json < "${f}" > "$out"
'';
in
builtins.fromJSON (builtins.readFile jsonFile);
mkYamlConf = name: cfg:
if cfg != null then {
"trafficserver/${name}.yaml".source = yaml.generate "${name}.yaml" cfg;
} else {
"trafficserver/${name}.yaml".text = "";
};
mkRecordLines = path: value:
if isAttrs value then
lib.mapAttrsToList (n: v: mkRecordLines (path ++ [ n ]) v) value
else if isInt value then
"CONFIG ${concatStringsSep "." path} INT ${toString value}"
else if isFloat value then
"CONFIG ${concatStringsSep "." path} FLOAT ${toString value}"
else
"CONFIG ${concatStringsSep "." path} STRING ${toString value}";
mkRecordsConfig = cfg: concatStringsSep "\n" (flatten (mkRecordLines [ ] cfg));
mkPluginConfig = cfg: concatStringsSep "\n" (map (p: "${p.path} ${p.arg}") cfg);
in
{
options.services.trafficserver = {
enable = mkEnableOption "Apache Traffic Server";
cache = mkOption {
type = types.lines;
default = "";
example = "dest_domain=example.com suffix=js action=never-cache";
description = ''
Caching rules that overrule the origin's caching policy.
Consult the <link xlink:href="${getManualUrl "cache.config"}">upstream
documentation</link> for more details.
'';
};
hosting = mkOption {
type = types.lines;
default = "";
example = "domain=example.com volume=1";
description = ''
Partition the cache according to origin server or domain
Consult the <link xlink:href="${getManualUrl "hosting.config"}">
upstream documentation</link> for more details.
'';
};
ipAllow = mkOption {
type = types.nullOr yaml.type;
default = fromYAML (getConfPath "ip_allow.yaml");
defaultText = "upstream defaults";
example = literalExample {
ip_allow = [{
apply = "in";
ip_addrs = "127.0.0.1";
action = "allow";
methods = "ALL";
}];
};
description = ''
Control client access to Traffic Server and Traffic Server connections
to upstream servers.
Consult the <link xlink:href="${getManualUrl "ip_allow.yaml"}">upstream
documentation</link> for more details.
'';
};
logging = mkOption {
type = types.nullOr yaml.type;
default = fromYAML (getConfPath "logging.yaml");
defaultText = "upstream defaults";
example = literalExample { };
description = ''
Configure logs.
Consult the <link xlink:href="${getManualUrl "logging.yaml"}">upstream
documentation</link> for more details.
'';
};
parent = mkOption {
type = types.lines;
default = "";
example = ''
dest_domain=. method=get parent="p1.example:8080; p2.example:8080" round_robin=true
'';
description = ''
Identify the parent proxies used in an cache hierarchy.
Consult the <link xlink:href="${getManualUrl "parent.config"}">upstream
documentation</link> for more details.
'';
};
plugins = mkOption {
default = [ ];
description = ''
Controls run-time loadable plugins available to Traffic Server, as
well as their configuration.
Consult the <link xlink:href="${getManualUrl "plugin.config"}">upstream
documentation</link> for more details.
'';
type = with types;
listOf (submodule {
options.path = mkOption {
type = str;
example = "xdebug.so";
description = ''
Path to plugin. The path can either be absolute, or relative to
the plugin directory.
'';
};
options.arg = mkOption {
type = str;
default = "";
example = "--header=ATS-My-Debug";
description = "arguments to pass to the plugin";
};
});
};
records = mkOption {
type = with types;
let valueType = (attrsOf (oneOf [ int float str valueType ])) // {
description = "Traffic Server records value";
};
in
valueType;
default = { };
example = literalExample { proxy.config.proxy_name = "my_server"; };
description = ''
List of configurable variables used by Traffic Server.
Consult the <link xlink:href="${getManualUrl "records.config"}">
upstream documentation</link> for more details.
'';
};
remap = mkOption {
type = types.lines;
default = "";
example = "map http://from.example http://origin.example";
description = ''
URL remapping rules used by Traffic Server.
Consult the <link xlink:href="${getManualUrl "remap.config"}">
upstream documentation</link> for more details.
'';
};
splitDns = mkOption {
type = types.lines;
default = "";
example = ''
dest_domain=internal.corp.example named="255.255.255.255:212 255.255.255.254" def_domain=corp.example search_list="corp.example corp1.example"
dest_domain=!internal.corp.example named=255.255.255.253
'';
description = ''
Specify the DNS server that Traffic Server should use under specific
conditions.
Consult the <link xlink:href="${getManualUrl "splitdns.config"}">
upstream documentation</link> for more details.
'';
};
sslMulticert = mkOption {
type = types.lines;
default = "";
example = "dest_ip=* ssl_cert_name=default.pem";
description = ''
Configure SSL server certificates to terminate the SSL sessions.
Consult the <link xlink:href="${getManualUrl "ssl_multicert.config"}">
upstream documentation</link> for more details.
'';
};
sni = mkOption {
type = types.nullOr yaml.type;
default = null;
example = literalExample {
sni = [{
fqdn = "no-http2.example.com";
https = "off";
}];
};
description = ''
Configure aspects of TLS connection handling for both inbound and
outbound connections.
Consult the <link xlink:href="${getManualUrl "sni.yaml"}">upstream
documentation</link> for more details.
'';
};
storage = mkOption {
type = types.lines;
default = "/var/cache/trafficserver 256M";
example = "/dev/disk/by-id/XXXXX volume=1";
description = ''
List all the storage that make up the Traffic Server cache.
Consult the <link xlink:href="${getManualUrl "storage.config"}">
upstream documentation</link> for more details.
'';
};
strategies = mkOption {
type = types.nullOr yaml.type;
default = null;
description = ''
Specify the next hop proxies used in an cache hierarchy and the
algorithms used to select the next proxy.
Consult the <link xlink:href="${getManualUrl "strategies.yaml"}">
upstream documentation</link> for more details.
'';
};
volume = mkOption {
type = types.nullOr yaml.type;
default = "";
example = "volume=1 scheme=http size=20%";
description = ''
Manage cache space more efficiently and restrict disk usage by
creating cache volumes of different sizes.
Consult the <link xlink:href="${getManualUrl "volume.config"}">
upstream documentation</link> for more details.
'';
};
};
config = mkIf cfg.enable {
environment.etc = {
"trafficserver/cache.config".text = cfg.cache;
"trafficserver/hosting.config".text = cfg.hosting;
"trafficserver/parent.config".text = cfg.parent;
"trafficserver/plugin.config".text = mkPluginConfig cfg.plugins;
"trafficserver/records.config".text = mkRecordsConfig cfg.records;
"trafficserver/remap.config".text = cfg.remap;
"trafficserver/splitdns.config".text = cfg.splitDns;
"trafficserver/ssl_multicert.config".text = cfg.sslMulticert;
"trafficserver/storage.config".text = cfg.storage;
"trafficserver/volume.config".text = cfg.volume;
} // (mkYamlConf "ip_allow" cfg.ipAllow)
// (mkYamlConf "logging" cfg.logging)
// (mkYamlConf "sni" cfg.sni)
// (mkYamlConf "strategies" cfg.strategies);
environment.systemPackages = [ pkgs.trafficserver ];
systemd.packages = [ pkgs.trafficserver ];
# Traffic Server does privilege handling independently of systemd, and
# therefore should be started as root
systemd.services.trafficserver = {
enable = true;
wantedBy = [ "multi-user.target" ];
};
# These directories can't be created by systemd because:
#
# 1. Traffic Servers starts as root and switches to an unprivileged user
# afterwards. The runtime directories defined below are assumed to be
# owned by that user.
# 2. The bin/trafficserver script assumes these directories exist.
systemd.tmpfiles.rules = [
"d '/run/trafficserver' - ${user} ${group} - -"
"d '/var/cache/trafficserver' - ${user} ${group} - -"
"d '/var/lib/trafficserver' - ${user} ${group} - -"
"d '/var/log/trafficserver' - ${user} ${group} - -"
];
services.trafficserver = {
records.proxy.config.admin.user_id = user;
records.proxy.config.body_factory.template_sets_dir =
"${pkgs.trafficserver}/etc/trafficserver/body_factory";
};
users.users.trafficserver = {
description = "Apache Traffic Server";
isSystemUser = true;
inherit group;
};
users.groups.trafficserver = { };
};
}

View file

@ -151,7 +151,6 @@ in
services.upower.enable = config.powerManagement.enable;
services.gnome3.glib-networking.enable = true;
services.gvfs.enable = true;
services.gvfs.package = pkgs.xfce.gvfs;
services.tumbler.enable = true;
services.system-config-printer.enable = (mkIf config.services.printing.enable (mkDefault true));
services.xserver.libinput.enable = mkDefault true; # used in xfce4-settings-manager

View file

@ -666,6 +666,7 @@ in
# The default max inotify watches is 8192.
# Nowadays most apps require a good number of inotify watches,
# the value below is used by default on several other distros.
boot.kernel.sysctl."fs.inotify.max_user_instances" = mkDefault 524288;
boot.kernel.sysctl."fs.inotify.max_user_watches" = mkDefault 524288;
systemd.defaultUnit = mkIf cfg.autorun "graphical.target";

View file

@ -16,6 +16,16 @@ let
userData=/etc/ec2-metadata/user-data
# Check if user-data looks like a shell script and execute it with the
# runtime shell if it does. Otherwise treat it as a nixos configuration
# expression
if IFS= LC_ALL=C read -rN2 shebang < $userData && [ "$shebang" = '#!' ]; then
# NB: we cannot chmod the $userData file, this is why we execute it via
# `pkgs.runtimeShell`. This means we have only limited support for shell
# scripts compatible with the `pkgs.runtimeShell`.
exec ${pkgs.runtimeShell} $userData
fi
if [ -s "$userData" ]; then
# If the user-data looks like it could be a nix expression,
# copy it over. Also, look for a magic three-hash comment and set

View file

@ -224,6 +224,25 @@ in rec {
);
# Test job for https://github.com/NixOS/nixpkgs/issues/121354 to test
# automatic sizing without blocking the channel.
amazonImageAutomaticSize = forMatchingSystems [ "x86_64-linux" "aarch64-linux" ] (system:
with import ./.. { inherit system; };
hydraJob ((import lib/eval-config.nix {
inherit system;
modules =
[ configuration
versionModule
./maintainers/scripts/ec2/amazon-image.nix
({ ... }: { amazonImage.sizeMB = "auto"; })
];
}).config.system.build.amazonImage)
);
# Ensure that all packages used by the minimal NixOS config end up in the channel.
dummy = forAllSystems (system: pkgs.runCommand "dummy"
{ toplevel = (import lib/eval-config.nix {

32
nixos/tests/airsonic.nix Normal file
View file

@ -0,0 +1,32 @@
import ./make-test-python.nix ({ pkgs, ... }: {
name = "airsonic";
meta = with pkgs.lib.maintainers; {
maintainers = [ sumnerevans ];
};
machine =
{ pkgs, ... }:
{
services.airsonic = {
enable = true;
maxMemory = 800;
};
# Airsonic is a Java application, and unfortunately requires a significant
# amount of memory.
virtualisation.memorySize = 1024;
};
testScript = ''
def airsonic_is_up(_) -> bool:
return machine.succeed("curl --fail http://localhost:4040/login")
machine.start()
machine.wait_for_unit("airsonic.service")
machine.wait_for_open_port(4040)
with machine.nested("Waiting for UI to work"):
retry(airsonic_is_up)
'';
})

View file

@ -24,6 +24,8 @@ in
_3proxy = handleTest ./3proxy.nix {};
acme = handleTest ./acme.nix {};
agda = handleTest ./agda.nix {};
airsonic = handleTest ./airsonic.nix {};
amazon-init-shell = handleTest ./amazon-init-shell.nix {};
ammonite = handleTest ./ammonite.nix {};
atd = handleTest ./atd.nix {};
avahi = handleTest ./avahi.nix {};
@ -413,6 +415,7 @@ in
# traefik test relies on docker-containers
trac = handleTest ./trac.nix {};
traefik = handleTestOn ["x86_64-linux"] ./traefik.nix {};
trafficserver = handleTest ./trafficserver.nix {};
transmission = handleTest ./transmission.nix {};
trezord = handleTest ./trezord.nix {};
trickster = handleTest ./trickster.nix {};

View file

@ -0,0 +1,40 @@
# This test verifies that the amazon-init service can treat the `user-data` ec2
# metadata file as a shell script. If amazon-init detects that `user-data` is a
# script (based on the presence of the shebang #! line) it executes it and
# exits.
# Note that other tests verify that amazon-init can treat user-data as a nixos
# configuration expression.
{ system ? builtins.currentSystem,
config ? {},
pkgs ? import ../.. { inherit system config; }
}:
with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
makeTest {
name = "amazon-init";
meta = with maintainers; {
maintainers = [ urbas ];
};
machine = { ... }:
{
imports = [ ../modules/profiles/headless.nix ../modules/virtualisation/amazon-init.nix ];
services.openssh.enable = true;
networking.hostName = "";
environment.etc."ec2-metadata/user-data" = {
text = ''
#!/usr/bin/bash
echo successful > /tmp/evidence
'';
};
};
testScript = ''
# To wait until amazon-init terminates its run
unnamed.wait_for_unit("amazon-init.service")
unnamed.succeed("grep -q successful /tmp/evidence")
'';
}

View file

@ -18,6 +18,10 @@ import ./make-test-python.nix ({ pkgs, ...} :
};
virtualisation.memorySize = 1024;
# Need to switch to a different VGA card / GPU driver because Cage segfaults with the default one (std):
# machine # [ 14.355893] .cage-wrapped[736]: segfault at 20 ip 00007f035fa0d8c7 sp 00007ffce9e4a2f0 error 4 in libwlroots.so.8[7f035fa07000+5a000]
# machine # [ 14.358108] Code: 4f a8 ff ff eb aa 0f 1f 44 00 00 c3 0f 1f 80 00 00 00 00 41 54 49 89 f4 55 31 ed 53 48 89 fb 48 8d 7f 18 48 8d 83 b8 00 00 00 <80> 7f 08 00 75 0d 48 83 3f 00 0f 85 91 00 00 00 48 89 fd 48 83 c7
virtualisation.qemu.options = [ "-vga virtio" ];
};
enableOCR = true;
@ -25,11 +29,6 @@ import ./make-test-python.nix ({ pkgs, ...} :
testScript = { nodes, ... }: let
user = nodes.machine.config.users.users.alice;
in ''
# Need to switch to a different VGA card / GPU driver because Cage segfaults with the default one (std):
# machine # [ 14.355893] .cage-wrapped[736]: segfault at 20 ip 00007f035fa0d8c7 sp 00007ffce9e4a2f0 error 4 in libwlroots.so.8[7f035fa07000+5a000]
# machine # [ 14.358108] Code: 4f a8 ff ff eb aa 0f 1f 44 00 00 c3 0f 1f 80 00 00 00 00 41 54 49 89 f4 55 31 ed 53 48 89 fb 48 8d 7f 18 48 8d 83 b8 00 00 00 <80> 7f 08 00 75 0d 48 83 3f 00 0f 85 91 00 00 00 48 89 fd 48 83 c7
os.environ["QEMU_OPTS"] = "-vga virtio"
with subtest("Wait for cage to boot up"):
start_all()
machine.wait_for_file("/run/user/${toString user.uid}/wayland-0.lock")

View file

@ -92,13 +92,19 @@ in
{ onlySSL = true;
sslCertificate = "${example-good-cert}/server.crt";
sslCertificateKey = "${example-good-cert}/server.key";
locations."/".extraConfig = "return 200 'It works!';";
locations."/".extraConfig = ''
add_header Content-Type text/plain;
return 200 'It works!';
'';
};
services.nginx.virtualHosts."bad.example.com" =
{ onlySSL = true;
sslCertificate = "${example-bad-cert}/server.crt";
sslCertificateKey = "${example-bad-cert}/server.key";
locations."/".extraConfig = "return 200 'It does not work!';";
locations."/".extraConfig = ''
add_header Content-Type text/plain;
return 200 'It does not work!';
'';
};
environment.systemPackages = with pkgs;

View file

@ -18,6 +18,11 @@ in {
environment.systemPackages = [ pkgs.git ];
systemd.tmpfiles.rules = [
# type path mode user group age arg
" d /git 0755 root root - -"
];
services.gitDaemon = {
enable = true;
basePath = "/git";
@ -35,7 +40,6 @@ in {
with subtest("create project.git"):
server.succeed(
"mkdir /git",
"git init --bare /git/project.git",
"touch /git/project.git/git-daemon-export-ok",
)

View file

@ -1,4 +1,4 @@
import ./make-test-python.nix ({ pkgs, ... }:
import ./make-test-python.nix ({ pkgs, lib, ... }:
let
configDir = "/var/lib/foobar";
@ -6,9 +6,7 @@ let
mqttPassword = "secret";
in {
name = "home-assistant";
meta = with pkgs.lib; {
maintainers = with maintainers; [ dotlambda ];
};
meta.maintainers = lib.teams.home-assistant.members;
nodes.hass = { pkgs, ... }: {
environment.systemPackages = with pkgs; [ mosquitto ];
@ -47,6 +45,10 @@ in {
payload_on = "let_there_be_light";
payload_off = "off";
}];
emulated_hue = {
host_ip = "127.0.0.1";
listen_port = 80;
};
logger = {
default = "info";
logs."homeassistant.components.mqtt" = "debug";
@ -82,6 +84,9 @@ in {
hass.succeed(
"mosquitto_pub -V mqttv5 -t home-assistant/test -u ${mqttUsername} -P '${mqttPassword}' -m let_there_be_light"
)
with subtest("Check that capabilities are passed for emulated_hue to bind to port 80"):
hass.wait_for_open_port(80)
hass.succeed("curl --fail http://localhost:80/description.xml")
with subtest("Print log to ease debugging"):
output_log = hass.succeed("cat ${configDir}/home-assistant.log")
print("\n### home-assistant.log ###\n")
@ -93,5 +98,8 @@ in {
# example line: 2020-06-20 10:01:32 DEBUG (MainThread) [homeassistant.components.mqtt] Received message on home-assistant/test: b'let_there_be_light'
with subtest("Check we received the mosquitto message"):
assert "let_there_be_light" in output_log
with subtest("Check systemd unit hardening"):
hass.log(hass.succeed("systemd-analyze security home-assistant.service"))
'';
})

View file

@ -75,7 +75,7 @@ let
else ''
def assemble_qemu_flags():
flags = "-cpu max"
${if system == "x86_64-linux"
${if (system == "x86_64-linux" || system == "i686-linux")
then ''flags += " -m 1024"''
else ''flags += " -m 768 -enable-kvm -machine virt,gic-version=host"''
}

View file

@ -1,16 +1,156 @@
import ./make-test-python.nix ({ lib, ...}:
import ./make-test-python.nix ({ lib, pkgs, ... }:
{
name = "jellyfin";
meta.maintainers = with lib.maintainers; [ minijackson ];
{
name = "jellyfin";
meta.maintainers = with lib.maintainers; [ minijackson ];
machine =
{ ... }:
{ services.jellyfin.enable = true; };
machine =
{ ... }:
{
services.jellyfin.enable = true;
environment.systemPackages = with pkgs; [ ffmpeg ];
};
testScript = ''
machine.wait_for_unit("jellyfin.service")
machine.wait_for_open_port(8096)
machine.succeed("curl --fail http://localhost:8096/")
'';
})
# Documentation of the Jellyfin API: https://api.jellyfin.org/
# Beware, this link can be resource intensive
testScript =
let
payloads = {
auth = pkgs.writeText "auth.json" (builtins.toJSON {
Username = "jellyfin";
});
empty = pkgs.writeText "empty.json" (builtins.toJSON { });
};
in
''
import json
import time
from urllib.parse import urlencode
machine.wait_for_unit("jellyfin.service")
machine.wait_for_open_port(8096)
machine.succeed("curl --fail http://localhost:8096/")
machine.wait_until_succeeds("curl --fail http://localhost:8096/health | grep Healthy")
auth_header = 'MediaBrowser Client="NixOS Integration Tests", DeviceId="1337", Device="Apple II", Version="20.09"'
def api_get(path):
return f"curl --fail 'http://localhost:8096{path}' -H 'X-Emby-Authorization:{auth_header}'"
def api_post(path, json_file=None):
if json_file:
return f"curl --fail -X post 'http://localhost:8096{path}' -d '@{json_file}' -H Content-Type:application/json -H 'X-Emby-Authorization:{auth_header}'"
else:
return f"curl --fail -X post 'http://localhost:8096{path}' -H 'X-Emby-Authorization:{auth_header}'"
with machine.nested("Wizard completes"):
machine.wait_until_succeeds(api_get("/Startup/Configuration"))
machine.succeed(api_get("/Startup/FirstUser"))
machine.succeed(api_post("/Startup/Complete"))
with machine.nested("Can login"):
auth_result = machine.succeed(
api_post(
"/Users/AuthenticateByName",
"${payloads.auth}",
)
)
auth_result = json.loads(auth_result)
auth_token = auth_result["AccessToken"]
auth_header += f", Token={auth_token}"
sessions_result = machine.succeed(api_get("/Sessions"))
sessions_result = json.loads(sessions_result)
this_session = [
session for session in sessions_result if session["DeviceId"] == "1337"
]
if len(this_session) != 1:
raise Exception("Session not created")
me = machine.succeed(api_get("/Users/Me"))
me = json.loads(me)["Id"]
with machine.nested("Can add library"):
tempdir = machine.succeed("mktemp -d -p /var/lib/jellyfin").strip()
machine.succeed(f"chmod 755 '{tempdir}'")
# Generate a dummy video that we can test later
videofile = f"{tempdir}/Big Buck Bunny (2008) [1080p].mkv"
machine.succeed(f"ffmpeg -f lavfi -i testsrc2=duration=5 '{videofile}'")
add_folder_query = urlencode(
{
"name": "My Library",
"collectionType": "Movies",
"paths": tempdir,
"refreshLibrary": "true",
}
)
machine.succeed(
api_post(
f"/Library/VirtualFolders?{add_folder_query}",
"${payloads.empty}",
)
)
def is_refreshed(_):
folders = machine.succeed(api_get(f"/Library/VirtualFolders"))
folders = json.loads(folders)
print(folders)
return all(folder["RefreshStatus"] == "Idle" for folder in folders)
retry(is_refreshed)
with machine.nested("Can identify videos"):
items = []
# For some reason, having the folder refreshed doesn't mean the
# movie was scanned
def has_movie(_):
global items
items = machine.succeed(
api_get(f"/Users/{me}/Items?IncludeItemTypes=Movie&Recursive=true")
)
items = json.loads(items)["Items"]
return len(items) == 1
retry(has_movie)
video = items[0]["Id"]
item_info = machine.succeed(api_get(f"/Users/{me}/Items/{video}"))
item_info = json.loads(item_info)
if item_info["Name"] != "Big Buck Bunny":
raise Exception("Jellyfin failed to properly identify file")
with machine.nested("Can read videos"):
media_source_id = item_info["MediaSources"][0]["Id"]
machine.succeed(
"ffmpeg"
+ f" -headers 'X-Emby-Authorization:{auth_header}'"
+ f" -i http://localhost:8096/Videos/{video}/master.m3u8?mediaSourceId={media_source_id}"
+ f" /tmp/test.mkv"
)
duration = machine.succeed(
"ffprobe /tmp/test.mkv"
+ " -show_entries format=duration"
+ " -of compact=print_section=0:nokey=1"
)
if duration.strip() != "5.000000":
raise Exception("Downloaded video has wrong duration")
'';
})

View file

@ -1,4 +1,4 @@
import ./make-test-python.nix ({ pkgs, ... }:
import ./make-test-python.nix ({ pkgs, lib, ... }:
let
port = 1888;
@ -30,6 +30,9 @@ in {
];
};
};
# disable private /tmp for this test
systemd.services.mosquitto.serviceConfig.PrivateTmp = lib.mkForce false;
};
client1 = client;

View file

@ -69,6 +69,9 @@ in {
imports = [ ../modules/profiles/installation-device.nix
../modules/profiles/base.nix ];
virtualisation.memorySize = 1300;
# To add the secondary disk:
virtualisation.qemu.options = [ "-drive index=2,file=${debianImage}/disk-image.qcow2,read-only,if=virtio" ];
# The test cannot access the network, so any packages
# nixos-rebuild needs must be included in the VM.
system.extraDependencies = with pkgs;
@ -95,11 +98,6 @@ in {
});
testScript = ''
# hack to add the secondary disk
os.environ[
"QEMU_OPTS"
] = "-drive index=2,file=${debianImage}/disk-image.qcow2,read-only,if=virtio"
machine.start()
machine.succeed("udevadm settle")
machine.wait_for_unit("multi-user.target")

View file

@ -61,7 +61,7 @@ in
client.wait_until_succeeds("ping -c1 server")
# make sure pinnwand is listening
server.wait_until_succeeds("ss -lnp | grep ${toString port}")
server.wait_for_open_port(${toString port})
# send the contents of /etc/machine-id
response = client.succeed("steck paste /etc/machine-id")
@ -75,6 +75,12 @@ in
if line.startswith("Removal link:"):
removal_link = line.split(":", 1)[1]
# start the reaper, it shouldn't do anything meaningful here
server.systemctl("start pinnwand-reaper.service")
server.wait_until_fails("systemctl is-active -q pinnwand-reaper.service")
server.log(server.execute("journalctl -u pinnwand-reaper -e --no-pager")[1])
# check whether paste matches what we sent
client.succeed(f"curl {raw_url} > /tmp/machine-id")
client.succeed("diff /tmp/machine-id /etc/machine-id")
@ -82,5 +88,7 @@ in
# remove paste and check that it's not available any more
client.succeed(f"curl {removal_link}")
client.fail(f"curl --fail {raw_url}")
server.log(server.succeed("systemd-analyze security pinnwand"))
'';
})

View file

@ -25,6 +25,7 @@ let
machine = {
services.rspamd.enable = true;
networking.enableIPv6 = enableIPv6;
virtualisation.memorySize = 1024;
};
testScript = ''
start_all()
@ -68,6 +69,7 @@ in
group = "rspamd";
}];
};
virtualisation.memorySize = 1024;
};
testScript = ''
@ -116,6 +118,7 @@ in
'';
};
};
virtualisation.memorySize = 1024;
};
testScript = ''
@ -221,6 +224,7 @@ in
rspamd_logger.infox(rspamd_config, 'Work dammit!!!')
'';
};
virtualisation.memorySize = 1024;
};
testScript = ''
${initMachine}
@ -287,6 +291,7 @@ in
postfix.enable = true;
workers.rspamd_proxy.type = "rspamd_proxy";
};
virtualisation.memorySize = 1024;
};
testScript = ''
${initMachine}

View file

@ -0,0 +1,176 @@
# verifies:
# 1. Traffic Server is able to start
# 2. Traffic Server spawns traffic_crashlog upon startup
# 3. Traffic Server proxies HTTP requests according to URL remapping rules
# in 'services.trafficserver.remap'
# 4. Traffic Server applies per-map settings specified with the conf_remap
# plugin
# 5. Traffic Server caches HTTP responses
# 6. Traffic Server processes HTTP PUSH requests
# 7. Traffic Server can load the healthchecks plugin
# 8. Traffic Server logs HTTP traffic as configured
#
# uses:
# - bin/traffic_manager
# - bin/traffic_server
# - bin/traffic_crashlog
# - bin/traffic_cache_tool
# - bin/traffic_ctl
# - bin/traffic_logcat
# - bin/traffic_logstats
# - bin/tspush
import ./make-test-python.nix ({ pkgs, ... }: {
name = "trafficserver";
meta = with pkgs.lib.maintainers; {
maintainers = [ midchildan ];
};
nodes = {
ats = { pkgs, lib, config, ... }: let
user = config.users.users.trafficserver.name;
group = config.users.groups.trafficserver.name;
healthchecks = pkgs.writeText "healthchecks.conf" ''
/status /tmp/ats.status text/plain 200 500
'';
in {
services.trafficserver.enable = true;
services.trafficserver.records = {
proxy.config.http.server_ports = "80 80:ipv6";
proxy.config.hostdb.host_file.path = "/etc/hosts";
proxy.config.log.max_space_mb_headroom = 0;
proxy.config.http.push_method_enabled = 1;
# check that cache storage is usable before accepting traffic
proxy.config.http.wait_for_cache = 2;
};
services.trafficserver.plugins = [
{ path = "healthchecks.so"; arg = toString healthchecks; }
{ path = "xdebug.so"; }
];
services.trafficserver.remap = ''
map http://httpbin.test http://httpbin
map http://pristine-host-hdr.test http://httpbin \
@plugin=conf_remap.so \
@pparam=proxy.config.url_remap.pristine_host_hdr=1
map http://ats/tspush http://httpbin/cache \
@plugin=conf_remap.so \
@pparam=proxy.config.http.cache.required_headers=0
'';
services.trafficserver.storage = ''
/dev/vdb volume=1
'';
networking.firewall.allowedTCPPorts = [ 80 ];
virtualisation.emptyDiskImages = [ 256 ];
services.udev.extraRules = ''
KERNEL=="vdb", OWNER="${user}", GROUP="${group}"
'';
};
httpbin = { pkgs, lib, ... }: let
python = pkgs.python3.withPackages
(ps: with ps; [ httpbin gunicorn gevent ]);
in {
systemd.services.httpbin = {
enable = true;
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${python}/bin/gunicorn -b 0.0.0.0:80 httpbin:app -k gevent";
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
};
client = { pkgs, lib, ... }: {
environment.systemPackages = with pkgs; [ curl ];
};
};
testScript = { nodes, ... }: let
sampleFile = pkgs.writeText "sample.txt" ''
It's the season of White Album.
'';
in ''
import json
import re
ats.wait_for_unit("trafficserver")
ats.wait_for_open_port(80)
httpbin.wait_for_unit("httpbin")
httpbin.wait_for_open_port(80)
with subtest("Traffic Server is running"):
out = ats.succeed("traffic_ctl server status")
assert out.strip() == "Proxy -- on"
with subtest("traffic_crashlog is running"):
ats.succeed("pgrep -f traffic_crashlog")
with subtest("basic remapping works"):
out = client.succeed("curl -vv -H 'Host: httpbin.test' http://ats/headers")
assert json.loads(out)["headers"]["Host"] == "httpbin"
with subtest("conf_remap plugin works"):
out = client.succeed(
"curl -vv -H 'Host: pristine-host-hdr.test' http://ats/headers"
)
assert json.loads(out)["headers"]["Host"] == "pristine-host-hdr.test"
with subtest("caching works"):
out = client.succeed(
"curl -vv -D - -H 'Host: httpbin.test' -H 'X-Debug: X-Cache' http://ats/cache/60 -o /dev/null"
)
assert "X-Cache: miss" in out
out = client.succeed(
"curl -vv -D - -H 'Host: httpbin.test' -H 'X-Debug: X-Cache' http://ats/cache/60 -o /dev/null"
)
assert "X-Cache: hit-fresh" in out
with subtest("pushing to cache works"):
url = "http://ats/tspush"
ats.succeed(f"echo {url} > /tmp/urls.txt")
out = ats.succeed(
f"tspush -f '${sampleFile}' -u {url}"
)
assert "HTTP/1.0 201 Created" in out, "cache push failed"
out = ats.succeed(
"traffic_cache_tool --spans /etc/trafficserver/storage.config find --input /tmp/urls.txt"
)
assert "Span: /dev/vdb" in out, "cache not stored on disk"
out = client.succeed(f"curl {url}").strip()
expected = (
open("${sampleFile}").read().strip()
)
assert out == expected, "cache content mismatch"
with subtest("healthcheck plugin works"):
out = client.succeed("curl -vv http://ats/status -o /dev/null -w '%{http_code}'")
assert out.strip() == "500"
ats.succeed("touch /tmp/ats.status")
out = client.succeed("curl -vv http://ats/status -o /dev/null -w '%{http_code}'")
assert out.strip() == "200"
with subtest("logging works"):
access_log_path = "/var/log/trafficserver/squid.blog"
ats.wait_for_file(access_log_path)
out = ats.succeed(f"traffic_logcat {access_log_path}").split("\n")[0]
expected = "^\S+ \S+ \S+ TCP_MISS/200 \S+ GET http://httpbin/headers - DIRECT/httpbin application/json$"
assert re.fullmatch(expected, out) is not None, "no matching logs"
out = json.loads(ats.succeed(f"traffic_logstats -jf {access_log_path}"))
assert out["total"]["error.total"]["req"] == "0", "unexpected log stat"
'';
})

View file

@ -61,13 +61,16 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
services.unbound = {
enable = true;
interfaces = [ "192.168.0.1" "fd21::1" "::1" "127.0.0.1" ];
allowedAccess = [ "192.168.0.0/24" "fd21::/64" "::1" "127.0.0.0/8" ];
extraConfig = ''
server:
local-data: "example.local. IN A 1.2.3.4"
local-data: "example.local. IN AAAA abcd::eeff"
'';
settings = {
server = {
interface = [ "192.168.0.1" "fd21::1" "::1" "127.0.0.1" ];
access-control = [ "192.168.0.0/24 allow" "fd21::/64 allow" "::1 allow" "127.0.0.0/8 allow" ];
local-data = [
''"example.local. IN A 1.2.3.4"''
''"example.local. IN AAAA abcd::eeff"''
];
};
};
};
};
@ -90,19 +93,25 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
services.unbound = {
enable = true;
allowedAccess = [ "192.168.0.0/24" "fd21::/64" "::1" "127.0.0.0/8" ];
interfaces = [ "::1" "127.0.0.1" "192.168.0.2" "fd21::2"
"192.168.0.2@853" "fd21::2@853" "::1@853" "127.0.0.1@853"
"192.168.0.2@443" "fd21::2@443" "::1@443" "127.0.0.1@443" ];
forwardAddresses = [
(lib.head nodes.authoritative.config.networking.interfaces.eth1.ipv6.addresses).address
(lib.head nodes.authoritative.config.networking.interfaces.eth1.ipv4.addresses).address
];
extraConfig = ''
server:
tls-service-pem: ${cert}/cert.pem
tls-service-key: ${cert}/key.pem
'';
settings = {
server = {
interface = [ "::1" "127.0.0.1" "192.168.0.2" "fd21::2"
"192.168.0.2@853" "fd21::2@853" "::1@853" "127.0.0.1@853"
"192.168.0.2@443" "fd21::2@443" "::1@443" "127.0.0.1@443" ];
access-control = [ "192.168.0.0/24 allow" "fd21::/64 allow" "::1 allow" "127.0.0.0/8 allow" ];
tls-service-pem = "${cert}/cert.pem";
tls-service-key = "${cert}/key.pem";
};
forward-zone = [
{
name = ".";
forward-addr = [
(lib.head nodes.authoritative.config.networking.interfaces.eth1.ipv6.addresses).address
(lib.head nodes.authoritative.config.networking.interfaces.eth1.ipv4.addresses).address
];
}
];
};
};
};
@ -122,12 +131,14 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
services.unbound = {
enable = true;
allowedAccess = [ "::1" "127.0.0.0/8" ];
interfaces = [ "::1" "127.0.0.1" ];
settings = {
server = {
interface = [ "::1" "127.0.0.1" ];
access-control = [ "::1 allow" "127.0.0.0/8 allow" ];
};
include = "/etc/unbound/extra*.conf";
};
localControlSocketPath = "/run/unbound/unbound.ctl";
extraConfig = ''
include: "/etc/unbound/extra*.conf"
'';
};
users.users = {
@ -143,12 +154,13 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
unauthorizeduser = { isSystemUser = true; };
};
# Used for testing configuration reloading
environment.etc = {
"unbound-extra1.conf".text = ''
forward-zone:
name: "example.local."
forward-addr: ${(lib.head nodes.resolver.config.networking.interfaces.eth1.ipv6.addresses).address}
forward-addr: ${(lib.head nodes.resolver.config.networking.interfaces.eth1.ipv4.addresses).address}
name: "example.local."
forward-addr: ${(lib.head nodes.resolver.config.networking.interfaces.eth1.ipv6.addresses).address}
forward-addr: ${(lib.head nodes.resolver.config.networking.interfaces.eth1.ipv4.addresses).address}
'';
"unbound-extra2.conf".text = ''
auth-zone:

View file

@ -1,4 +1,4 @@
import ./make-test-python.nix ({ pkgs, ... }:
import ./make-test-python.nix ({ pkgs, lib, ... }:
{
machine = { pkgs, ... }:
@ -6,6 +6,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
services.zigbee2mqtt = {
enable = true;
};
systemd.services.zigbee2mqtt.serviceConfig.DevicePolicy = lib.mkForce "auto";
};
testScript = ''
@ -14,6 +16,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
machine.succeed(
"journalctl -eu zigbee2mqtt | grep \"Error: Error while opening serialport 'Error: Error: No such file or directory, cannot open /dev/ttyACM0'\""
)
machine.log(machine.succeed("systemd-analyze security zigbee2mqtt.service"))
'';
}
)

View file

@ -0,0 +1,63 @@
{ lib
, stdenv
, fetchFromGitHub
, legacy ? false
, libinput
, pkg-config
, makeWrapper
, openal
, alure
, libXtst
, libX11
}:
let
inherit (lib) optionals;
in
stdenv.mkDerivation rec {
pname = "bucklespring";
version = "1.5.0";
src = fetchFromGitHub {
owner = "zevv";
repo = pname;
rev = version;
sha256 = "114dib4npb7r1z2zd1fwsx71xbf9r6psxqd7n7590cwz1w3r51mz";
};
nativeBuildInputs = [ pkg-config makeWrapper ];
buildInputs = [ openal alure ]
++ optionals (legacy) [ libXtst libX11 ]
++ optionals (!legacy) [ libinput ];
makeFlags = optionals (!legacy) [ "libinput=1" ];
installPhase = ''
runHook preInstall
mkdir -p $out/share/wav
cp -r $src/wav $out/share/.
install -D ./buckle.desktop $out/share/applications/buckle.desktop
install -D ./buckle $out/bin/buckle
wrapProgram $out/bin/buckle --add-flags "-p $out/share/wav"
runHook postInstall
'';
meta = with lib; {
description = "Nostalgia bucklespring keyboard sound";
longDescription = ''
When built with libinput (wayland or bare console),
users need to be in the input group to use this:
<code>users.users.alice.extraGroups = [ "input" ];</code>
'';
homepage = "https://github.com/zevv/bucklespring";
license = licenses.gpl2Only;
platforms = platforms.unix;
maintainers = [ maintainers.evils ];
};
}

View file

@ -6,7 +6,7 @@
, cmake
, docbook_xml_dtd_45
, docbook_xsl
, ffmpeg_3
, ffmpeg
, flac
, id3lib
, libogg
@ -31,21 +31,22 @@ stdenv.mkDerivation rec {
version = "3.8.6";
src = fetchurl {
url = "mirror://sourceforge/project/kid3/kid3/${version}/${pname}-${version}.tar.gz";
sha256 = "sha256-ce+MWCJzAnN+u+07f0dvn0jnbqiUlS2RbcM9nAj5bgg=";
url = "https://download.kde.org/stable/${pname}/${version}/${pname}-${version}.tar.xz";
hash = "sha256-R4gAWlCw8RezhYbw1XDo+wdp797IbLoM3wqHwr+ul6k=";
};
nativeBuildInputs = [
cmake
docbook_xml_dtd_45
docbook_xsl
pkg-config
python3
wrapQtAppsHook
];
buildInputs = [
automoc4
chromaprint
docbook_xml_dtd_45
docbook_xsl
ffmpeg_3
ffmpeg
flac
id3lib
libogg
@ -53,7 +54,6 @@ stdenv.mkDerivation rec {
libxslt
mp4v2
phonon
python3
qtbase
qtmultimedia
qtquickcontrols
@ -71,6 +71,7 @@ stdenv.mkDerivation rec {
'';
meta = with lib; {
homepage = "https://kid3.kde.org/";
description = "A simple and powerful audio tag editor";
longDescription = ''
If you want to easily tag multiple MP3, Ogg/Vorbis, FLAC, MPC, MP4/AAC,
@ -101,7 +102,6 @@ stdenv.mkDerivation rec {
- Edit synchronized lyrics and event timing codes, import and export
LRC files.
'';
homepage = "http://kid3.sourceforge.net/";
license = licenses.lgpl2Plus;
maintainers = [ maintainers.AndersonTorres ];
platforms = platforms.linux;

File diff suppressed because it is too large Load diff

View file

@ -4,18 +4,17 @@
rustPlatform.buildRustPackage rec {
pname = "librespot";
version = "0.1.3";
version = "0.1.6";
src = fetchFromGitHub {
owner = "librespot-org";
repo = "librespot";
rev = "v${version}";
sha256 = "1ixh47yvaamrpzagqsiimc3y6bi4nbym95843d23am55zkrgnmy5";
sha256 = "153i9n3qwmmwc29f62cz8nbqrlry16iygvibm1sdnvpf0s6wk5f3";
};
cargoSha256 = "1csls8kzzx28ng6w9vdwhnnav5sqp2m5fj430db5z306xh5acg3d";
cargoPatches = [ ./cargo-lock.patch ];
cargoSha256 = "11d64rpq4b5rdxk5wx0hhzgc6mvs6h2br0w3kfncfklp67vn3v4v";
cargoBuildFlags = with lib; [
"--no-default-features"

View file

@ -21,6 +21,8 @@ lib.makeScope newScope (self: with self; {
mopidy-musicbox-webclient = callPackage ./musicbox-webclient.nix { };
mopidy-podcast = callPackage ./podcast.nix { };
mopidy-scrobbler = callPackage ./scrobbler.nix { };
mopidy-somafm = callPackage ./somafm.nix { };

View file

@ -0,0 +1,31 @@
{ lib, python3Packages, mopidy }:
python3Packages.buildPythonApplication rec {
pname = "mopidy-podcast";
version = "3.0.0";
src = python3Packages.fetchPypi {
inherit version;
pname = "Mopidy-Podcast";
sha256 = "1z2b523yvdpcf8p7m7kczrvaw045lmxzhq4qj00dflxa2yw61qxr";
};
propagatedBuildInputs = [
mopidy
python3Packages.cachetools
python3Packages.uritools
];
checkInputs = with python3Packages; [
pytestCheckHook
];
meta = with lib; {
homepage = "https://github.com/tkem/mopidy-podcast";
description = "Mopidy extension for browsing and playing podcasts";
license = licenses.asl20;
maintainers = [
maintainers.daneads
];
};
}

View file

@ -4,7 +4,7 @@
, boost
, curl
, fetchFromGitHub
, ffmpeg_3
, ffmpeg
, lame
, libev
, libmicrohttpd
@ -17,13 +17,13 @@
stdenv.mkDerivation rec {
pname = "musikcube";
version = "0.96.5";
version = "0.96.7";
src = fetchFromGitHub {
owner = "clangen";
repo = pname;
rev = version;
sha256 = "sha256-GxMQPP8i/NWvduf10f+xVyuG666pChj9RsiF4jfygyY=";
sha256 = "1y00vwn1h10cfflxrm5bk271ak9gilhjycgi44hlkkhmf5bdgn35";
};
nativeBuildInputs = [
@ -34,7 +34,7 @@ stdenv.mkDerivation rec {
alsaLib
boost
curl
ffmpeg_3
ffmpeg
lame
libev
libmicrohttpd

View file

@ -11,17 +11,17 @@
stdenv.mkDerivation rec {
pname = "ocenaudio";
version = "3.10.2";
version = "3.10.6";
src = fetchurl {
url = "https://www.ocenaudio.com/downloads/index.php/ocenaudio_debian9_64.deb?version=${version}";
sha256 = "sha256-mmo6/zc/3R8ptXfY01RKUOLgmDhWTHiYBMlGqpdMTAo=";
sha256 = "0fgvm1xw2kgrqj3w6slpfxbb3pw9k8i0dz16q9d5d8gyyvr2mh8g";
};
nativeBuildInputs = [
autoPatchelfHook
qt5.qtbase
qt5.wrapQtAppsHook
libjack2
libpulseaudio
bzip2
@ -33,7 +33,6 @@ stdenv.mkDerivation rec {
dontUnpack = true;
dontBuild = true;
dontStrip = true;
dontWrapQtApps = true;
installPhase = ''
mkdir -p $out

View file

@ -1,7 +1,7 @@
{ lib, stdenv, fetchurl, python3, wrapGAppsHook, gettext, libsoup, gnome3, gtk3, gdk-pixbuf, librsvg,
tag ? "", xvfb_run, dbus, glibcLocales, glib, glib-networking, gobject-introspection, hicolor-icon-theme,
gst_all_1, withGstPlugins ? true,
xineBackend ? false, xineLib,
xineBackend ? false, xine-lib,
withDbusPython ? false, withPyInotify ? false, withMusicBrainzNgs ? false, withPahoMqtt ? false,
webkitgtk ? null,
keybinder3 ? null, gtksourceview ? null, libmodplug ? null, kakasi ? null, libappindicator-gtk3 ? null }:
@ -23,7 +23,7 @@ python3.pkgs.buildPythonApplication rec {
checkInputs = [ gdk-pixbuf hicolor-icon-theme ] ++ (with python3.pkgs; [ pytest pytest_xdist polib xvfb_run dbus.daemon glibcLocales ]);
buildInputs = [ gnome3.adwaita-icon-theme libsoup glib glib-networking gtk3 webkitgtk gdk-pixbuf keybinder3 gtksourceview libmodplug libappindicator-gtk3 kakasi gobject-introspection ]
++ (if xineBackend then [ xineLib ] else with gst_all_1;
++ (if xineBackend then [ xine-lib ] else with gst_all_1;
[ gstreamer gst-plugins-base ] ++ optionals withGstPlugins [ gst-plugins-good gst-plugins-ugly gst-plugins-bad ]);
propagatedBuildInputs = with python3.pkgs; [ pygobject3 pycairo mutagen gst-python feedparser ]

View file

@ -22,7 +22,7 @@
with lib;
let
version = "0.21.0";
version = "0.21.1";
majorMinorVersion = versions.majorMinor version;
desktop = fetchurl {
url = "https://raw.githubusercontent.com/bitcoin-core/packaging/${majorMinorVersion}/debian/bitcoin-qt.desktop";
@ -38,7 +38,7 @@ stdenv.mkDerivation rec {
"https://bitcoincore.org/bin/bitcoin-core-${version}/bitcoin-${version}.tar.gz"
"https://bitcoin.org/bin/bitcoin-core-${version}/bitcoin-${version}.tar.gz"
];
sha256 = "1a91202c62ee49fb64d57a52b8d6d01cd392fffcbef257b573800f9289655f37";
sha256 = "caff23449220cf45753f312cefede53a9eac64000bb300797916526236b6a1e0";
};
nativeBuildInputs =

View file

@ -0,0 +1,29 @@
{ stdenv, lib, fetchFromGitHub }:
stdenv.mkDerivation rec {
pname = "miniscript";
version = "unstable-2020-12-01";
src = fetchFromGitHub {
owner = "sipa";
repo = pname;
rev = "02682a398a35b410571b10cde7f39837141ddad6";
sha256 = "079jz4g88cfzfm9a6ykby9haxwcs033c1288mgr8cl2hw4qd2sjl";
};
installPhase = ''
runHook preInstall
mkdir -p $out/bin
cp miniscript $out/bin/miniscript
runHook postInstall
'';
meta = with lib; {
description = "Compiler and inspector for the miniscript Bitcoin policy language";
longDescription = "Miniscript is a language for writing (a subset of) Bitcoin Scripts in a structured way, enabling analysis, composition, generic signing and more.";
homepage = "http://bitcoin.sipa.be/miniscript/";
license = licenses.mit;
platforms = platforms.linux;
maintainers = with maintainers; [ RaghavSood jb55 ];
};
}

View file

@ -17,22 +17,15 @@
with lib;
let
arch = if stdenv.isx86_64 then "x86-64"
else if stdenv.isi686 then "i686"
else if stdenv.isAarch64 then "armv8-a"
else throw "unsupported architecture";
in
stdenv.mkDerivation rec {
pname = "monero-gui";
version = "0.17.1.9";
version = "0.17.2.1";
src = fetchFromGitHub {
owner = "monero-project";
repo = "monero-gui";
rev = "v${version}";
sha256 = "0143mmxk0jfb5pmjlx6v0knvf8v49kmkpjxlp6rw8lwnlf71xadn";
sha256 = "1apjvpvn6hg0k0ak6wpg4prcdcslnb6fqhzzg2p4iy846f0ai9ji";
};
nativeBuildInputs = [
@ -58,7 +51,10 @@ stdenv.mkDerivation rec {
chmod -R +w source/monero
'';
patches = [ ./move-log-file.patch ];
patches = [
./move-log-file.patch
./use-system-libquirc.patch
];
postPatch = ''
# set monero-gui version
@ -69,17 +65,15 @@ stdenv.mkDerivation rec {
substituteInPlace src/daemon/DaemonManager.cpp \
--replace 'QApplication::applicationDirPath() + "' '"${monero}/bin'
# only build external deps, *not* the full monero
# 1: only build external deps, *not* the full monero
# 2: use nixpkgs libraries
substituteInPlace CMakeLists.txt \
--replace 'add_subdirectory(monero)' \
'add_subdirectory(monero EXCLUDE_FROM_ALL)'
# use nixpkgs quirc
substituteInPlace CMakeLists.txt \
'add_subdirectory(monero EXCLUDE_FROM_ALL)' \
--replace 'add_subdirectory(external)' ""
'';
cmakeFlags = [ "-DARCH=${arch}" ];
cmakeFlags = [ "-DARCH=default" ];
desktopItem = makeDesktopItem {
name = "monero-wallet-gui";

View file

@ -0,0 +1,37 @@
diff --git a/src/QR-Code-scanner/CMakeLists.txt b/src/QR-Code-scanner/CMakeLists.txt
index 15e288df..2e9b3305 100644
--- a/src/QR-Code-scanner/CMakeLists.txt
+++ b/src/QR-Code-scanner/CMakeLists.txt
@@ -1,11 +1,18 @@
+find_library(QUIRC_LIBRARY quirc REQUIRED)
+find_path(QUIRC_INCLUDE_DIR quirc.h REQUIRED)
+
add_library(qrdecoder STATIC
Decoder.cpp
)
+target_include_directories(qrdecoder
+ PUBLIC
+ ${QUIRC_INCLUDE_DIR}
+)
target_link_libraries(qrdecoder
PUBLIC
Qt5::Gui
PRIVATE
- quirc
+ ${QUIRC_LIBRARY}
)
if(WITH_SCANNER)
diff --git a/src/QR-Code-scanner/Decoder.cpp b/src/QR-Code-scanner/Decoder.cpp
index 1bb99140..353ca189 100644
--- a/src/QR-Code-scanner/Decoder.cpp
+++ b/src/QR-Code-scanner/Decoder.cpp
@@ -30,7 +30,7 @@
#include <limits>
-#include "quirc.h"
+#include <quirc.h>
QrDecoder::QrDecoder()
: m_qr(quirc_new())

View file

@ -17,13 +17,13 @@ assert trezorSupport -> all (x: x!=null) [ libusb1 protobuf python3 ];
stdenv.mkDerivation rec {
pname = "monero";
version = "0.17.1.9";
version = "0.17.2.0";
src = fetchFromGitHub {
owner = "monero-project";
repo = "monero";
rev = "v${version}";
sha256 = "0jqss4csvkcrhrmaa3vrnyv6yiwqpbfw7037clx9xcfm4qrrfiwy";
sha256 = "0jwlmrpzisvw1c06cvd5b3s3hd4w0pa1qmrypfwah67qj3x6hnb6";
fetchSubmodules = true;
};

View file

@ -2,13 +2,13 @@
stdenv.mkDerivation rec {
pname = "bluej";
version = "5.0.0";
version = "5.0.1";
src = fetchurl {
# We use the deb here. First instinct might be to go for the "generic" JAR
# download, but that is actually a graphical installer that is much harder
# to unpack than the deb.
url = "https://www.bluej.org/download/files/BlueJ-linux-${builtins.replaceStrings ["."] [""] version}.deb";
sha256 = "sha256-U81FIf67Qm/86+hA9iUCHt61dxiZsTkkequlVjft6/0=";
sha256 = "sha256-KhNhJ2xsw1g2yemwP6NQmJvk4cxZAQQNPEUBuLso5qM=";
};
nativeBuildInputs = [ makeWrapper ];

View file

@ -4,8 +4,8 @@ let
src = pkgs.fetchgit {
url = "https://github.com/ttuegel/emacs2nix.git";
fetchSubmodules = true;
rev = "b815a9323c1f58f6c163a1f968939c57a8b6cfa0";
sha256 = "183xlmhjmj4z2zssc0pw990h7bf3bam8zqswnf1zcsyp8z7yrl5g";
rev = "860da04ca91cbb69c9b881a54248d16bdaaf9923";
sha256 = "1r3xmyk9rfgx7ln69dk8mgbnh3awcalm3r1c5ia2shlsrymvv1df";
};
in pkgs.mkShell {

View file

@ -362,6 +362,7 @@ let
zmq = super.zmq.overrideAttrs (old: {
stripDebugList = [ "share" ];
preBuild = ''
export EZMQ_LIBDIR=$(mktemp -d)
make
'';
nativeBuildInputs = [
@ -372,7 +373,7 @@ let
(pkgs.zeromq.override { enableDrafts = true; })
];
postInstall = ''
mv $out/share/emacs/site-lisp/elpa/zmq-*/src/.libs/emacs-zmq.so $out/share/emacs/site-lisp/elpa/zmq-*
mv $EZMQ_LIBDIR/emacs-zmq.* $out/share/emacs/site-lisp/elpa/zmq-*
rm -r $out/share/emacs/site-lisp/elpa/zmq-*/src
rm $out/share/emacs/site-lisp/elpa/zmq-*/Makefile
'';

View file

@ -99,7 +99,10 @@ return Promise to resolve in that process."
("github" (list "nix-prefetch-url"
"--unpack" (concat "https://github.com/" repo "/archive/" commit ".tar.gz")))
("gitlab" (list "nix-prefetch-url"
"--unpack" (concat "https://gitlab.com/" repo "/repository/archive.tar.gz?ref=" commit)))
"--unpack" (concat "https://gitlab.com/api/v4/projects/"
(url-hexify-string repo)
"/repository/archive.tar.gz?ref="
commit)))
("bitbucket" (list "nix-prefetch-hg"
(concat "https://bitbucket.com/" repo) commit))
("hg" (list "nix-prefetch-hg"

View file

@ -242,12 +242,12 @@ in
clion = buildClion rec {
name = "clion-${version}";
version = "2021.1"; /* updated by script */
version = "2021.1.1"; /* updated by script */
description = "C/C++ IDE. New. Intelligent. Cross-platform";
license = lib.licenses.unfree;
src = fetchurl {
url = "https://download.jetbrains.com/cpp/CLion-${version}.tar.gz";
sha256 = "1qq2k14pf2qy93y1xchlv08vvx99zcml8bdcx3h6jnjz6d7gz0px"; /* updated by script */
sha256 = "0xzlkf3gq6fcb0q9mcj8k39880l8h21pb1lz0xl2dqj8cfwpws9h"; /* updated by script */
};
wmClass = "jetbrains-clion";
update-channel = "CLion RELEASE"; # channel's id as in http://www.jetbrains.com/updates/updates.xml
@ -255,12 +255,12 @@ in
datagrip = buildDataGrip rec {
name = "datagrip-${version}";
version = "2021.1"; /* updated by script */
version = "2021.1.1"; /* updated by script */
description = "Your Swiss Army Knife for Databases and SQL";
license = lib.licenses.unfree;
src = fetchurl {
url = "https://download.jetbrains.com/datagrip/${name}.tar.gz";
sha256 = "11am11lkrhgfianr1apkkl4mn8gcsf6p1vz47y7lz4rfm05ac4gj"; /* updated by script */
sha256 = "0smg0qbk3mnm2543w0nlvnyvbwmprf0p3z2spwrmcmfagv50crrx"; /* updated by script */
};
wmClass = "jetbrains-datagrip";
update-channel = "DataGrip RELEASE";
@ -268,12 +268,12 @@ in
goland = buildGoland rec {
name = "goland-${version}";
version = "2021.1"; /* updated by script */
version = "2021.1.1"; /* updated by script */
description = "Up and Coming Go IDE";
license = lib.licenses.unfree;
src = fetchurl {
url = "https://download.jetbrains.com/go/${name}.tar.gz";
sha256 = "1hxid7k5b26hiwwdxbvhi1fzhlrvm1xsd5gb0vj0g5zw658y2lzz"; /* updated by script */
sha256 = "02fyrq4px9w34amincgjgm6maxpxn445j5h4nfbskx7z428ynx25"; /* updated by script */
};
wmClass = "jetbrains-goland";
update-channel = "GoLand RELEASE";
@ -281,12 +281,12 @@ in
idea-community = buildIdea rec {
name = "idea-community-${version}";
version = "2021.1"; /* updated by script */
version = "2021.1.1"; /* updated by script */
description = "Integrated Development Environment (IDE) by Jetbrains, community edition";
license = lib.licenses.asl20;
src = fetchurl {
url = "https://download.jetbrains.com/idea/ideaIC-${version}.tar.gz";
sha256 = "1d7m39rzdgh2fyx50rpifqfsdmvfpi04hjp52pl76m35gyb5hsvs"; /* updated by script */
sha256 = "1say19p7kgx4b2ccs9bv61phllzhl8gmrd1fp1a5cnagya7vl1c5"; /* updated by script */
};
wmClass = "jetbrains-idea-ce";
update-channel = "IntelliJ IDEA RELEASE";
@ -294,12 +294,12 @@ in
idea-ultimate = buildIdea rec {
name = "idea-ultimate-${version}";
version = "2021.1"; /* updated by script */
version = "2021.1.1"; /* updated by script */
description = "Integrated Development Environment (IDE) by Jetbrains, requires paid license";
license = lib.licenses.unfree;
src = fetchurl {
url = "https://download.jetbrains.com/idea/ideaIU-${version}-no-jbr.tar.gz";
sha256 = "062kaph42xs5hc01sbmry4cm7nkyjks43qr5m7pbj5a2bgd7zzgx"; /* updated by script */
sha256 = "19zi4njz79z8gi458kz1m0sia79y3rhbayix4rmh93mwfc0npkii"; /* updated by script */
};
wmClass = "jetbrains-idea";
update-channel = "IntelliJ IDEA RELEASE";
@ -320,12 +320,12 @@ in
phpstorm = buildPhpStorm rec {
name = "phpstorm-${version}";
version = "2021.1"; /* updated by script */
version = "2021.1.2"; /* updated by script */
description = "Professional IDE for Web and PHP developers";
license = lib.licenses.unfree;
src = fetchurl {
url = "https://download.jetbrains.com/webide/PhpStorm-${version}.tar.gz";
sha256 = "052m7mqa1s548my0gda9y2mysi2ijq27c9b3bskrwqsf1pm5ry63"; /* updated by script */
sha256 = "02s75fqd9hfh302zha4jw6qynpgm9nkrlq7s78nk3fc3d3hw8v5y"; /* updated by script */
};
wmClass = "jetbrains-phpstorm";
update-channel = "PhpStorm RELEASE";
@ -333,12 +333,12 @@ in
pycharm-community = buildPycharm rec {
name = "pycharm-community-${version}";
version = "2021.1"; /* updated by script */
version = "2021.1.1"; /* updated by script */
description = "PyCharm Community Edition";
license = lib.licenses.asl20;
src = fetchurl {
url = "https://download.jetbrains.com/python/${name}.tar.gz";
sha256 = "1iiglh7s2zm37kj6hzlzxb1jnzh2p0j1f2zzhg3nqyrrakfbyq3h"; /* updated by script */
sha256 = "04bs9sz872b0h1zzax23irvj6q5wxnzp6fl4f177j94kh4116cqh"; /* updated by script */
};
wmClass = "jetbrains-pycharm-ce";
update-channel = "PyCharm RELEASE";
@ -346,12 +346,12 @@ in
pycharm-professional = buildPycharm rec {
name = "pycharm-professional-${version}";
version = "2021.1"; /* updated by script */
version = "2021.1.1"; /* updated by script */
description = "PyCharm Professional Edition";
license = lib.licenses.unfree;
src = fetchurl {
url = "https://download.jetbrains.com/python/${name}.tar.gz";
sha256 = "1n3b4mdygzal7w88gwka5wh5jp09bh2zmm4n5rz9s7hr2srz71mz"; /* updated by script */
sha256 = "0wc9j7nilakmm7scf7a71zb3k9vixgih05ni3n3pp4iznvwb3nxg"; /* updated by script */
};
wmClass = "jetbrains-pycharm";
update-channel = "PyCharm RELEASE";
@ -359,12 +359,12 @@ in
rider = buildRider rec {
name = "rider-${version}";
version = "2021.1.1"; /* updated by script */
version = "2021.1.2"; /* updated by script */
description = "A cross-platform .NET IDE based on the IntelliJ platform and ReSharper";
license = lib.licenses.unfree;
src = fetchurl {
url = "https://download.jetbrains.com/rider/JetBrains.Rider-${version}.tar.gz";
sha256 = "00kdbsjw9hmq7x94pjscslv0b412g8l0jbvyi7jiyay8xc6wiaaj"; /* updated by script */
sha256 = "1a28pi18j0cb2wxhw1vnfg9gqsgf2kyfg0hl4xgqp50gzv7i3aam"; /* updated by script */
};
wmClass = "jetbrains-rider";
update-channel = "Rider RELEASE";
@ -372,12 +372,12 @@ in
ruby-mine = buildRubyMine rec {
name = "ruby-mine-${version}";
version = "2021.1"; /* updated by script */
version = "2021.1.1"; /* updated by script */
description = "The Most Intelligent Ruby and Rails IDE";
license = lib.licenses.unfree;
src = fetchurl {
url = "https://download.jetbrains.com/ruby/RubyMine-${version}.tar.gz";
sha256 = "12mkb51x1w5wbx436pfnfzcad10qd53y43n0p4l2zg9yx985gm7v"; /* updated by script */
sha256 = "05sfjf5523idsl7byc7400r4xqv1d65gpmkh5x0lbgf1k3bx2wlm"; /* updated by script */
};
wmClass = "jetbrains-rubymine";
update-channel = "RubyMine RELEASE";
@ -385,12 +385,12 @@ in
webstorm = buildWebStorm rec {
name = "webstorm-${version}";
version = "2021.1"; /* updated by script */
version = "2021.1.1"; /* updated by script */
description = "Professional IDE for Web and JavaScript development";
license = lib.licenses.unfree;
src = fetchurl {
url = "https://download.jetbrains.com/webstorm/WebStorm-${version}.tar.gz";
sha256 = "15i521qj2b0y1viqr0xx815ckpq359j6nars4xxq8xvy7cg729yc"; /* updated by script */
sha256 = "1hici40qsxj2fw29g68i6hr1vhr0h7xrlhkialy74ah53wi7myz1"; /* updated by script */
};
wmClass = "jetbrains-webstorm";
update-channel = "WebStorm RELEASE";

View file

@ -6,7 +6,7 @@
# now defaults to false because some tests can be flaky (clipboard etc)
, doCheck ? false
, nodejs ? null, fish ? null, python ? null
, nodejs ? null, fish ? null, python3 ? null
}:
with lib;
@ -19,7 +19,7 @@ let
]
));
pyEnv = python.withPackages(ps: [ ps.pynvim ps.msgpack ]);
pyEnv = python3.withPackages(ps: with ps; [ pynvim msgpack ]);
# FIXME: this is verry messy and strange.
# see https://github.com/NixOS/nixpkgs/pull/80528

View file

@ -1,5 +1,5 @@
{ lib, mkDerivation, fetchFromGitHub, cmake, doxygen, makeWrapper
, msgpack, neovim, pythonPackages, qtbase }:
, msgpack, neovim, python3Packages, qtbase }:
mkDerivation rec {
pname = "neovim-qt-unwrapped";
@ -20,7 +20,7 @@ mkDerivation rec {
buildInputs = [
neovim.unwrapped # only used to generate help tags at build time
qtbase
] ++ (with pythonPackages; [
] ++ (with python3Packages; [
jinja2 python msgpack
]);

View file

@ -1,11 +1,14 @@
{ lib, fetchFromGitHub, pythonPackages }:
{ lib
, fetchFromGitHub
, python3
, neovim
}:
with lib;
pythonPackages.buildPythonApplication rec {
with python3.pkgs; buildPythonApplication rec {
pname = "neovim-remote";
version = "2.4.0";
disabled = !pythonPackages.isPy3k;
src = fetchFromGitHub {
owner = "mhinz";
@ -14,12 +17,24 @@ pythonPackages.buildPythonApplication rec {
sha256 = "0jlw0qksak4bdzddpsj74pm2f2bgpj3cwrlspdjjy0j9qzg0mpl9";
};
propagatedBuildInputs = with pythonPackages; [
propagatedBuildInputs = [
pynvim
psutil
setuptools
];
checkInputs = [
neovim
pytestCheckHook
];
disabledTests = [
# these tests get stuck and never return
"test_escape_filenames_properly"
"test_escape_single_quotes_in_filenames"
"test_escape_double_quotes_in_filenames"
];
meta = {
description = "A tool that helps controlling nvim processes from a terminal";
homepage = "https://github.com/mhinz/neovim-remote/";

View file

@ -1,5 +1,4 @@
{ lib, stdenv, mkDerivation, fetchFromGitHub, cmake, doxygen, makeWrapper
, msgpack, neovim, pythonPackages, qtbase, neovim-qt-unwrapped }:
{ stdenv, makeWrapper, neovim, neovim-qt-unwrapped }:
let
unwrapped = neovim-qt-unwrapped;

View file

@ -4,7 +4,6 @@
, neovim-unwrapped
, bundlerEnv
, ruby
, pythonPackages
, python3Packages
, writeText
, wrapNeovimUnstable
@ -48,12 +47,6 @@ let
requiredPlugins = vimUtils.requiredPlugins configure;
getDeps = attrname: map (plugin: plugin.${attrname} or (_: [ ]));
pluginPython2Packages = getDeps "pythonDependencies" requiredPlugins;
python2Env = pythonPackages.python.withPackages (ps:
[ ps.pynvim ]
++ (extraPython2Packages ps)
++ (lib.concatMap (f: f ps) pluginPython2Packages));
pluginPython3Packages = getDeps "python3Dependencies" requiredPlugins;
python3Env = python3Packages.python.withPackages (ps:
[ ps.pynvim ]
@ -69,7 +62,6 @@ let
# While the latter tells nvim that this provider is not available
hostprog_check_table = {
node = withNodeJs;
python = withPython2;
python3 = withPython3;
ruby = withRuby;
};
@ -99,11 +91,12 @@ let
manifestRc = vimUtils.vimrcContent (configure // { customRC = ""; });
neovimRcContent = vimUtils.vimrcContent configure;
in
assert withPython2 -> throw "Python2 support has been removed from neovim, please remove withPython2 and extraPython2Packages.";
args // {
wrapperArgs = makeWrapperArgs;
inherit neovimRcContent;
inherit manifestRc;
inherit python2Env;
inherit python3Env;
inherit withNodeJs;
} // lib.optionalAttrs withRuby {
@ -120,7 +113,7 @@ let
# to keep backwards compatibility
legacyWrapper = neovim: {
extraMakeWrapperArgs ? ""
, withPython ? true
, withPython ? false
/* the function you would have passed to python.withPackages */
, extraPythonPackages ? (_: [])
/* the function you would have passed to python.withPackages */
@ -138,14 +131,14 @@ let
else funOrList);
res = makeNeovimConfig {
withPython2 = withPython;
extraPythonPackages = compatFun extraPythonPackages;
inherit withPython3;
extraPython3Packages = compatFun extraPython3Packages;
inherit withNodeJs withRuby viAlias vimAlias;
inherit configure;
};
in
assert withPython -> throw "Python2 support has been removed from neovim, please remove withPython and extraPythonPackages.";
wrapNeovimUnstable neovim (res // {
wrapperArgs = lib.escapeShellArgs (
res.wrapperArgs ++ lib.optionals (configure != {}) [

View file

@ -3,7 +3,6 @@
, bundlerEnv, ruby
, nodejs
, nodePackages
, pythonPackages
, python3Packages
}:
with lib;
@ -15,7 +14,7 @@ let
# should contain all args but the binary
wrapperArgs ? ""
, manifestRc ? null
, withPython2 ? true, python2Env ? null
, withPython2 ? false
, withPython3 ? true, python3Env ? null
, withNodeJs ? false
, rubyEnv ? null
@ -35,6 +34,8 @@ let
[ "${neovim}/bin/nvim" "${placeholder "out"}/bin/nvim" ] ++
[ "--set" "NVIM_SYSTEM_RPLUGIN_MANIFEST" "${placeholder "out"}/rplugin.vim" ];
in
assert withPython2 -> throw "Python2 support has been removed from the neovim wrapper, please remove withPython2 and python2Env.";
symlinkJoin {
name = "neovim-${lib.getVersion neovim}";
# Remove the symlinks created by symlinkJoin which we need to perform
@ -44,9 +45,6 @@ let
substitute ${neovim}/share/applications/nvim.desktop $out/share/applications/nvim.desktop \
--replace 'Name=Neovim' 'Name=WrappedNeovim'
''
+ optionalString withPython2 ''
makeWrapper ${python2Env}/bin/python $out/bin/nvim-python --unset PYTHONPATH
''
+ optionalString withPython3 ''
makeWrapper ${python3Env}/bin/python3 $out/bin/nvim-python3 --unset PYTHONPATH
''

View file

@ -4,13 +4,13 @@ with python3.pkgs;
buildPythonApplication rec {
pname = "thonny";
version = "3.3.2";
version = "3.3.6";
src = fetchFromGitHub {
owner = pname;
repo = pname;
rev = "v${version}";
sha256 = "1pzy7v48x4ip8v6aqm8hl5ywx7xiqbsfypxxifih8gnlangp1n8y";
sha256 = "0ga0pqvq3nglr4jgh8ajv0bv8c7q09h1jh6q6r5cwqa49fawkr02";
};
propagatedBuildInputs = with python3.pkgs; [

View file

@ -1,7 +1,8 @@
{ stdenv, lib, makeDesktopItem
, unzip, libsecret, libXScrnSaver, libxshmfence, wrapGAppsHook
, gtk2, atomEnv, at-spi2-atk, autoPatchelfHook
, systemd, fontconfig, libdbusmenu
, systemd, fontconfig, libdbusmenu, buildFHSUserEnvBubblewrap
, writeShellScriptBin
# Populate passthru.tests
, tests
@ -13,13 +14,14 @@
let
inherit (stdenv.hostPlatform) system;
in
stdenv.mkDerivation {
unwrapped = stdenv.mkDerivation {
inherit pname version src sourceRoot;
passthru = {
inherit executableName tests;
fhs = fhs {};
fhsWithPackages = f: fhs { additionalPkgs = f; };
};
desktopItem = makeDesktopItem {
@ -97,4 +99,64 @@ in
'';
inherit meta;
}
};
# Vscode and variants allow for users to download and use extensions
# which often include the usage of pre-built binaries.
# This has been an on-going painpoint for many users, as
# a full extension update cycle has to be done through nixpkgs
# in order to create or update extensions.
# See: #83288 #91179 #73810 #41189
#
# buildFHSUserEnv allows for users to use the existing vscode
# extension tooling without significant pain.
fhs = { additionalPkgs ? pkgs: [] }: buildFHSUserEnvBubblewrap {
# also determines the name of the wrapped command
name = executableName;
# additional libraries which are commonly needed for extensions
targetPkgs = pkgs: (with pkgs; [
# ld-linux-x86-64-linux.so.2 and others
glibc
# dotnet
curl
icu
libunwind
libuuid
openssl
zlib
# mono
krb5
]) ++ additionalPkgs pkgs;
# restore desktop item icons
extraInstallCommands = ''
mkdir -p $out/share/applications
for item in ${unwrapped}/share/applications/*.desktop; do
ln -s $item $out/share/applications/
done
'';
runScript = "${unwrapped}/bin/${executableName}";
# vscode likes to kill the parent so that the
# gui application isn't attached to the terminal session
dieWithParent = false;
passthru = {
inherit executableName;
inherit (unwrapped) pname version; # for home-manager module
};
meta = meta // {
description = ''
Wrapped variant of ${pname} which launches in a FHS compatible envrionment.
Should allow for easy usage of extensions without nix-specific modifications.
'';
};
};
in
unwrapped

View file

@ -18,13 +18,13 @@ mkDerivation rec {
cmakeFlags = [
"-DROUTINO_XML_PATH=${routino}/share/routino"
"-DQUAZIP_INCLUDE_DIR=${quazip}/include/quazip5"
"-DLIBQUAZIP_LIBRARY=${quazip}/lib/libquazip.so"
];
patches = [
"${src}/FindPROJ4.patch"
"${src}/FindQuaZip5.patch"
# Support QuaZip 1.x.
./pr350-support-quazip-1x.patch
];
qtWrapperArgs = [

View file

@ -0,0 +1,141 @@
From 8fb751c656a14020ba37fb91b7f7cba3c49d8504 Mon Sep 17 00:00:00 2001
From: kiozen <oliver.eichler@gmx.de>
Date: Sat, 20 Mar 2021 12:14:29 +0100
Subject: [PATCH] [QMS-349] Upgrade to Quazip Qt5 V1.x
Simply adjusted the cmake scripts
---
CMakeLists.txt | 2 +-
src/qmapshack/CMakeLists.txt | 27 +++++++++++++--------------
3 files changed, 15 insertions(+), 15 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8d2cf127..7420d9b2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -152,7 +152,7 @@ find_package(GDAL REQUIRED)
find_package(PROJ REQUIRED)
find_package(JPEG REQUIRED)
find_package(ROUTINO REQUIRED)
-find_package(QuaZip5 REQUIRED)
+find_package(QuaZip-Qt5 REQUIRED)
find_package(ALGLIB ) # optional as we can use our local version
diff --git a/src/qmapshack/CMakeLists.txt b/src/qmapshack/CMakeLists.txt
index 08eeb183..9b3836d6 100644
--- a/src/qmapshack/CMakeLists.txt
+++ b/src/qmapshack/CMakeLists.txt
@@ -22,8 +22,8 @@ add_definitions(-DROUTINO_XML_PATH=${ROUTINO_XML_PATH})
# All source files needed to compile
###############################################################################################
-set( SRCS
- CAbout.cpp
+set( SRCS
+ CAbout.cpp
CMainWindow.cpp
CSingleInstanceProxy.cpp
canvas/CCanvas.cpp
@@ -160,7 +160,7 @@ set( SRCS
gis/trk/CInvalidTrk.cpp
gis/trk/CKnownExtension.cpp
gis/trk/CListTrkPts.cpp
- gis/trk/CPropertyTrk.cpp
+ gis/trk/CPropertyTrk.cpp
gis/trk/CScrOptTrk.cpp
gis/trk/CSelectActivityColor.cpp
gis/trk/CTableTrk.cpp
@@ -272,7 +272,7 @@ set( SRCS
mouse/line/CLineOpMovePoint.cpp
mouse/line/CLineOpSelectRange.cpp
mouse/line/CScrOptEditLine.cpp
- mouse/line/CScrOptRangeLine.cpp
+ mouse/line/CScrOptRangeLine.cpp
mouse/line/ILineOp.cpp
mouse/line/IMouseEditLine.cpp
plot/CPlot.cpp
@@ -401,7 +401,7 @@ set( HDRS
gis/CGisListDB.h
gis/CGisListWks.h
gis/CGisWorkspace.h
- gis/CSelDevices.h
+ gis/CSelDevices.h
gis/IGisItem.h
gis/IGisLine.h
gis/Poi.h
@@ -512,7 +512,7 @@ set( HDRS
gis/trk/CInvalidTrk.h
gis/trk/CKnownExtension.h
gis/trk/CListTrkPts.h
- gis/trk/CPropertyTrk.h
+ gis/trk/CPropertyTrk.h
gis/trk/CScrOptTrk.h
gis/trk/CSelectActivityColor.h
gis/trk/CTableTrk.h
@@ -579,7 +579,7 @@ set( HDRS
map/CMapList.h
map/CMapMAP.h
map/CMapPathSetup.h
- map/CMapPropSetup.h
+ map/CMapPropSetup.h
map/CMapRMAP.h
map/CMapTMS.h
map/CMapVRT.h
@@ -655,7 +655,7 @@ set( HDRS
realtime/CRtSelectSource.h
realtime/CRtWorkspace.h
realtime/IRtInfo.h
- realtime/IRtRecord.h
+ realtime/IRtRecord.h
realtime/IRtSource.h
realtime/gpstether/CRtGpsTether.h
realtime/gpstether/CRtGpsTetherInfo.h
@@ -764,7 +764,7 @@ set( UIS
gis/search/IGeoSearchWebConfigDialog.ui
gis/search/ISearchExplanationDialog.ui
gis/summary/IGisSummary.ui
- gis/summary/IGisSummarySetup.ui
+ gis/summary/IGisSummarySetup.ui
gis/trk/ICombineTrk.ui
gis/trk/ICutTrk.ui
gis/trk/IDetailsTrk.ui
@@ -818,7 +818,7 @@ set( UIS
mouse/range/IActionSelect.ui
mouse/range/IRangeToolSetup.ui
mouse/range/IScrOptRangeTool.ui
- mouse/range/IScrOptRangeTrk.ui
+ mouse/range/IScrOptRangeTrk.ui
mouse/IScrOptRuler.ui
mouse/IScrOptSelect.ui
mouse/line/IScrOptEditLine.ui
@@ -899,7 +899,6 @@ include_directories(
${PROJ_INCLUDE_DIRS}
${ROUTINO_INCLUDE_DIRS}
${ALGLIB_INCLUDE_DIRS}
- ${QUAZIP_INCLUDE_DIRS}
)
if(APPLE)
@@ -934,10 +933,10 @@ endif(Qt5DBus_FOUND)
target_link_libraries(${APPLICATION_NAME}
Qt5::Widgets
- Qt5::Xml
+ Qt5::Xml
Qt5::Sql
Qt5::PrintSupport
- Qt5::UiTools
+ Qt5::UiTools
Qt5::Network
Qt5::WebEngineWidgets
Qt5::Qml
@@ -947,7 +946,7 @@ target_link_libraries(${APPLICATION_NAME}
${PROJ_LIBRARIES}
${ROUTINO_LIBRARIES}
${ALGLIB_LIBRARIES}
- ${QUAZIP_LIBRARIES}
+ QuaZip::QuaZip
)
if(APPLE)

View file

@ -25,14 +25,14 @@
stdenv.mkDerivation rec {
pname = "foxotron";
version = "2021-03-12";
version = "2021-04-19";
src = fetchFromGitHub {
owner = "Gargaj";
repo = "Foxotron";
rev = version;
fetchSubmodules = true;
sha256 = "1finvbs3pbfyvm525blwgwl5jci2zjxb1923i0cm8rmf7wasaapb";
sha256 = "sha256-YTCnWHXBNqvJmhRqRQRFCVvBcqbjKzcc3AKVXS0jvno=";
};
nativeBuildInputs = [ cmake pkg-config makeWrapper ];
@ -67,7 +67,7 @@ stdenv.mkDerivation rec {
Revision 2021 3D Graphics Competition.
'';
homepage = "https://github.com/Gargaj/Foxotron";
license = licenses.publicDomain;
license = licenses.unlicense;
maintainers = with maintainers; [ OPNA2608 ];
platforms = platforms.all;
};

View file

@ -27,6 +27,15 @@ mkDerivation rec {
sha256 = "1bq7bv4p7w67172y893lvpk90d6fgdpnylynbj2kn8m2hs6khya4";
};
patches = [
# Add support for Quazip 1.x.
(fetchpatch {
url = "https://github.com/nomacs/nomacs/pull/576.patch";
sha256 = "11ryjvd9jbb0cqagai4a6980jfq8lrcbyw2d7z9yld1f42w9kbxm";
stripLen = 1;
})
];
setSourceRoot = ''
sourceRoot=$(echo */ImageLounge)
'';

View file

@ -34,7 +34,8 @@ in mkDerivation rec {
postPatch = ''
substituteInPlace OpenBoard.pro \
--replace '/usr/include/quazip' '${quazip}/include/quazip5' \
--replace '/usr/include/quazip' '${quazip}/include/QuaZip-Qt5-${quazip.version}/quazip' \
--replace '-lquazip5' '-lquazip1-qt5' \
--replace '/usr/include/poppler' '${poppler.dev}/include/poppler'
'';

View file

@ -0,0 +1,99 @@
{ lib
, stdenv
, fetchFromGitLab
, fetchpatch
, appstream-glib
, desktop-file-utils
, meson
, ninja
, pkg-config
, python3
, rustPlatform
, wrapGAppsHook
, gdk-pixbuf
, glib
, gst_all_1
, gtk4
, libadwaita
, openssl
, sqlite
, wayland
, zbar
}:
stdenv.mkDerivation rec {
pname = "authenticator";
version = "4.0.3";
src = fetchFromGitLab {
domain = "gitlab.gnome.org";
owner = "World";
repo = "Authenticator";
rev = version;
sha256 = "0fvs76f3fm5pxn7wg6sjbqpgip5w2j7xrh4siasdcl2bx6vsld8b";
};
cargoDeps = rustPlatform.fetchCargoTarball {
inherit src;
name = "${pname}-${version}";
sha256 = "1s97jyszxf24rs3ni11phiyvmp1wm8sicb0rh1jgwz4bn1cnakx4";
};
postPatch = ''
patchShebangs build-aux
'';
nativeBuildInputs = [
appstream-glib
desktop-file-utils
meson
ninja
pkg-config
python3
wrapGAppsHook
] ++ (with rustPlatform; [
cargoSetupHook
rust.cargo
rust.rustc
]);
buildInputs = [
gdk-pixbuf
glib
gst_all_1.gstreamer
gst_all_1.gst-plugins-base
# gst-plugins-good needs gtk4 support:
# https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/767
# We copy the way it is built from the Flatpak:
# https://gitlab.gnome.org/World/Authenticator/-/blob/master/build-aux/com.belmoussaoui.Authenticator.Devel.json
(gst_all_1.gst-plugins-good.overrideAttrs (old: {
patches = old.patches or [ ] ++ [
"${src}/build-aux/767.patch"
];
mesonFlags = old.mesonFlags ++ [
"-Dgtk3=disabled"
"-Dgtk4=enabled"
"-Dgtk4-experiments=true"
];
buildInputs = old.buildInputs ++ [
gtk4
];
}))
(gst_all_1.gst-plugins-bad.override { enableZbar = true; })
gtk4
libadwaita
openssl
sqlite
wayland
zbar
];
meta = with lib; {
description = "Two-factor authentication code generator for GNOME";
homepage = "https://gitlab.gnome.org/World/Authenticator";
license = licenses.gpl3Plus;
maintainers = with maintainers; [ dotlambda ];
};
}

View file

@ -2,7 +2,6 @@
, stdenv
, copyDesktopItems
, fetchFromGitHub
, fetchpatch
, makeDesktopItem
, makeWrapper
, fontconfig
@ -19,18 +18,18 @@
stdenv.mkDerivation rec {
pname = "dbeaver-ce";
version = "21.0.3"; # When updating also update fetchedMavenDeps.sha256
version = "21.0.4"; # When updating also update fetchedMavenDeps.sha256
src = fetchFromGitHub {
owner = "dbeaver";
repo = "dbeaver";
rev = version;
sha256 = "sha256-ItM8t+gqE0ccuuimfEMUddykl+xt2eZIBd3MbpreRwA=";
sha256 = "sha256-jV7Pe4MsLQnIrkDnlI2SrPzSjiDHM59GbMy4G7oeQK8=";
};
fetchedMavenDeps = stdenv.mkDerivation {
name = "dbeaver-${version}-maven-deps";
inherit src patches;
inherit src;
buildInputs = [
maven
@ -51,18 +50,9 @@ stdenv.mkDerivation rec {
dontFixup = true;
outputHashAlgo = "sha256";
outputHashMode = "recursive";
outputHash = "sha256-rsK/B39ogNu5nC41OfyAsLiwBz4gWyH+8Fj7E6+rOng=";
outputHash = "sha256-RspJTWVM0ZpAz4yDeKsG7wSHZ//bi3SSV5c0gbsqZKY=";
};
patches = [
# Fix eclipse-color-theme URL (https://github.com/dbeaver/dbeaver/pull/12133)
# After April 15, 2021 eclipse-color-theme.github.com no longer redirects to eclipse-color-theme.github.io
(fetchpatch {
url = "https://github.com/dbeaver/dbeaver/commit/65d65e2c2c711cc87fddcec425a6915aa80f4ced.patch";
sha256 = "sha256-pxOcRYkV/5o+tHcRhHDZ1TmZSHMnKBmkNTVAlIf9nUE=";
})
];
nativeBuildInputs = [
copyDesktopItems
makeWrapper

View file

@ -1,5 +1,5 @@
{ lib, stdenv, fetchurl, perl, libX11, libXinerama, libjpeg, libpng, libtiff, pkg-config,
librsvg, glib, gtk2, libXext, libXxf86vm, poppler, xineLib, ghostscript, makeWrapper }:
librsvg, glib, gtk2, libXext, libXxf86vm, poppler, xine-lib, ghostscript, makeWrapper }:
stdenv.mkDerivation rec {
pname = "eaglemode";
@ -12,11 +12,11 @@ stdenv.mkDerivation rec {
nativeBuildInputs = [ pkg-config ];
buildInputs = [ perl libX11 libXinerama libjpeg libpng libtiff
librsvg glib gtk2 libXxf86vm libXext poppler xineLib ghostscript makeWrapper ];
librsvg glib gtk2 libXxf86vm libXext poppler xine-lib ghostscript makeWrapper ];
# The program tries to dlopen Xxf86vm, Xext and Xinerama, so we use the
# trick on NIX_LDFLAGS and dontPatchELF to make it find them.
# I use 'yes y' to skip a build error linking with xineLib,
# I use 'yes y' to skip a build error linking with xine-lib,
# because xine stopped exporting "_x_vo_new_port"
# https://sourceforge.net/projects/eaglemode/forums/forum/808824/topic/5115261
buildPhase = ''

View file

@ -41,6 +41,11 @@ stdenv.mkDerivation rec {
json-glib
];
postInstall = ''
mkdir -p $out/lib/udev/rules.d
sed "s|/usr/libexec/|$out/libexec/|" < $src/debian/feedbackd.udev > $out/lib/udev/rules.d/90-feedbackd.rules
'';
meta = with lib; {
description = "A daemon to provide haptic (and later more) feedback on events";
homepage = "https://source.puri.sm/Librem5/feedbackd";

View file

@ -2,16 +2,16 @@
buildGoModule rec {
pname = "geoipupdate";
version = "4.6.0";
version = "4.7.1";
src = fetchFromGitHub {
owner = "maxmind";
repo = "geoipupdate";
rev = "v${version}";
sha256 = "1rzc8kidm8nr9pbcbq96kax3cbf39afrk5vzpl04lzpw3jbbakjq";
sha256 = "sha256-nshQxr6y3TxKsAVSA9mzL7LJfCtpv0QuuTTqk3/lENc=";
};
vendorSha256 = "1f858k8cl0dgiw124jv0p9jhi9aqxnc3nmc7hksw70fla2nzjrv0";
vendorSha256 = "sha256-fqQWFhFeyW4GntRBxEeN6WSOo0G+1hH9vSEZmBKglz8=";
doCheck = false;

View file

@ -1,41 +1,54 @@
{ lib, stdenv, fetchurl, glibc, libGLU, libGL, freetype, glib, libSM, libICE, libXi, libXv
, libXrender, libXrandr, libXfixes, libXcursor, libXinerama, libXext, libX11, libXcomposite
, libxcb, sqlite, zlib, fontconfig, dpkg, libproxy, libxml2, gst_all_1, dbus, makeWrapper }:
{ lib
, stdenv
, mkDerivation
, fetchurl
, ffmpeg_3
, freetype
, gdal_2
, glib
, libGL
, libGLU
, libICE
, libSM
, libXi
, libXv
, libav_12
, libXrender
, libXrandr
, libXfixes
, libXcursor
, libXinerama
, libXext
, libX11
, libXcomposite
, libxcb
, sqlite
, zlib
, fontconfig
, dpkg
, libproxy
, libxml2
, gst_all_1
, dbus
, makeWrapper
, qtlocation
, qtwebkit
, qtx11extras
, qtsensors
, qtscript
, xkeyboardconfig
, autoPatchelfHook
}:
let
arch =
if stdenv.hostPlatform.system == "x86_64-linux" then "amd64"
else throw "Unsupported system ${stdenv.hostPlatform.system} ";
fullPath = lib.makeLibraryPath [
glibc
glib
stdenv.cc.cc
libSM
libICE
libXi
libXv
libGLU libGL
libXrender
libXrandr
libXfixes
libXcursor
libXinerama
libXcomposite
freetype
libXext
libX11
libxcb
sqlite
zlib
fontconfig
libproxy
libxml2
dbus
gst_all_1.gstreamer
gst_all_1.gst-plugins-base
];
in
stdenv.mkDerivation rec {
mkDerivation rec {
pname = "googleearth-pro";
version = "7.3.3.7786";
@ -44,20 +57,56 @@ stdenv.mkDerivation rec {
sha256 = "1s3cakwrgf702g33rh8qs657d8bl68wgg8k89rksgvswwpd2zbb3";
};
nativeBuildInputs = [ dpkg makeWrapper ];
nativeBuildInputs = [ dpkg makeWrapper autoPatchelfHook ];
propagatedBuildInputs = [ xkeyboardconfig ];
buildInputs = [
dbus
ffmpeg_3
fontconfig
freetype
gdal_2
glib
gst_all_1.gst-plugins-base
gst_all_1.gstreamer
libGL
libGLU
libICE
libSM
libX11
libXcomposite
libXcursor
libXext
libXfixes
libXi
libXinerama
libXrandr
libXrender
libXv
libav_12
libproxy
libxcb
libxml2
qtlocation
qtscript
qtsensors
qtwebkit
qtx11extras
sqlite
zlib
];
doInstallCheck = true;
dontBuild = true;
dontPatchELF = true;
unpackPhase = ''
# deb file contains a setuid binary, so 'dpkg -x' doesn't work here
dpkg --fsys-tarfile ${src} | tar --extract
'';
installPhase =''
runHook preInstall
mkdir $out
mv usr/* $out/
rmdir usr
@ -66,20 +115,9 @@ stdenv.mkDerivation rec {
# patch and link googleearth binary
ln -s $out/opt/google/earth/pro/googleearth-bin $out/bin/googleearth-pro
patchelf --interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
--set-rpath "${fullPath}:\$ORIGIN" \
$out/opt/google/earth/pro/googleearth-bin
# patch and link gpsbabel binary
ln -s $out/opt/google/earth/pro/gpsbabel $out/bin/gpsbabel
patchelf --interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" \
--set-rpath "${fullPath}:\$ORIGIN" \
$out/opt/google/earth/pro/gpsbabel
# patch libraries
for a in $out/opt/google/earth/pro/*.so* ; do
patchelf --set-rpath "${fullPath}:\$ORIGIN" $a
done
# Add desktop config file and icons
mkdir -p $out/share/{applications,icons/hicolor/{16x16,22x22,24x24,32x32,48x48,64x64,128x128,256x256}/apps,pixmaps}
@ -89,23 +127,37 @@ stdenv.mkDerivation rec {
ln -s $out/opt/google/earth/pro/product_logo_"$size".png $out/share/icons/hicolor/"$size"x"$size"/apps/google-earth-pro.png
done
ln -s $out/opt/google/earth/pro/product_logo_256.png $out/share/pixmaps/google-earth-pro.png
runHook postInstall
'';
postInstall = ''
find "$out/opt/google/earth/pro" -name "*.so.*" | \
egrep -v 'libssl*|libcrypto*|libicu*' | \
xargs rm
find "$out/opt/google/earth/pro" -name "*.so" | \
egrep -v 'libgoogle*|libauth*|libbase*|libcommon*|libcommon_gui*|libcommon_platform*|libcommon_webbrowser*|libcomponentframework*|libgeobase*|libgeobaseutils*|libge_net*|libgdata*|libgoogleapi*|libmath*|libmoduleframework*|libmaps*|libport*|libprintmodule*|libprofile*|librender*|libreporting*|libsgutil*|libspatial*|libxsltransform*|libbase*|libport*|libport*|libbase*|libcomponentframework*|libIGCore*|libIGUtils*|libaction*|libapiloader*|libapiloader*|libIGCore*|libIGUtils*|libIGMath*|libfusioncommon*|libge_exif*|libaction*|libfusioncommon*|libapiloader*|liblayer*|libapiloader*|libIGAttrs*|libIGCore*|libIGGfx*|libIGMath*|libIGSg*|libIGUtils*|libwmsbase*|libwebbrowser*|libevllpro*|libalchemyext*|libge_cache*|libflightsim*|libnpgeinprocessplugin*|libmeasure*|libviewsync*|libcapture*|libtheme*|libgps*|libgisingest*|libsearchmodule*|libinput_plugin*|libnavigate*|libspnav*|libsearch*|libLeap*' | \
xargs rm
'';
autoPatchelfIgnoreMissingDeps=true;
installCheckPhase = ''
$out/bin/gpsbabel -V > /dev/null
'';
# wayland is not supported by Qt included in binary package, so make sure it uses xcb
fixupPhase = ''
wrapProgram $out/bin/googleearth-pro --set QT_QPA_PLATFORM xcb
postFixup = ''
wrapProgram $out/bin/googleearth-pro \
--set QT_QPA_PLATFORM xcb \
--set QT_XKB_CONFIG_ROOT "${xkeyboardconfig}/share/X11/xkb"
'';
meta = with lib; {
description = "A world sphere viewer";
homepage = "https://earth.google.com";
homepage = "https://www.google.com/earth/";
license = licenses.unfree;
maintainers = with maintainers; [ friedelino ];
maintainers = with maintainers; [ friedelino shamilton ];
platforms = platforms.linux;
};
}

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