summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nixos/modules/services/mail/dovecot.nix2
-rw-r--r--nixos/modules/services/mail/rspamd.nix261
-rw-r--r--nixos/release.nix1
-rw-r--r--nixos/tests/rspamd.nix140
-rw-r--r--pkgs/applications/editors/typora/default.nix6
-rw-r--r--pkgs/applications/graphics/darktable/default.nix34
-rw-r--r--pkgs/applications/networking/instant-messengers/gajim/default.nix15
-rw-r--r--pkgs/applications/networking/instant-messengers/gajim/fix-tests.patch13
-rw-r--r--pkgs/applications/virtualization/docker/default.nix16
-rw-r--r--pkgs/development/libraries/libproxy/default.nix12
-rw-r--r--pkgs/development/python-modules/awesome-slugify/default.nix6
-rw-r--r--pkgs/development/python-modules/pythonnet/default.nix84
-rw-r--r--pkgs/development/tools/hcloud/default.nix24
-rw-r--r--pkgs/development/tools/selenium/chromedriver/default.nix11
-rw-r--r--pkgs/tools/misc/youtube-dl/default.nix4
-rw-r--r--pkgs/tools/typesetting/asciidoctor/default.nix16
-rw-r--r--pkgs/top-level/all-packages.nix13
-rw-r--r--pkgs/top-level/python-packages.nix5
18 files changed, 545 insertions, 118 deletions
diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix
index c5cb06cf54e2..b42c73b86668 100644
--- a/nixos/modules/services/mail/dovecot.nix
+++ b/nixos/modules/services/mail/dovecot.nix
@@ -113,7 +113,7 @@ let
   mailboxes = { lib, pkgs, ... }: {
     options = {
       name = mkOption {
-        type = types.str;
+        type = types.strMatching ''[^"]+'';
         example = "Spam";
         description = "The name of the mailbox.";
       };
diff --git a/nixos/modules/services/mail/rspamd.nix b/nixos/modules/services/mail/rspamd.nix
index b80aa48f2c86..09fb587e74b5 100644
--- a/nixos/modules/services/mail/rspamd.nix
+++ b/nixos/modules/services/mail/rspamd.nix
@@ -1,14 +1,152 @@
-{ config, lib, pkgs, ... }:
+{ config, options, pkgs, lib, ... }:
 
 with lib;
 
 let
 
   cfg = config.services.rspamd;
+  opts = options.services.rspamd;
 
-  mkBindSockets = socks: concatStringsSep "\n" (map (each: "  bind_socket = \"${each}\"") socks);
+  bindSocketOpts = {options, config, ... }: {
+    options = {
+      socket = mkOption {
+        type = types.str;
+        example = "localhost:11333";
+        description = ''
+          Socket for this worker to listen on in a format acceptable by rspamd.
+        '';
+      };
+      mode = mkOption {
+        type = types.str;
+        default = "0644";
+        description = "Mode to set on unix socket";
+      };
+      owner = mkOption {
+        type = types.str;
+        default = "${cfg.user}";
+        description = "Owner to set on unix socket";
+      };
+      group = mkOption {
+        type = types.str;
+        default = "${cfg.group}";
+        description = "Group to set on unix socket";
+      };
+      rawEntry = mkOption {
+        type = types.str;
+        internal = true;
+      };
+    };
+    config.rawEntry = let
+      maybeOption = option:
+        optionalString options.${option}.isDefined " ${option}=${config.${option}}";
+    in
+      if (!(hasPrefix "/" config.socket)) then "${config.socket}"
+      else "${config.socket}${maybeOption "mode"}${maybeOption "owner"}${maybeOption "group"}";
+  };
 
-   rspamdConfFile = pkgs.writeText "rspamd.conf"
+  workerOpts = { name, ... }: {
+    options = {
+      enable = mkOption {
+        type = types.nullOr types.bool;
+        default = null;
+        description = "Whether to run the rspamd worker.";
+      };
+      name = mkOption {
+        type = types.nullOr types.str;
+        default = name;
+        description = "Name of the worker";
+      };
+      type = mkOption {
+        type = types.nullOr (types.enum [
+          "normal" "controller" "fuzzy_storage" "proxy" "lua"
+        ]);
+        description = "The type of this worker";
+      };
+      bindSockets = mkOption {
+        type = types.listOf (types.either types.str (types.submodule bindSocketOpts));
+        default = [];
+        description = ''
+          List of sockets to listen, in format acceptable by rspamd
+        '';
+        example = [{
+          socket = "/run/rspamd.sock";
+          mode = "0666";
+          owner = "rspamd";
+        } "*:11333"];
+        apply = value: map (each: if (isString each)
+          then if (isUnixSocket each)
+            then {socket = each; owner = cfg.user; group = cfg.group; mode = "0644"; rawEntry = "${each}";}
+            else {socket = each; rawEntry = "${each}";}
+          else each) value;
+      };
+      count = mkOption {
+        type = types.nullOr types.int;
+        default = null;
+        description = ''
+          Number of worker instances to run
+        '';
+      };
+      includes = mkOption {
+        type = types.listOf types.str;
+        default = [];
+        description = ''
+          List of files to include in configuration
+        '';
+      };
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = "Additional entries to put verbatim into worker section of rspamd config file.";
+      };
+    };
+    config = mkIf (name == "normal" || name == "controller" || name == "fuzzy") {
+      type = mkDefault name;
+      includes = mkDefault [ "$CONFDIR/worker-${name}.inc" ];
+      bindSockets = mkDefault (if name == "normal"
+        then [{
+              socket = "/run/rspamd/rspamd.sock";
+              mode = "0660";
+              owner = cfg.user;
+              group = cfg.group;
+            }]
+        else if name == "controller"
+        then [ "localhost:11334" ]
+        else [] );
+    };
+  };
+
+  indexOf = default: start: list: e:
+    if list == []
+    then default
+    else if (head list) == e then start
+    else (indexOf default (start + (length (listenStreams (head list).socket))) (tail list) e);
+
+  systemdSocket = indexOf (abort "Socket not found") 0 allSockets;
+
+  isUnixSocket = socket: hasPrefix "/" (if (isString socket) then socket else socket.socket);
+  isPort = hasPrefix "*:";
+  isIPv4Socket = hasPrefix "*v4:";
+  isIPv6Socket = hasPrefix "*v6:";
+  isLocalHost = hasPrefix "localhost:";
+  listenStreams = socket:
+    if (isLocalHost socket) then
+      let port = (removePrefix "localhost:" socket);
+      in [ "127.0.0.1:${port}" ] ++ (if config.networking.enableIPv6 then ["[::1]:${port}"] else [])
+    else if (isIPv6Socket socket) then [removePrefix "*v6:" socket]
+    else if (isPort socket) then [removePrefix "*:" socket]
+    else if (isIPv4Socket socket) then
+      throw "error: IPv4 only socket not supported in rspamd with socket activation"
+    else if (length (splitString " " socket)) != 1 then
+      throw "error: string options not supported in rspamd with socket activation"
+    else [socket];
+
+  mkBindSockets = enabled: socks: concatStringsSep "\n  " (flatten (map (each:
+    if cfg.socketActivation && enabled != false then
+      let systemd = (systemdSocket each);
+      in (imap (idx: e: "bind_socket = \"systemd:${toString (systemd + idx - 1)}\";") (listenStreams each.socket))
+    else "bind_socket = \"${each.rawEntry}\";") socks));
+
+  rspamdConfFile = pkgs.writeText "rspamd.conf"
     ''
       .include "$CONFDIR/common.conf"
 
@@ -22,19 +160,33 @@ let
         .include "$CONFDIR/logging.inc"
       }
 
-      worker {
-      ${mkBindSockets cfg.bindSocket}
-        .include "$CONFDIR/worker-normal.inc"
-      }
-
-      worker {
-      ${mkBindSockets cfg.bindUISocket}
-        .include "$CONFDIR/worker-controller.inc"
-      }
+      ${concatStringsSep "\n" (mapAttrsToList (name: value: ''
+        worker ${optionalString (value.name != "normal" && value.name != "controller") "${value.name}"} {
+          type = "${value.type}";
+          ${optionalString (value.enable != null)
+            "enabled = ${if value.enable != false then "yes" else "no"};"}
+          ${mkBindSockets value.enable value.bindSockets}
+          ${optionalString (value.count != null) "count = ${toString value.count};"}
+          ${concatStringsSep "\n  " (map (each: ".include \"${each}\"") value.includes)}
+          ${value.extraConfig}
+        }
+      '') cfg.workers)}
 
       ${cfg.extraConfig}
    '';
 
+  allMappedSockets = flatten (mapAttrsToList (name: value:
+    if value.enable != false
+    then imap (idx: each: {
+        name = "${name}";
+        index = idx;
+        value = each;
+      }) value.bindSockets
+    else []) cfg.workers);
+  allSockets = map (e: e.value) allMappedSockets;
+
+  allSocketNames = map (each: "rspamd-${each.name}-${toString each.index}.socket") allMappedSockets;
+
 in
 
 {
@@ -48,36 +200,43 @@ in
       enable = mkEnableOption "Whether to run the rspamd daemon.";
 
       debug = mkOption {
+        type = types.bool;
         default = false;
         description = "Whether to run the rspamd daemon in debug mode.";
       };
 
-      bindSocket = mkOption {
-        type = types.listOf types.str;
-        default = [
-          "/run/rspamd/rspamd.sock mode=0660 owner=${cfg.user} group=${cfg.group}"
-        ];
-        defaultText = ''[
-          "/run/rspamd/rspamd.sock mode=0660 owner=${cfg.user} group=${cfg.group}"
-        ]'';
+      socketActivation = mkOption {
+        type = types.bool;
         description = ''
-          List of sockets to listen, in format acceptable by rspamd
-        '';
-        example = ''
-          bindSocket = [
-            "/run/rspamd.sock mode=0666 owner=rspamd"
-            "*:11333"
-          ];
+          Enable systemd socket activation for rspamd.
         '';
       };
 
-      bindUISocket = mkOption {
-        type = types.listOf types.str;
-        default = [
-          "localhost:11334"
-        ];
+      workers = mkOption {
+        type = with types; attrsOf (submodule workerOpts);
         description = ''
-          List of sockets for web interface, in format acceptable by rspamd
+          Attribute set of workers to start.
+        '';
+        default = {
+          normal = {};
+          controller = {};
+        };
+        example = literalExample ''
+          {
+            normal = {
+              includes = [ "$CONFDIR/worker-normal.inc" ];
+              bindSockets = [{
+                socket = "/run/rspamd/rspamd.sock";
+                mode = "0660";
+                owner = "${cfg.user}";
+                group = "${cfg.group}";
+              }];
+            };
+            controller = {
+              includes = [ "$CONFDIR/worker-controller.inc" ];
+              bindSockets = [ "[::1]:11334" ];
+            };
+          }
         '';
       };
 
@@ -113,6 +272,13 @@ in
 
   config = mkIf cfg.enable {
 
+    services.rspamd.socketActivation = mkDefault (!opts.bindSocket.isDefined && !opts.bindUISocket.isDefined);
+
+    assertions = [ {
+      assertion = !cfg.socketActivation || !(opts.bindSocket.isDefined || opts.bindUISocket.isDefined);
+      message = "Can't use socketActivation for rspamd when using renamed bind socket options";
+    } ];
+
     # Allow users to run 'rspamc' and 'rspamadm'.
     environment.systemPackages = [ pkgs.rspamd ];
 
@@ -128,17 +294,22 @@ in
       gid = config.ids.gids.rspamd;
     };
 
+    environment.etc."rspamd.conf".source = rspamdConfFile;
+
     systemd.services.rspamd = {
       description = "Rspamd Service";
 
-      wantedBy = [ "multi-user.target" ];
-      after = [ "network.target" ];
+      wantedBy = mkIf (!cfg.socketActivation) [ "multi-user.target" ];
+      after = [ "network.target" ] ++
+       (if cfg.socketActivation then allSocketNames else []);
+      requires = mkIf cfg.socketActivation allSocketNames;
 
       serviceConfig = {
         ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -c ${rspamdConfFile} -f";
         Restart = "always";
         RuntimeDirectory = "rspamd";
         PrivateTmp = true;
+        Sockets = mkIf cfg.socketActivation (concatStringsSep " " allSocketNames);
       };
 
       preStart = ''
@@ -146,5 +317,25 @@ in
         ${pkgs.coreutils}/bin/chown ${cfg.user}:${cfg.group} /var/lib/rspamd
       '';
     };
+    systemd.sockets = mkIf cfg.socketActivation
+      (listToAttrs (map (each: {
+        name = "rspamd-${each.name}-${toString each.index}";
+        value = {
+          description = "Rspamd socket ${toString each.index} for worker ${each.name}";
+          wantedBy = [ "sockets.target" ];
+          listenStreams = (listenStreams each.value.socket);
+          socketConfig = {
+            BindIPv6Only = mkIf (isIPv6Socket each.value.socket) "ipv6-only";
+            Service = "rspamd.service";
+            SocketUser = mkIf (isUnixSocket each.value.socket) each.value.owner;
+            SocketGroup = mkIf (isUnixSocket each.value.socket) each.value.group;
+            SocketMode = mkIf (isUnixSocket each.value.socket) each.value.mode;
+          };
+        };
+      }) allMappedSockets));
   };
+  imports = [
+    (mkRenamedOptionModule [ "services" "rspamd" "bindSocket" ] [ "services" "rspamd" "workers" "normal" "bindSockets" ])
+    (mkRenamedOptionModule [ "services" "rspamd" "bindUISocket" ] [ "services" "rspamd" "workers" "controller" "bindSockets" ])
+  ];
 }
diff --git a/nixos/release.nix b/nixos/release.nix
index a9c0aae7a526..e9d145031c4f 100644
--- a/nixos/release.nix
+++ b/nixos/release.nix
@@ -333,6 +333,7 @@ in rec {
   # tests.quagga = callTest tests/quagga.nix {};
   tests.quake3 = callTest tests/quake3.nix {};
   tests.radicale = callTest tests/radicale.nix {};
+  tests.rspamd = callSubTests tests/rspamd.nix {};
   tests.runInMachine = callTest tests/run-in-machine.nix {};
   tests.samba = callTest tests/samba.nix {};
   tests.sddm = callSubTests tests/sddm.nix {};
diff --git a/nixos/tests/rspamd.nix b/nixos/tests/rspamd.nix
new file mode 100644
index 000000000000..6b2e2dd3a531
--- /dev/null
+++ b/nixos/tests/rspamd.nix
@@ -0,0 +1,140 @@
+{ system ? builtins.currentSystem }:
+with import ../lib/testing.nix { inherit system; };
+with pkgs.lib;
+let
+  initMachine = ''
+    startAll
+    $machine->waitForUnit("rspamd.service");
+    $machine->succeed("id \"rspamd\" >/dev/null");
+  '';
+  checkSocket = socket: user: group: mode: ''
+    $machine->succeed("ls ${socket} >/dev/null");
+    $machine->succeed("[[ \"\$(stat -c %U ${socket})\" == \"${user}\" ]]");
+    $machine->succeed("[[ \"\$(stat -c %G ${socket})\" == \"${group}\" ]]");
+    $machine->succeed("[[ \"\$(stat -c %a ${socket})\" == \"${mode}\" ]]");
+  '';
+  simple = name: socketActivation: enableIPv6: makeTest {
+    name = "rspamd-${name}";
+    machine = {
+      services.rspamd = {
+        enable = true;
+        socketActivation = socketActivation;
+      };
+      networking.enableIPv6 = enableIPv6;
+    };
+    testScript = ''
+      startAll
+      $machine->waitForUnit("multi-user.target");
+      $machine->waitForOpenPort(11334);
+      $machine->waitForUnit("rspamd.service");
+      $machine->succeed("id \"rspamd\" >/dev/null");
+      ${checkSocket "/run/rspamd/rspamd.sock" "rspamd" "rspamd" "660" }
+      sleep 10;
+      $machine->log($machine->succeed("cat /etc/rspamd.conf"));
+      $machine->log($machine->succeed("systemctl cat rspamd.service"));
+      ${if socketActivation then ''
+        $machine->log($machine->succeed("systemctl cat rspamd-controller-1.socket"));
+        $machine->log($machine->succeed("systemctl cat rspamd-normal-1.socket"));
+      '' else ''
+        $machine->fail("systemctl cat rspamd-controller-1.socket");
+        $machine->fail("systemctl cat rspamd-normal-1.socket");
+      ''}
+      $machine->log($machine->succeed("curl http://localhost:11334/auth"));
+      $machine->log($machine->succeed("curl http://127.0.0.1:11334/auth"));
+      ${optionalString enableIPv6 ''
+        $machine->log($machine->succeed("curl http://[::1]:11334/auth"));
+      ''}
+    '';
+  };
+in
+{
+  simple = simple "simple" false true;
+  ipv4only = simple "ipv4only" false false;
+  simple-socketActivated = simple "simple-socketActivated" true true;
+  ipv4only-socketActivated = simple "ipv4only-socketActivated" true false;
+  deprecated = makeTest {
+    name = "rspamd-deprecated";
+    machine = {
+      services.rspamd = {
+        enable = true;
+        bindSocket = [ "/run/rspamd.sock mode=0600 user=root group=root" ];
+        bindUISocket = [ "/run/rspamd-worker.sock mode=0666 user=root group=root" ];
+      };
+    };
+
+    testScript = ''
+      ${initMachine}
+      $machine->waitForFile("/run/rspamd.sock");
+      ${checkSocket "/run/rspamd.sock" "root" "root" "600" }
+      ${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" }
+      $machine->log($machine->succeed("cat /etc/rspamd.conf"));
+      $machine->fail("systemctl cat rspamd-normal-1.socket");
+      $machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat"));
+      $machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping"));
+    '';
+  };
+
+  bindports = makeTest {
+    name = "rspamd-bindports";
+    machine = {
+      services.rspamd = {
+        enable = true;
+        socketActivation = false;
+        workers.normal.bindSockets = [{
+          socket = "/run/rspamd.sock";
+          mode = "0600";
+          owner = "root";
+          group = "root";
+        }];
+        workers.controller.bindSockets = [{
+          socket = "/run/rspamd-worker.sock";
+          mode = "0666";
+          owner = "root";
+          group = "root";
+        }];
+      };
+    };
+
+    testScript = ''
+      ${initMachine}
+      $machine->waitForFile("/run/rspamd.sock");
+      ${checkSocket "/run/rspamd.sock" "root" "root" "600" }
+      ${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" }
+      $machine->log($machine->succeed("cat /etc/rspamd.conf"));
+      $machine->fail("systemctl cat rspamd-normal-1.socket");
+      $machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat"));
+      $machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping"));
+    '';
+  };
+  socketActivated = makeTest {
+    name = "rspamd-socketActivated";
+    machine = {
+      services.rspamd = {
+        enable = true;
+        workers.normal.bindSockets = [{
+          socket = "/run/rspamd.sock";
+          mode = "0600";
+          owner = "root";
+          group = "root";
+        }];
+        workers.controller.bindSockets = [{
+          socket = "/run/rspamd-worker.sock";
+          mode = "0666";
+          owner = "root";
+          group = "root";
+        }];
+      };
+    };
+
+    testScript = ''
+      startAll
+      $machine->waitForFile("/run/rspamd.sock");
+      ${checkSocket "/run/rspamd.sock" "root" "root" "600" }
+      ${checkSocket "/run/rspamd-worker.sock" "root" "root" "666" }
+      $machine->log($machine->succeed("cat /etc/rspamd.conf"));
+      $machine->log($machine->succeed("systemctl cat rspamd-normal-1.socket"));
+      $machine->log($machine->succeed("rspamc -h /run/rspamd-worker.sock stat"));
+      $machine->log($machine->succeed("curl --unix-socket /run/rspamd-worker.sock http://localhost/ping"));
+    '';
+  };
+}
diff --git a/pkgs/applications/editors/typora/default.nix b/pkgs/applications/editors/typora/default.nix
index 22e7c3d31b36..7c6d186b8830 100644
--- a/pkgs/applications/editors/typora/default.nix
+++ b/pkgs/applications/editors/typora/default.nix
@@ -3,18 +3,18 @@
 
 stdenv.mkDerivation rec {
   name = "typora-${version}";
-  version = "0.9.41";
+  version = "0.9.44";
 
   src =
     if stdenv.system == "x86_64-linux" then
       fetchurl {
         url = "https://www.typora.io/linux/typora_${version}_amd64.deb";
-        sha256 = "e4916f86c7c12aec8fd59b3ef79c2a4d3f77b02a0a9e962916c688871c9fda1d";
+        sha256 = "9442c090bf2619d270890228abd7dabb9e217c0b200615f8ed3cb255efd122d5";
       }
     else
       fetchurl {
         url = "https://www.typora.io/linux/typora_${version}_i386.deb";
-        sha256 = "18960fb4b2cd6cf9cb77025a4035a3258f1599b1d225fb673b49c1588fa272d6";
+        sha256 = "ae228ca946d03940b85df30c995c4de3f942a780e32d4dcab872dec671c66ef3";
       }
     ;
 
diff --git a/pkgs/applications/graphics/darktable/default.nix b/pkgs/applications/graphics/darktable/default.nix
index 787ddc72ec9a..e9932b93fbe0 100644
--- a/pkgs/applications/graphics/darktable/default.nix
+++ b/pkgs/applications/graphics/darktable/default.nix
@@ -1,15 +1,10 @@
-{ stdenv, fetchurl, libsoup, graphicsmagick, SDL, json_glib
-, GConf, atk, cairo, cmake, curl, dbus_glib, exiv2, glib
-, libgnome_keyring, gtk3, ilmbase, intltool, lcms, lcms2
-, lensfun, libXau, libXdmcp, libexif, libglade, libgphoto2, libjpeg
-, libpng, libpthreadstubs, librsvg, libtiff, libxcb
-, openexr, osm-gps-map, pixman, pkgconfig, sqlite, bash, libxslt, openjpeg
-, mesa, lua, pugixml, colord, colord-gtk, libxshmfence, libxkbcommon
-, epoxy, at_spi2_core, libwebp, libsecret, wrapGAppsHook, gnome3
+{ stdenv, fetchurl, libsoup, graphicsmagick, json_glib, wrapGAppsHook
+, cairo, cmake, ninja, curl, perl, llvm, desktop_file_utils, exiv2, glib
+, ilmbase, gtk3, intltool, lcms2, lensfun, libX11, libexif, libgphoto2, libjpeg
+, libpng, librsvg, libtiff, openexr, osm-gps-map, pkgconfig, sqlite, libxslt
+, openjpeg, lua, pugixml, colord, colord-gtk, libwebp, libsecret, gnome3
 }:
 
-assert stdenv ? glibc;
-
 stdenv.mkDerivation rec {
   version = "2.4.1";
   name = "darktable-${version}";
@@ -19,16 +14,15 @@ stdenv.mkDerivation rec {
     sha256 = "014pq80i5k1kdvvrl7xrgaaq3i4fzv09h7a3pwzlp2ahkczwcm32";
   };
 
-  buildInputs =
-    [ GConf atk cairo cmake curl dbus_glib exiv2 glib libgnome_keyring gtk3
-      ilmbase intltool lcms lcms2 lensfun libXau libXdmcp libexif
-      libglade libgphoto2 libjpeg libpng libpthreadstubs
-      librsvg libtiff libxcb openexr pixman pkgconfig sqlite libxslt
-      libsoup graphicsmagick SDL json_glib openjpeg mesa lua pugixml
-      colord colord-gtk libxshmfence libxkbcommon epoxy at_spi2_core
-      libwebp libsecret wrapGAppsHook gnome3.adwaita-icon-theme
-      osm-gps-map
-    ];
+  nativeBuildInputs = [ cmake ninja llvm pkgconfig intltool perl desktop_file_utils wrapGAppsHook ];
+
+  buildInputs = [
+    cairo curl exiv2 glib gtk3 ilmbase lcms2 lensfun libX11 libexif
+    libgphoto2 libjpeg libpng librsvg libtiff openexr sqlite libxslt
+    libsoup graphicsmagick json_glib openjpeg lua pugixml
+    colord colord-gtk libwebp libsecret gnome3.adwaita-icon-theme
+    osm-gps-map
+  ];
 
   cmakeFlags = [
     "-DBUILD_USERMANUAL=False"
diff --git a/pkgs/applications/networking/instant-messengers/gajim/default.nix b/pkgs/applications/networking/instant-messengers/gajim/default.nix
index b01c6497fb23..42c510495574 100644
--- a/pkgs/applications/networking/instant-messengers/gajim/default.nix
+++ b/pkgs/applications/networking/instant-messengers/gajim/default.nix
@@ -1,9 +1,6 @@
 { stdenv, fetchurl, autoreconfHook, python, intltool, pkgconfig, libX11
 , ldns, pythonPackages
 
-# Test requirements
-, xvfb_run
-
 , enableJingle ? true, farstream ? null, gst-plugins-bad ? null
 ,                      libnice ? null
 , enableE2E ? true
@@ -25,13 +22,13 @@ with stdenv.lib;
 
 stdenv.mkDerivation rec {
   name = "gajim-${version}";
-  version = "0.16.8";
+  version = "0.16.9";
 
   src = fetchurl {
     name = "${name}.tar.bz2";
     url = "https://dev.gajim.org/gajim/gajim/repository/archive.tar.bz2?"
         + "ref=${name}";
-    sha256 = "009cpzqh4zy7hc9pq3r5m4lgagwawhjab13rjzavb0n9ggijcscb";
+    sha256 = "121dh906zya9n7npyk7b5xama0z3ycy9jl7l5jm39pc86h1winh3";
   };
 
   patches = let
@@ -46,8 +43,7 @@ stdenv.mkDerivation rec {
     name = "gajim-${name}.patch";
     url = "https://dev.gajim.org/gajim/gajim/commit/${rev}.diff";
     inherit sha256;
-  }) cherries)
-    ++ [./fix-tests.patch]; # https://dev.gajim.org/gajim/gajim/issues/8660
+  }) cherries);
 
   postPatch = ''
     sed -i -e '0,/^[^#]/ {
@@ -74,8 +70,6 @@ stdenv.mkDerivation rec {
 
   nativeBuildInputs = [
     autoreconfHook pythonPackages.wrapPython intltool pkgconfig
-    # Test dependencies
-    xvfb_run
   ];
 
   autoreconfPhase = ''
@@ -114,9 +108,8 @@ stdenv.mkDerivation rec {
 
   doInstallCheck = true;
   installCheckPhase = ''
-    XDG_DATA_DIRS="$out/share/gajim''${XDG_DATA_DIRS:+:}$XDG_DATA_DIRS" \
     PYTHONPATH="test:$out/share/gajim/src:''${PYTHONPATH:+:}$PYTHONPATH" \
-      xvfb-run make test
+      make test_nogui
   '';
 
   enableParallelBuilding = true;
diff --git a/pkgs/applications/networking/instant-messengers/gajim/fix-tests.patch b/pkgs/applications/networking/instant-messengers/gajim/fix-tests.patch
deleted file mode 100644
index cb866bb2d739..000000000000
--- a/pkgs/applications/networking/instant-messengers/gajim/fix-tests.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/src/common/gajim.py b/src/common/gajim.py
-index 4a5d884b6..95d401b67 100644
---- a/src/common/gajim.py
-+++ b/src/common/gajim.py
-@@ -415,7 +415,7 @@ def get_jid_from_account(account_name, full=False):
-     jid = name + '@' + hostname
-     if full:
-         resource = connections[account_name].server_resource
--        jid += '/' + resource
-+        jid += '/' + str(resource)
-     return jid
- 
- def get_our_jids():
diff --git a/pkgs/applications/virtualization/docker/default.nix b/pkgs/applications/virtualization/docker/default.nix
index 56436d047f2e..339d3e8490d9 100644
--- a/pkgs/applications/virtualization/docker/default.nix
+++ b/pkgs/applications/virtualization/docker/default.nix
@@ -209,14 +209,14 @@ rec {
     tiniSha256 = "0zj4kdis1vvc6dwn4gplqna0bs7v6d1y2zc8v80s3zi018inhznw";
   };
 
-  docker_18_01 = dockerGen rec {
-    version = "18.01.0-ce";
-    rev = "03596f51b120095326d2004d676e97228a21014d"; # git commit
-    sha256 = "1zffaxwkfz8ca76f5ql5z76mcjx37jbgv2kk75i68487yg16x0md";
-    runcRev = "b2567b37d7b75eb4cf325b77297b140ea686ce8f";
-    runcSha256 = "0zarsrbfcm1yp6mdl6rcrigdf7nb70xmv2cbggndz0qqyrw0mk0l";
-    containerdRev = "89623f28b87a6004d4b785663257362d1658a729";
-    containerdSha256 = "0irx7ps6rhq7z69cr3gspxdr7ywrv6dz62gkr1z2723cki9hsxma";
+  docker_18_02 = dockerGen rec {
+    version = "18.02.0-ce";
+    rev = "fc4de447b563498eb4da89f56fb858bbe761d91b"; # git commit
+    sha256 = "1025cwv2niiwg5pc30nb1qky1raisvd9ix2qw6rdib232hwq9k8m";
+    runcRev = "9f9c96235cc97674e935002fc3d78361b696a69e";
+    runcSha256 = "18f8vqdbf685dd777pjh8jzpxafw2vapqh4m43xgyi7lfwa0gsln";
+    containerdRev = "9b55aab90508bd389d7654c4baf173a981477d55";
+    containerdSha256 = "0kfafqi66yp4qy738pl11f050hfrx9m4kc670qpx7fmf9ii7q6p2";
     tiniRev = "949e6facb77383876aeff8a6944dde66b3089574";
     tiniSha256 = "0zj4kdis1vvc6dwn4gplqna0bs7v6d1y2zc8v80s3zi018inhznw";
   };
diff --git a/pkgs/development/libraries/libproxy/default.nix b/pkgs/development/libraries/libproxy/default.nix
index 614890e929f7..bf9e2d079cd6 100644
--- a/pkgs/development/libraries/libproxy/default.nix
+++ b/pkgs/development/libraries/libproxy/default.nix
@@ -1,5 +1,6 @@
-{ stdenv, lib, fetchFromGitHub, pkgconfig, cmake
-, dbus, networkmanager, spidermonkey_38, pcre, python2, python3 }:
+{ stdenv, lib, fetchFromGitHub, pkgconfig, cmake, zlib
+, dbus, networkmanager, spidermonkey_38, pcre, python2, python3
+, SystemConfiguration, CoreFoundation, JavaScriptCore }:
 
 stdenv.mkDerivation rec {
   name = "libproxy-${version}";
@@ -16,7 +17,10 @@ stdenv.mkDerivation rec {
 
   nativeBuildInputs = [ pkgconfig cmake ];
 
-  buildInputs = [ dbus networkmanager spidermonkey_38 pcre python2 python3 ];
+  buildInputs = [ pcre python2 python3 zlib ]
+        ++ (if stdenv.hostPlatform.isDarwin
+            then [ SystemConfiguration CoreFoundation JavaScriptCore ]
+            else [ spidermonkey_38 dbus networkmanager ]);
 
   preConfigure = ''
     cmakeFlagsArray+=(
@@ -27,7 +31,7 @@ stdenv.mkDerivation rec {
   '';
 
   meta = with stdenv.lib; {
-    platforms = platforms.linux;
+    platforms = platforms.linux ++ platforms.darwin;
     license = licenses.lgpl21;
     homepage = http://libproxy.github.io/libproxy/;
     description = "A library that provides automatic proxy configuration management";
diff --git a/pkgs/development/python-modules/awesome-slugify/default.nix b/pkgs/development/python-modules/awesome-slugify/default.nix
index 105c70c28b34..945c941dec4e 100644
--- a/pkgs/development/python-modules/awesome-slugify/default.nix
+++ b/pkgs/development/python-modules/awesome-slugify/default.nix
@@ -3,13 +3,17 @@
 buildPythonPackage rec {
   pname = "awesome-slugify";
   version = "1.6.5";
-  name  = "${pname}-${version}";
 
   src = fetchPypi {
     inherit pname version;
     sha256 = "0wgxrhr8s5vk2xmcz9s1z1aml4ppawmhkbggl9rp94c747xc7pmv";
   };
 
+  prePatch = ''
+    substituteInPlace setup.py \
+        --replace 'Unidecode>=0.04.14,<0.05' 'Unidecode>=0.04.14'
+  '';
+
   patches = [
     ./slugify_filename_test.patch # fixes broken test by new unidecode
   ];
diff --git a/pkgs/development/python-modules/pythonnet/default.nix b/pkgs/development/python-modules/pythonnet/default.nix
new file mode 100644
index 000000000000..98f714c8d538
--- /dev/null
+++ b/pkgs/development/python-modules/pythonnet/default.nix
@@ -0,0 +1,84 @@
+{ lib
+, fetchPypi
+, fetchNuGet
+, buildPythonPackage
+, python
+, pytest
+, pycparser
+, pkgconfig
+, dotnetbuildhelpers
+, clang
+, mono
+}:
+
+let
+
+  UnmanagedExports127 = fetchNuGet {
+    baseName = "UnmanagedExports";
+    version = "1.2.7";
+    sha256 = "0bfrhpmq556p0swd9ssapw4f2aafmgp930jgf00sy89hzg2bfijf";
+    outputFiles = [ "*" ];
+  };
+
+  NUnit360 = fetchNuGet {
+    baseName = "NUnit";
+    version = "3.6.0";
+    sha256 = "0wz4sb0hxlajdr09r22kcy9ya79lka71w0k1jv5q2qj3d6g2frz1";
+    outputFiles = [ "*" ];
+  };
+
+in
+
+buildPythonPackage rec {
+  pname = "pythonnet";
+  version = "2.3.0";
+
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "1hxnkrfj8ark9sbamcxzd63p98vgljfvdwh79qj3ac8pqrgghq80";
+  };
+
+  postPatch = ''
+    substituteInPlace setup.py --replace 'self._install_packages()' '#self._install_packages()'
+  '';
+
+  preConfigure = ''
+    [ -z "$dontPlacateNuget" ] && placate-nuget.sh
+    [ -z "$dontPlacatePaket" ] && placate-paket.sh
+  '';
+
+  nativeBuildInputs = [
+    pytest
+    pycparser
+
+    pkgconfig
+    dotnetbuildhelpers
+    clang
+
+    NUnit360
+    UnmanagedExports127
+  ];
+
+  buildInputs = [
+    mono
+  ];
+
+  preBuild = ''
+    rm -rf packages
+    mkdir packages
+
+    ln -s ${NUnit360}/lib/dotnet/NUnit/ packages/NUnit.3.6.0
+    ln -s ${UnmanagedExports127}/lib/dotnet/NUnit/ packages/UnmanagedExports.1.2.7
+  '';
+
+  checkPhase = ''
+    ${python.interpreter} -m pytest
+  '';
+
+  meta = with lib; {
+    description = ".Net and Mono integration for Python";
+    homepage = https://pythonnet.github.io;
+    license = licenses.mit;
+    maintainers = with maintainers; [ jraygauthier ];
+  };
+}
diff --git a/pkgs/development/tools/hcloud/default.nix b/pkgs/development/tools/hcloud/default.nix
new file mode 100644
index 000000000000..e56502a4ad05
--- /dev/null
+++ b/pkgs/development/tools/hcloud/default.nix
@@ -0,0 +1,24 @@
+{ stdenv, buildGoPackage, fetchFromGitHub }:
+
+buildGoPackage rec {
+  name = "hcloud-${version}";
+  version = "1.3.0";
+  goPackagePath = "github.com/hetznercloud/cli";
+
+  src = fetchFromGitHub {
+    owner = "hetznercloud";
+    repo = "cli";
+    rev = "v${version}";
+    sha256 = "1216qz1kk38vkvfrznjwb65vsbhscqvvrsbp2i6pnf0i85p00pqm";
+  };
+
+  buildFlagsArray = [ "-ldflags=" "-X github.com/hetznercloud/cli.Version=${version}" ];
+
+  meta = {
+    description = "A command-line interface for Hetzner Cloud, a provider for cloud virtual private servers";
+    homepage = https://github.com/hetznercloud/cli;
+    license = stdenv.lib.licenses.mit;
+    platforms = stdenv.lib.platforms.all;
+    maintainers = [ stdenv.lib.maintainers.zauberpony ];
+  };
+}
diff --git a/pkgs/development/tools/selenium/chromedriver/default.nix b/pkgs/development/tools/selenium/chromedriver/default.nix
index 61f5f93ebfaa..554a5585f150 100644
--- a/pkgs/development/tools/selenium/chromedriver/default.nix
+++ b/pkgs/development/tools/selenium/chromedriver/default.nix
@@ -4,19 +4,14 @@
 }:
 let
   allSpecs = {
-    "i686-linux" = {
-      system = "linux32";
-      sha256 = "13fngjg2v0l3vhlmjnffy785ckgk2kbpm7307li75vinkcly91cj";
-    };
-
     "x86_64-linux" = {
       system = "linux64";
-      sha256 = "0x5vnmnw6mws6iw9s0kcm4crx9gfgy0vjjpk1v0wk7jpn6d0bl47";
+      sha256 = "13iyz6579yw4fk9dr4nf2pdj55v1iflj8yf9a4zz7qw5996d5yk7";
     };
 
     "x86_64-darwin" = {
       system = "mac64";
-      sha256 = "09y8ijj75q5a7snzchxinxfq2ad2sw0f30zi0p3hqf1n88y28jq6";
+      sha256 = "11xa31bxhrq0p7kd3j76dihp73abdbmbwdng5454m1wir6yj25f1";
     };
   };
 
@@ -33,7 +28,7 @@ let
 in
 stdenv.mkDerivation rec {
   name = "chromedriver-${version}";
-  version = "2.33";
+  version = "2.35";
 
   src = fetchurl {
     url = "http://chromedriver.storage.googleapis.com/${version}/chromedriver_${spec.system}.zip";
diff --git a/pkgs/tools/misc/youtube-dl/default.nix b/pkgs/tools/misc/youtube-dl/default.nix
index c4595a1a94e1..0386896d97f8 100644
--- a/pkgs/tools/misc/youtube-dl/default.nix
+++ b/pkgs/tools/misc/youtube-dl/default.nix
@@ -16,11 +16,11 @@ with stdenv.lib;
 buildPythonApplication rec {
 
   name = "youtube-dl-${version}";
-  version = "2018.01.27";
+  version = "2018.02.08";
 
   src = fetchurl {
     url = "https://yt-dl.org/downloads/${version}/${name}.tar.gz";
-    sha256 = "14vbm8pr6xdrdbk8j9k4v82rnalbdpk2lcm7n9wj6z6d441ymji9";
+    sha256 = "0iq5mav782gz0gm00rry3v7gdxkkx4y1k0p20pvz32ga4id5k1mg";
   };
 
   nativeBuildInputs = [ makeWrapper ];
diff --git a/pkgs/tools/typesetting/asciidoctor/default.nix b/pkgs/tools/typesetting/asciidoctor/default.nix
index f494f1911593..02b57ee3a13b 100644
--- a/pkgs/tools/typesetting/asciidoctor/default.nix
+++ b/pkgs/tools/typesetting/asciidoctor/default.nix
@@ -1,12 +1,18 @@
-{ stdenv, lib, bundlerEnv, ruby, curl }:
-
-bundlerEnv {
-  pname = "asciidoctor";
+{ stdenv, lib, bundlerApp, ruby, curl }:
 
+bundlerApp {
   inherit ruby;
-
+  pname = "asciidoctor";
   gemdir = ./.;
 
+  exes = [
+    "asciidoctor"
+    "asciidoctor-bespoke"
+    "asciidoctor-latex"
+    "asciidoctor-pdf"
+    "asciidoctor-safe"
+  ];
+
   meta = with lib; {
     description = "A faster Asciidoc processor written in Ruby";
     homepage = http://asciidoctor.org/;
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index e0cca97ea849..c09a3843e263 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -7623,6 +7623,8 @@ with pkgs;
     guile = guile_2_0;
   };
 
+  hcloud = callPackage ../development/tools/hcloud { };
+
   help2man = callPackage ../development/tools/misc/help2man {
     inherit (perlPackages) LocaleGettext;
   };
@@ -9894,9 +9896,7 @@ with pkgs;
   };
 
   libproxy = callPackage ../development/libraries/libproxy {
-    stdenv = if stdenv.isDarwin
-      then overrideCC stdenv gcc
-      else stdenv;
+    inherit (darwin.apple_sdk.frameworks) SystemConfiguration CoreFoundation JavaScriptCore;
   };
 
   libpseudo = callPackage ../development/libraries/libpseudo { };
@@ -11167,7 +11167,7 @@ with pkgs;
   strigi = callPackage ../development/libraries/strigi { clucene_core = clucene_core_2; };
 
   subdl = callPackage ../applications/video/subdl { };
-  
+
   subtitleeditor = callPackage ../applications/video/subtitleeditor { };
 
   suil-qt4 = callPackage ../development/libraries/audio/suil {
@@ -14651,7 +14651,6 @@ with pkgs;
   });
 
   darktable = callPackage ../applications/graphics/darktable {
-    inherit (gnome2) GConf libglade;
     lua = lua5_3;
     pugixml = pugixml.override { shared = true; };
   };
@@ -14712,10 +14711,10 @@ with pkgs;
 
   inherit (callPackage ../applications/virtualization/docker { })
     docker_17_12
-    docker_18_01;
+    docker_18_02;
 
   docker = docker_17_12;
-  docker-edge = docker_18_01;
+  docker-edge = docker_18_02;
 
   docker-proxy = callPackage ../applications/virtualization/docker/proxy.nix { };
 
diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix
index b36407936127..ca0acaa69057 100644
--- a/pkgs/top-level/python-packages.nix
+++ b/pkgs/top-level/python-packages.nix
@@ -14845,6 +14845,11 @@ in {
     };
   };
 
+  pythonnet = callPackage ../development/python-modules/pythonnet {
+    # `mono >= 4.6` required to prevent crashes encountered with earlier versions.
+    mono = pkgs.mono46;
+  };
+
   pytz = callPackage ../development/python-modules/pytz { };
 
   pytzdata = callPackage ../development/python-modules/pytzdata { };