summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--maintainers/maintainer-list.nix6
-rw-r--r--nixos/modules/config/update-users-groups.pl6
-rw-r--r--nixos/modules/config/users-groups.nix9
-rw-r--r--nixos/modules/services/networking/mosquitto.nix10
-rw-r--r--nixos/modules/system/boot/systemd.nix17
-rw-r--r--nixos/modules/system/boot/systemd/logind.nix3
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/mosquitto.nix28
-rw-r--r--nixos/tests/mysql/mysql-backup.nix1
-rw-r--r--nixos/tests/user-home-mode.nix27
-rw-r--r--pkgs/applications/blockchains/sparrow/default.nix232
-rw-r--r--pkgs/applications/blockchains/sparrow/openimajgrabber.nix40
-rw-r--r--pkgs/applications/emulators/box64/default.nix66
-rw-r--r--pkgs/applications/emulators/citra/default.nix122
-rw-r--r--pkgs/applications/emulators/citra/generic.nix107
-rwxr-xr-xpkgs/applications/emulators/citra/update.sh84
-rw-r--r--pkgs/applications/misc/pgmodeler/default.nix4
-rw-r--r--pkgs/development/compilers/gcc/10/default.nix7
-rw-r--r--pkgs/development/python-modules/lektor/default.nix1
-rw-r--r--pkgs/development/python-modules/mkdocs-drawio-exporter/default.nix33
-rw-r--r--pkgs/development/python-modules/pamqp/default.nix42
-rw-r--r--pkgs/development/python-modules/pulumi-aws/default.nix44
-rw-r--r--pkgs/development/python-modules/pulumi/default.nix89
-rw-r--r--pkgs/development/python-modules/pytile/default.nix2
-rw-r--r--pkgs/os-specific/linux/apfs/default.nix10
-rw-r--r--pkgs/os-specific/linux/systemd/default.nix2
-rw-r--r--pkgs/os-specific/linux/zenpower/default.nix8
-rw-r--r--pkgs/servers/home-assistant/default.nix5
-rw-r--r--pkgs/tools/admin/pulumi/update-pulumi-shell.nix8
-rwxr-xr-xpkgs/tools/admin/pulumi/update.sh2
-rw-r--r--pkgs/tools/networking/isync/default.nix1
-rw-r--r--pkgs/top-level/aliases.nix1
-rw-r--r--pkgs/top-level/all-packages.nix14
-rw-r--r--pkgs/top-level/python-packages.nix5
34 files changed, 909 insertions, 128 deletions
diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix
index d8eaff4a0d8d2..654311d6e287e 100644
--- a/maintainers/maintainer-list.nix
+++ b/maintainers/maintainer-list.nix
@@ -14607,4 +14607,10 @@
       fingerprint = "41EA 00B4 00F9 6970 1CB2  D3AF EF90 E3E9 8B8F 5C0B";
     }];
   };
+  snpschaaf = {
+    email = "philipe.schaaf@secunet.com";
+    name = "Philippe Schaaf";
+    github = "snpschaaf";
+    githubId = 105843013;
+  };
 }
diff --git a/nixos/modules/config/update-users-groups.pl b/nixos/modules/config/update-users-groups.pl
index 26ce561013b6f..5a21cb45d52be 100644
--- a/nixos/modules/config/update-users-groups.pl
+++ b/nixos/modules/config/update-users-groups.pl
@@ -223,10 +223,10 @@ foreach my $u (@{$spec->{users}}) {
     }
 
     # Ensure home directory incl. ownership and permissions.
-    if ($u->{createHome}) {
-        make_path($u->{home}, { mode => 0700 }) if ! -e $u->{home} and ! $is_dry;
+    if ($u->{createHome} and !$is_dry) {
+        make_path($u->{home}, { mode => oct($u->{homeMode}) }) if ! -e $u->{home};
         chown $u->{uid}, $u->{gid}, $u->{home};
-        chmod 0700, $u->{home};
+        chmod oct($u->{homeMode}), $u->{home};
     }
 
     if (defined $u->{passwordFile}) {
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 9b0b4935b988f..d3bdf218c3392 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -139,6 +139,12 @@ let
         description = "The user's home directory.";
       };
 
+      homeMode = mkOption {
+        type = types.strMatching "[0-7]{1,5}";
+        default = "700";
+        description = "The user's home directory mode in numeric format. See chmod(1). The mode is only applied if <option>users.users.&lt;name&gt;.createHome</option> is true.";
+      };
+
       cryptHomeLuks = mkOption {
         type = with types; nullOr str;
         default = null;
@@ -319,6 +325,7 @@ let
           group = mkDefault "users";
           createHome = mkDefault true;
           home = mkDefault "/home/${config.name}";
+          homeMode = mkDefault "700";
           useDefaultShell = mkDefault true;
           isSystemUser = mkDefault false;
         })
@@ -430,7 +437,7 @@ let
     inherit (cfg) mutableUsers;
     users = mapAttrsToList (_: u:
       { inherit (u)
-          name uid group description home createHome isSystemUser
+          name uid group description home homeMode createHome isSystemUser
           password passwordFile hashedPassword
           autoSubUidGidRange subUidRanges subGidRanges
           initialPassword initialHashedPassword;
diff --git a/nixos/modules/services/networking/mosquitto.nix b/nixos/modules/services/networking/mosquitto.nix
index b41a2fd27be2f..256d9457d3960 100644
--- a/nixos/modules/services/networking/mosquitto.nix
+++ b/nixos/modules/services/networking/mosquitto.nix
@@ -199,6 +199,7 @@ let
     allow_anonymous = 1;
     allow_zero_length_clientid = 1;
     auto_id_prefix = 1;
+    bind_interface = 1;
     cafile = 1;
     capath = 1;
     certfile = 1;
@@ -295,7 +296,7 @@ let
   };
 
   listenerAsserts = prefix: listener:
-    assertKeysValid prefix freeformListenerKeys listener.settings
+    assertKeysValid "${prefix}.settings" freeformListenerKeys listener.settings
     ++ userAsserts prefix listener.users
     ++ imap0
       (i: v: authAsserts "${prefix}.authPlugins.${toString i}" v)
@@ -397,7 +398,7 @@ let
   };
 
   bridgeAsserts = prefix: bridge:
-    assertKeysValid prefix freeformBridgeKeys bridge.settings
+    assertKeysValid "${prefix}.settings" freeformBridgeKeys bridge.settings
     ++ [ {
       assertion = length bridge.addresses > 0;
       message = "Bridge ${prefix} needs remote broker addresses";
@@ -526,7 +527,7 @@ let
 
   globalAsserts = prefix: cfg:
     flatten [
-      (assertKeysValid prefix freeformGlobalKeys cfg.settings)
+      (assertKeysValid "${prefix}.settings" freeformGlobalKeys cfg.settings)
       (imap0 (n: l: listenerAsserts "${prefix}.listener.${toString n}" l) cfg.listeners)
       (mapAttrsToList (n: b: bridgeAsserts "${prefix}.bridge.${n}" b) cfg.bridges)
     ];
@@ -629,9 +630,10 @@ in
                ]));
         RemoveIPC = true;
         RestrictAddressFamilies = [
-          "AF_UNIX"  # for sd_notify() call
+          "AF_UNIX"
           "AF_INET"
           "AF_INET6"
+          "AF_NETLINK"
         ];
         RestrictNamespaces = true;
         RestrictRealtime = true;
diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix
index 2c9ee9fc319fc..679c5210a6b32 100644
--- a/nixos/modules/system/boot/systemd.nix
+++ b/nixos/modules/system/boot/systemd.nix
@@ -35,11 +35,11 @@ let
       "nss-lookup.target"
       "nss-user-lookup.target"
       "time-sync.target"
-    ] ++ (optionals cfg.package.withCryptsetup [
+    ] ++ optionals cfg.package.withCryptsetup [
       "cryptsetup.target"
       "cryptsetup-pre.target"
       "remote-cryptsetup.target"
-    ]) ++ [
+    ] ++ [
       "sigpwr.target"
       "timers.target"
       "paths.target"
@@ -133,20 +133,27 @@ let
 
       # Slices / containers.
       "slices.target"
+    ] ++ optionals cfg.package.withImportd [
+      "systemd-importd.service"
+    ] ++ optionals cfg.package.withMachined [
       "machine.slice"
       "machines.target"
-      "systemd-importd.service"
       "systemd-machined.service"
+    ] ++ [
       "systemd-nspawn@.service"
 
       # Misc.
       "systemd-sysctl.service"
+    ] ++ optionals cfg.package.withTimedated [
       "dbus-org.freedesktop.timedate1.service"
-      "dbus-org.freedesktop.locale1.service"
-      "dbus-org.freedesktop.hostname1.service"
       "systemd-timedated.service"
+    ] ++ optionals cfg.package.withLocaled [
+      "dbus-org.freedesktop.locale1.service"
       "systemd-localed.service"
+    ] ++ optionals cfg.package.withHostnamed [
+      "dbus-org.freedesktop.hostname1.service"
       "systemd-hostnamed.service"
+    ] ++ [
       "systemd-exit.service"
       "systemd-update-done.service"
     ] ++ cfg.additionalUpstreamSystemUnits;
diff --git a/nixos/modules/system/boot/systemd/logind.nix b/nixos/modules/system/boot/systemd/logind.nix
index c1e6cfe61d041..97ac588bce174 100644
--- a/nixos/modules/system/boot/systemd/logind.nix
+++ b/nixos/modules/system/boot/systemd/logind.nix
@@ -81,8 +81,11 @@ in
       "systemd-logind.service"
       "autovt@.service"
       "systemd-user-sessions.service"
+    ] ++ optionals config.systemd.package.withImportd [
       "dbus-org.freedesktop.import1.service"
+    ] ++ optionals config.systemd.package.withMachined [
       "dbus-org.freedesktop.machine1.service"
+    ] ++ [
       "dbus-org.freedesktop.login1.service"
       "user@.service"
       "user-runtime-dir@.service"
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index 0de71030c4fbb..f4b6ee73562eb 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -580,6 +580,7 @@ in
   uptermd = handleTest ./uptermd.nix {};
   usbguard = handleTest ./usbguard.nix {};
   user-activation-scripts = handleTest ./user-activation-scripts.nix {};
+  user-home-mode = handleTest ./user-home-mode.nix {};
   uwsgi = handleTest ./uwsgi.nix {};
   v2ray = handleTest ./v2ray.nix {};
   vault = handleTest ./vault.nix {};
diff --git a/nixos/tests/mosquitto.nix b/nixos/tests/mosquitto.nix
index 36cc8e3e3d9bd..d516d3373d9f6 100644
--- a/nixos/tests/mosquitto.nix
+++ b/nixos/tests/mosquitto.nix
@@ -4,6 +4,7 @@ let
   port = 1888;
   tlsPort = 1889;
   anonPort = 1890;
+  bindTestPort = 1891;
   password = "VERY_secret";
   hashedPassword = "$7$101$/WJc4Mp+I+uYE9sR$o7z9rD1EYXHPwEP5GqQj6A7k4W1yVbePlb8TqNcuOLV9WNCiDgwHOB0JHC1WCtdkssqTBduBNUnUGd6kmZvDSw==";
   topic = "test/foo";
@@ -125,6 +126,10 @@ in {
               };
             };
           }
+          {
+            settings.bind_interface = "eth0";
+            port = bindTestPort;
+          }
         ];
       };
     };
@@ -134,6 +139,8 @@ in {
   };
 
   testScript = ''
+    import json
+
     def mosquitto_cmd(binary, user, topic, port):
         return (
             "mosquitto_{} "
@@ -162,6 +169,27 @@ in {
     start_all()
     server.wait_for_unit("mosquitto.service")
 
+    with subtest("bind_interface"):
+        addrs = dict()
+        for iface in json.loads(server.succeed("ip -json address show")):
+            for addr in iface['addr_info']:
+                # don't want to deal with multihoming here
+                assert addr['local'] not in addrs
+                addrs[addr['local']] = (iface['ifname'], addr['family'])
+
+        # mosquitto grabs *one* random address per type for bind_interface
+        (has4, has6) = (False, False)
+        for line in server.succeed("ss -HlptnO sport = ${toString bindTestPort}").splitlines():
+            items = line.split()
+            if "mosquitto" not in items[5]: continue
+            listener = items[3].rsplit(':', maxsplit=1)[0].strip('[]')
+            assert listener in addrs
+            assert addrs[listener][0] == "eth0"
+            has4 |= addrs[listener][1] == 'inet'
+            has6 |= addrs[listener][1] == 'inet6'
+        assert has4
+        assert has6
+
     with subtest("check passwords"):
         client1.succeed(publish("-m test", "password_store"))
         client1.succeed(publish("-m test", "password_file"))
diff --git a/nixos/tests/mysql/mysql-backup.nix b/nixos/tests/mysql/mysql-backup.nix
index 9335b233327a7..968f56dd3c9bd 100644
--- a/nixos/tests/mysql/mysql-backup.nix
+++ b/nixos/tests/mysql/mysql-backup.nix
@@ -51,7 +51,6 @@ let
 
       # Do a backup and wait for it to start
       master.start_job("mysql-backup.service")
-      master.wait_for_unit("mysql-backup.service")
 
       # wait for backup to fail, because of database 'doesnotexist'
       master.wait_until_fails("systemctl is-active -q mysql-backup.service")
diff --git a/nixos/tests/user-home-mode.nix b/nixos/tests/user-home-mode.nix
new file mode 100644
index 0000000000000..1366d102a99b3
--- /dev/null
+++ b/nixos/tests/user-home-mode.nix
@@ -0,0 +1,27 @@
+import ./make-test-python.nix ({ lib, ... }: {
+  name = "user-home-mode";
+  meta = with lib.maintainers; { maintainers = [ fbeffa ]; };
+
+  nodes.machine = {
+    users.users.alice = {
+      initialPassword = "pass1";
+      isNormalUser = true;
+    };
+    users.users.bob = {
+      initialPassword = "pass2";
+      isNormalUser = true;
+      homeMode = "750";
+    };
+  };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+    machine.wait_for_unit("getty@tty1.service")
+    machine.wait_until_tty_matches(1, "login: ")
+    machine.send_chars("alice\n")
+    machine.wait_until_tty_matches(1, "Password: ")
+    machine.send_chars("pass1\n")
+    machine.succeed('[ "$(stat -c %a /home/alice)" == "700" ]')
+    machine.succeed('[ "$(stat -c %a /home/bob)" == "750" ]')
+  '';
+})
diff --git a/pkgs/applications/blockchains/sparrow/default.nix b/pkgs/applications/blockchains/sparrow/default.nix
new file mode 100644
index 0000000000000..662164a9f6f3d
--- /dev/null
+++ b/pkgs/applications/blockchains/sparrow/default.nix
@@ -0,0 +1,232 @@
+{ stdenv
+, lib
+, makeWrapper
+, fetchurl
+, makeDesktopItem
+, copyDesktopItems
+, autoPatchelfHook
+, openjdk17
+, gtk3
+, gsettings-desktop-schemas
+, writeScript
+, bash
+, gnugrep
+, tor
+, zlib
+, openimajgrabber
+, hwi
+, imagemagick
+}:
+
+let
+  pname = "sparrow";
+  version = "1.6.4";
+
+  src = fetchurl {
+    url = "https://github.com/sparrowwallet/${pname}/releases/download/${version}/${pname}-${version}.tar.gz";
+    sha256 = "1wdibpbhv3g6qk42ddfc5vyqkkwprczy45w5wi115qg3g1rf1in7";
+  };
+
+  launcher = writeScript "sparrow" ''
+    #! ${bash}/bin/bash
+    params=(
+      --module-path @out@/lib:@jdkModules@/modules
+      --add-opens javafx.graphics/com.sun.javafx.css=org.controlsfx.controls
+      --add-opens javafx.graphics/javafx.scene=org.controlsfx.controls
+      --add-opens javafx.controls/com.sun.javafx.scene.control.behavior=org.controlsfx.controls
+      --add-opens javafx.controls/com.sun.javafx.scene.control.inputmap=org.controlsfx.controls
+      --add-opens javafx.graphics/com.sun.javafx.scene.traversal=org.controlsfx.controls
+      --add-opens javafx.base/com.sun.javafx.event=org.controlsfx.controls
+      --add-opens javafx.controls/javafx.scene.control.cell=com.sparrowwallet.sparrow
+      --add-opens org.controlsfx.controls/impl.org.controlsfx.skin=com.sparrowwallet.sparrow
+      --add-opens org.controlsfx.controls/impl.org.controlsfx.skin=javafx.fxml
+      --add-opens javafx.graphics/com.sun.javafx.tk=centerdevice.nsmenufx
+      --add-opens javafx.graphics/com.sun.javafx.tk.quantum=centerdevice.nsmenufx
+      --add-opens javafx.graphics/com.sun.glass.ui=centerdevice.nsmenufx
+      --add-opens javafx.controls/com.sun.javafx.scene.control=centerdevice.nsmenufx
+      --add-opens javafx.graphics/com.sun.javafx.menu=centerdevice.nsmenufx
+      --add-opens javafx.graphics/com.sun.glass.ui=com.sparrowwallet.sparrow
+      --add-opens javafx.graphics/com.sun.javafx.application=com.sparrowwallet.sparrow
+      --add-opens java.base/java.net=com.sparrowwallet.sparrow
+      --add-opens java.base/java.io=com.google.gson
+      --add-reads com.sparrowwallet.merged.module=java.desktop
+      --add-reads com.sparrowwallet.merged.module=java.sql
+      --add-reads com.sparrowwallet.merged.module=com.sparrowwallet.sparrow
+      --add-reads com.sparrowwallet.merged.module=logback.classic
+      --add-reads com.sparrowwallet.merged.module=com.fasterxml.jackson.databind
+      --add-reads com.sparrowwallet.merged.module=com.fasterxml.jackson.annotation
+      --add-reads com.sparrowwallet.merged.module=com.fasterxml.jackson.core
+      --add-reads com.sparrowwallet.merged.module=co.nstant.in.cbor
+      -m com.sparrowwallet.sparrow
+    )
+
+    XDG_DATA_DIRS=${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}:${gtk3}/share/gsettings-schemas/${gtk3.name}:$XDG_DATA_DIRS ${openjdk17}/bin/java ''${params[@]} $@
+  '';
+
+  torWrapper = writeScript "tor-wrapper" ''
+    #! ${bash}/bin/bash
+
+    exec ${tor}/bin/tor "$@"
+  '';
+
+  jdk-modules = stdenv.mkDerivation {
+    name = "jdk-modules";
+    nativeBuildInputs = [ openjdk17 ];
+    dontUnpack = true;
+
+    buildPhase = ''
+      # Extract the JDK's JIMAGE and generate a list of modules.
+      mkdir modules
+      pushd modules
+      jimage extract ${openjdk17}/lib/openjdk/lib/modules
+      ls | xargs -d " " -- echo > ../manifest.txt
+      popd
+    '';
+
+    installPhase = ''
+      mkdir -p $out
+      cp manifest.txt $out/
+      cp -r modules/ $out/
+    '';
+  };
+
+  sparrow-modules = stdenv.mkDerivation {
+    pname = "sparrow-modules";
+    inherit version src;
+    nativeBuildInputs = [ makeWrapper gnugrep openjdk17 autoPatchelfHook stdenv.cc.cc.lib zlib ];
+
+    buildPhase = ''
+      # Extract Sparrow's JIMAGE and generate a list of them.
+      mkdir modules
+      pushd modules
+      jimage extract ../lib/runtime/lib/modules
+
+      # Delete JDK modules
+      cat ${jdk-modules}/manifest.txt | xargs -I {} -- rm -fR {}
+
+      # Delete unneeded native libs.
+
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/freebsd-x86-64
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/freebsd-x86
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/linux-aarch64
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/linux-arm
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/linux-armel
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/linux-mips64el
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/linux-ppc
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/linux-ppc64le
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/linux-s390x
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/linux-x86
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/openbsd-x86-64
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/openbsd-x86
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/sunos-sparc
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/sunos-sparcv9
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/sunos-x86-64
+      rm -fR com.sparrowwallet.merged.module/com/sun/jna/sunos-x86
+      rm -fR com.github.sarxos.webcam.capture/com/github/sarxos/webcam/ds/buildin/lib/linux_armel
+      rm -fR com.github.sarxos.webcam.capture/com/github/sarxos/webcam/ds/buildin/lib/linux_armhf
+      rm -fR com.github.sarxos.webcam.capture/com/github/sarxos/webcam/ds/buildin/lib/linux_x86
+      rm com.github.sarxos.webcam.capture/com/github/sarxos/webcam/ds/buildin/lib/linux_x64/OpenIMAJGrabber.so
+      rm -fR com.nativelibs4java.bridj/org/bridj/lib/linux_arm32_armel
+      rm -fR com.nativelibs4java.bridj/org/bridj/lib/linux_armel
+      rm -fR com.nativelibs4java.bridj/org/bridj/lib/linux_armhf
+      rm -fR com.nativelibs4java.bridj/org/bridj/lib/linux_x86
+      rm -fR com.nativelibs4java.bridj/org/bridj/lib/sunos_x64
+      rm -fR com.nativelibs4java.bridj/org/bridj/lib/sunos_x86
+      rm -fR com.sparrowwallet.merged.module/linux-aarch64
+      rm -fR com.sparrowwallet.merged.module/linux-arm
+      rm -fR com.sparrowwallet.merged.module/linux-x86
+      rm com.sparrowwallet.sparrow/native/linux/x64/hwi
+
+      ls | xargs -d " " -- echo > ../manifest.txt
+      find . | grep "\.so$" | xargs -- chmod ugo+x
+      popd
+
+      # Replace the embedded Tor binary (which is in a Tar archive)
+      # with one from Nixpkgs.
+      cp ${torWrapper} ./tor
+      tar -cJf tor.tar.xz tor
+      cp tor.tar.xz modules/netlayer.jpms/native/linux/x64/tor.tar.xz
+    '';
+
+    installPhase = ''
+      mkdir -p $out
+      cp manifest.txt $out/
+      cp -r modules/ $out/
+      ln -s ${openimajgrabber}/lib/OpenIMAJGrabber.so $out/modules/com.github.sarxos.webcam.capture/com/github/sarxos/webcam/ds/buildin/lib/linux_x64/OpenIMAJGrabber.so
+      ln -s ${hwi}/bin/hwi $out/modules/com.sparrowwallet.sparrow/native/linux/x64/hwi
+    '';
+  };
+
+  # To use the udev rules for connected hardware wallets,
+  # add "pkgs.sparrow" to "services.udev.packages" and add user accounts to the user group "plugdev".
+  udev-rules = stdenv.mkDerivation {
+    name = "sparrow-udev";
+
+    src = let version = "2.0.2"; in
+      fetchurl {
+        url = "https://github.com/bitcoin-core/HWI/releases/download/${version}/hwi-${version}.tar.gz";
+        sha256 = "sha256-di1fRsMbwpHcBFNTCVivfxpwhUoUKLA3YTnJxKq/jHM=";
+      };
+
+    installPhase = ''
+      mkdir -p $out/etc/udev/rules.d
+      cp -a hwilib/udev/* $out/etc/udev/rules.d
+      rm $out/etc/udev/rules.d/README.md
+    '';
+  };
+in
+stdenv.mkDerivation rec {
+  inherit pname version src;
+  nativeBuildInputs = [ makeWrapper copyDesktopItems ];
+
+  desktopItems = [
+    (makeDesktopItem {
+      name = "Sparrow";
+      exec = pname;
+      icon = pname;
+      desktopName = "Sparrow Bitcoin Wallet";
+      genericName = "Bitcoin Wallet";
+      categories = [ "Finance" ];
+    })
+  ];
+
+  sparrow-icons = stdenv.mkDerivation {
+    inherit version src;
+    pname = "sparrow-icons";
+    nativeBuildInputs = [ imagemagick ];
+
+    installPhase = ''
+      for n in 16 24 32 48 64 96 128 256; do
+        size=$n"x"$n
+        mkdir -p $out/hicolor/$size/apps
+        convert lib/Sparrow.png -resize $size $out/hicolor/$size/apps/sparrow.png
+        done;
+    '';
+  };
+
+  installPhase = ''
+    runHook preInstall
+
+    mkdir -p $out/bin $out
+    ln -s ${sparrow-modules}/modules $out/lib
+    install -D -m 777 ${launcher} $out/bin/sparrow
+    substituteAllInPlace $out/bin/sparrow
+    substituteInPlace $out/bin/sparrow --subst-var-by jdkModules ${jdk-modules}
+
+    mkdir -p $out/share/icons
+    ln -s ${sparrow-icons}/hicolor $out/share/icons
+
+    mkdir -p $out/etc/udev
+    ln -s ${udev-rules}/etc/udev/rules.d $out/etc/udev/rules.d
+
+    runHook postInstall
+  '';
+
+  meta = with lib; {
+    description = "A modern desktop Bitcoin wallet application supporting most hardware wallets and built on common standards such as PSBT, with an emphasis on transparency and usability.";
+    homepage = "https://sparrowwallet.com";
+    license = licenses.asl20;
+    maintainers = with maintainers; [ emmanuelrosa _1000101 ];
+    platforms = [ "x86_64-linux" ];
+  };
+}
diff --git a/pkgs/applications/blockchains/sparrow/openimajgrabber.nix b/pkgs/applications/blockchains/sparrow/openimajgrabber.nix
new file mode 100644
index 0000000000000..0bf642d49d1ca
--- /dev/null
+++ b/pkgs/applications/blockchains/sparrow/openimajgrabber.nix
@@ -0,0 +1,40 @@
+{ stdenv
+, lib
+, fetchFromGitHub
+, libv4l
+}:
+stdenv.mkDerivation rec {
+  pname = "openimajgrabber";
+  version = "1.3.10";
+
+  src = fetchFromGitHub {
+    owner = "openimaj";
+    repo = "openimaj";
+    rev = "openimaj-${version}";
+    sha256 = "sha256-Y8707ovE7f6Fk3cJ+PtwvzNpopgH5vlF55m2Xm4hjYM=";
+  };
+
+  buildInputs = [ libv4l ];
+
+  # These build instructions come from build.sh
+  buildPhase = ''
+    pushd hardware/core-video-capture/src-native/linux
+    g++ -fPIC -g -c OpenIMAJGrabber.cpp
+    g++ -fPIC -g -c capture.cpp
+    g++ -shared -Wl,-soname,OpenIMAJGrabber.so -o OpenIMAJGrabber.so OpenIMAJGrabber.o capture.o -lv4l2 -lrt -lv4lconvert
+    popd
+  '';
+
+  installPhase = ''
+    mkdir -p $out/lib
+    cp hardware/core-video-capture/src-native/linux/OpenIMAJGrabber.so $out/lib
+  '';
+
+  meta = with lib; {
+    description = "A collection of libraries and tools for multimedia (images, text, video, audio, etc.) content analysis and content generation. This package only builds the OpenIMAJGrabber for Linux.";
+    homepage = "http://www.openimaj.org";
+    license = licenses.bsd0;
+    maintainers = with maintainers; [ emmanuelrosa _1000101 ];
+    platforms = platforms.linux;
+  };
+}
diff --git a/pkgs/applications/emulators/box64/default.nix b/pkgs/applications/emulators/box64/default.nix
new file mode 100644
index 0000000000000..e383333c42086
--- /dev/null
+++ b/pkgs/applications/emulators/box64/default.nix
@@ -0,0 +1,66 @@
+{ lib
+, stdenv
+, fetchFromGitHub
+, cmake
+, python3
+}:
+
+stdenv.mkDerivation rec {
+  pname = "box64";
+  version = "0.1.8";
+
+  src = fetchFromGitHub {
+    owner = "ptitSeb";
+    repo = pname;
+    rev = "v${version}";
+    hash = "sha256-6k8Enbafnj19ATtgmw8W7LxtRpM3Ousj1bpZbbtq8TM=";
+  };
+
+  nativeBuildInputs = [
+    cmake
+    python3
+  ];
+
+  cmakeFlags = [
+    "-DNOGIT=1"
+  ] ++ (
+    if stdenv.hostPlatform.system == "aarch64-linux" then
+      [
+        "-DARM_DYNAREC=ON"
+      ]
+    else [
+      "-DLD80BITS=1"
+      "-DNOALIGN=1"
+    ]
+  );
+
+  installPhase = ''
+    runHook preInstall
+    install -Dm 0755 box64 "$out/bin/box64"
+    runHook postInstall
+  '';
+
+  doCheck = true;
+
+  checkPhase = ''
+    runHook preCheck
+    ctest
+    runHook postCheck
+  '';
+
+  doInstallCheck = true;
+
+  installCheckPhase = ''
+    runHook preInstallCheck
+    $out/bin/box64 -v
+    runHook postInstallCheck
+  '';
+
+  meta = with lib; {
+    homepage = "https://box86.org/";
+    description = "Lets you run x86_64 Linux programs on non-x86_64 Linux systems";
+    license = licenses.mit;
+    maintainers = with maintainers; [ gador ];
+    platforms = [ "x86_64-linux" "aarch64-linux" ];
+  };
+}
diff --git a/pkgs/applications/emulators/citra/default.nix b/pkgs/applications/emulators/citra/default.nix
index 31f5ebc3038ca..8b9f2cfd06908 100644
--- a/pkgs/applications/emulators/citra/default.nix
+++ b/pkgs/applications/emulators/citra/default.nix
@@ -1,93 +1,45 @@
-{ lib
-, stdenv
+{ branch
+, libsForQt5
 , fetchFromGitHub
-, cmake
-, wrapQtAppsHook
-, boost17x
-, pkg-config
-, libusb1
-, zstd
-, libressl
-, enableSdl2 ? true, SDL2
-, enableQt ? true, qtbase, qtmultimedia
-, enableQtTranslation ? enableQt, qttools
-, enableWebService ? true
-, enableCubeb ? true, libpulseaudio
-, enableFfmpegAudioDecoder ? true
-, enableFfmpegVideoDumper ? true
-, ffmpeg
-, useDiscordRichPresence ? true, rapidjson
-, enableFdk ? false, fdk_aac
+, fetchurl
 }:
-assert lib.assertMsg (!enableFfmpegAudioDecoder || !enableFdk) "Can't enable both enableFfmpegAudioDecoder and enableFdk";
 
-stdenv.mkDerivation {
-  pname = "citra";
-  version = "2021-11-01";
-
-  src = fetchFromGitHub {
-    owner = "citra-emu";
-    repo = "citra";
-    rev = "5a7d80172dd115ad9bc6e8e85cee6ed9511c48d0";
-    sha256 = "sha256-vy2JMizBsnRK9NBEZ1dxT7fP/HFhOZSsC+5P+Dzi27s=";
-    fetchSubmodules = true;
+let
+  # Fetched from https://api.citra-emu.org/gamedb, last updated 2022-05-02
+  # Please make sure to update this when updating citra!
+  compat-list = fetchurl {
+    name = "citra-compat-list";
+    url = "https://web.archive.org/web/20220502114622/https://api.citra-emu.org/gamedb/";
+    sha256 = "sha256-blIlaYaUQjw7Azgg+Dd7ZPEQf+ddZMO++Yxinwe+VG0=";
+  };
+in {
+  nightly = libsForQt5.callPackage ./generic.nix rec {
+    pname = "citra-nightly";
+    version = "1765";
+
+    src = fetchFromGitHub {
+      owner = "citra-emu";
+      repo = "citra-nightly";
+      rev = "nightly-${version}";
+      sha256 = "0d3dfh63cmsy5idbypdz3ibydmb4a35sfv7qmxxlcpc390pp9cvq";
+      fetchSubmodules = true;
+    };
+
+    inherit branch compat-list;
   };
 
-  nativeBuildInputs = [
-    cmake
-    pkg-config
-  ]
-  ++ lib.optionals enableQt [ wrapQtAppsHook ];
-
-  buildInputs = [
-    boost17x
-    libusb1
-  ]
-  ++ lib.optionals enableSdl2 [ SDL2 ]
-  ++ lib.optionals enableQt [ qtbase qtmultimedia ]
-  ++ lib.optionals enableQtTranslation [ qttools ]
-  ++ lib.optionals enableCubeb [ libpulseaudio ]
-  ++ lib.optionals (enableFfmpegAudioDecoder || enableFfmpegVideoDumper) [ ffmpeg ]
-  ++ lib.optionals useDiscordRichPresence [ rapidjson ]
-  ++ lib.optionals enableFdk [ fdk_aac ];
-
-  cmakeFlags = [
-    "-DUSE_SYSTEM_BOOST=ON"
-  ]
-  ++ lib.optionals (!enableSdl2) [ "-DENABLE_SDL2=OFF" ]
-  ++ lib.optionals (!enableQt) [ "-DENABLE_QT=OFF" ]
-  ++ lib.optionals enableQtTranslation [ "-DENABLE_QT_TRANSLATION=ON" ]
-  ++ lib.optionals (!enableWebService) [ "-DENABLE_WEB_SERVICE=OFF" ]
-  ++ lib.optionals (!enableCubeb) [ "-DENABLE_CUBEB=OFF" ]
-  ++ lib.optionals enableFfmpegAudioDecoder [ "-DENABLE_FFMPEG_AUDIO_DECODER=ON"]
-  ++ lib.optionals enableFfmpegVideoDumper [ "-DENABLE_FFMPEG_VIDEO_DUMPER=ON" ]
-  ++ lib.optionals useDiscordRichPresence [ "-DUSE_DISCORD_PRESENCE=ON" ]
-  ++ lib.optionals enableFdk [ "-DENABLE_FDK=ON" ];
-
-  postPatch = ''
-    # We already know the submodules are present
-    substituteInPlace CMakeLists.txt \
-      --replace "check_submodules_present()" ""
-
-    # Devendoring
-    rm -rf externals/zstd externals/libressl
-    cp -r ${zstd.src} externals/zstd
-    tar xf ${libressl.src} -C externals/
-    mv externals/${libressl.name} externals/libressl
-    chmod -R a+w externals/zstd
-  '';
+  canary = libsForQt5.callPackage ./generic.nix rec {
+    pname = "citra-canary";
+    version = "2146";
 
-  # Fixes https://github.com/NixOS/nixpkgs/issues/171173
-  postInstall = lib.optionalString (enableCubeb && enableSdl2) ''
-    wrapProgram "$out/bin/citra" \
-      --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ libpulseaudio ]}
-  '';
+    src = fetchFromGitHub {
+      owner = "citra-emu";
+      repo = "citra-canary";
+      rev = "canary-${version}";
+      sha256 = "1wnym0nklngimf5gaaa2703nz4g5iy572wlgp88h67rrh9b4f04r";
+      fetchSubmodules = true;
+    };
 
-  meta = with lib; {
-    homepage = "https://citra-emu.org";
-    description = "An open-source emulator for the Nintendo 3DS";
-    license = licenses.gpl2;
-    maintainers = with maintainers; [ abbradar ];
-    platforms = platforms.linux;
+    inherit branch compat-list;
   };
-}
+}.${branch}
diff --git a/pkgs/applications/emulators/citra/generic.nix b/pkgs/applications/emulators/citra/generic.nix
new file mode 100644
index 0000000000000..8a3c20c664cfc
--- /dev/null
+++ b/pkgs/applications/emulators/citra/generic.nix
@@ -0,0 +1,107 @@
+{ pname
+, version
+, src
+, branch
+, compat-list
+
+, lib
+, stdenv
+, fetchFromGitHub
+, cmake
+, boost17x
+, pkg-config
+, libusb1
+, zstd
+, libressl
+, enableSdl2 ? true, SDL2
+, enableQt ? true, qtbase, qtmultimedia, wrapQtAppsHook
+, enableQtTranslation ? enableQt, qttools
+, enableWebService ? true
+, enableCubeb ? true, libpulseaudio
+, enableFfmpegAudioDecoder ? true
+, enableFfmpegVideoDumper ? true
+, ffmpeg
+, useDiscordRichPresence ? true, rapidjson
+, enableFdk ? false, fdk_aac
+}:
+assert lib.assertMsg (!enableFfmpegAudioDecoder || !enableFdk) "Can't enable both enableFfmpegAudioDecoder and enableFdk";
+
+stdenv.mkDerivation rec {
+  inherit pname version src;
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+  ] ++ lib.optionals enableQt [ wrapQtAppsHook ];
+
+  buildInputs = [
+    boost17x
+    libusb1
+  ] ++ lib.optionals enableQt [ qtbase qtmultimedia ]
+    ++ lib.optional enableSdl2 SDL2
+    ++ lib.optional enableQtTranslation qttools
+    ++ lib.optional enableCubeb libpulseaudio
+    ++ lib.optional (enableFfmpegAudioDecoder || enableFfmpegVideoDumper) ffmpeg
+    ++ lib.optional useDiscordRichPresence rapidjson
+    ++ lib.optional enableFdk fdk_aac;
+
+  cmakeFlags = [
+    "-DUSE_SYSTEM_BOOST=ON"
+    "-DCITRA_USE_BUNDLED_FFMPEG=OFF"
+    "-DCITRA_USE_BUNDLED_QT=OFF"
+    "-DCITRA_USE_BUNDLED_SDL2=OFF"
+
+    # We dont want to bother upstream with potentially outdated compat reports
+    "-DCITRA_ENABLE_COMPATIBILITY_REPORTING=ON"
+    "-DENABLE_COMPATIBILITY_LIST_DOWNLOAD=OFF" # We provide this deterministically
+  ] ++ lib.optional (!enableSdl2) "-DENABLE_SDL2=OFF"
+    ++ lib.optional (!enableQt) "-DENABLE_QT=OFF"
+    ++ lib.optional enableQtTranslation "-DENABLE_QT_TRANSLATION=ON"
+    ++ lib.optional (!enableWebService) "-DENABLE_WEB_SERVICE=OFF"
+    ++ lib.optional (!enableCubeb) "-DENABLE_CUBEB=OFF"
+    ++ lib.optional enableFfmpegAudioDecoder "-DENABLE_FFMPEG_AUDIO_DECODER=ON"
+    ++ lib.optional enableFfmpegVideoDumper "-DENABLE_FFMPEG_VIDEO_DUMPER=ON"
+    ++ lib.optional useDiscordRichPresence "-DUSE_DISCORD_PRESENCE=ON"
+    ++ lib.optional enableFdk "-DENABLE_FDK=ON";
+
+  postPatch = ''
+    # Prep compatibilitylist
+    ln -s ${compat-list} ./dist/compatibility_list/compatibility_list.json
+
+    # We already know the submodules are present
+    substituteInPlace CMakeLists.txt \
+      --replace "check_submodules_present()" ""
+
+    # Devendoring
+    rm -rf externals/zstd externals/libressl
+    cp -r ${zstd.src} externals/zstd
+    tar xf ${libressl.src} -C externals/
+    mv externals/${libressl.name} externals/libressl
+    chmod -R a+w externals/zstd
+  '';
+
+  # Fixes https://github.com/NixOS/nixpkgs/issues/171173
+  postInstall = lib.optionalString (enableCubeb && enableSdl2) ''
+    wrapProgram "$out/bin/citra" \
+      --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ libpulseaudio ]}
+  '';
+
+  meta = with lib; {
+    homepage = "https://citra-emu.org";
+    description = "The ${branch} branch of an open-source emulator for the Ninteno 3DS";
+    longDescription = ''
+      A Nintendo 3DS Emulator written in C++
+      Using the nightly branch is recommended for general usage.
+      Using the canary branch is recommended if you would like to try out
+      experimental features, with a cost of stability.
+    '';
+    mainProgram = if enableQt then "citra-qt" else "citra";
+    platforms = platforms.linux;
+    license = licenses.gpl2Plus;
+    maintainers = with maintainers; [
+      abbradar
+      ashley
+      ivar
+    ];
+  };
+}
diff --git a/pkgs/applications/emulators/citra/update.sh b/pkgs/applications/emulators/citra/update.sh
new file mode 100755
index 0000000000000..eec36818fede2
--- /dev/null
+++ b/pkgs/applications/emulators/citra/update.sh
@@ -0,0 +1,84 @@
+#! /usr/bin/env nix-shell
+#! nix-shell -i bash -p nix nix-prefetch-git coreutils curl jq gnused
+
+set -euo pipefail
+
+# Will be replaced with the actual branch when running this from passthru.updateScript
+BRANCH="@branch@"
+
+if [[ ! "$(basename $PWD)" = "citra" ]]; then
+    echo "error: Script must be ran from citra's directory!"
+    exit 1
+fi
+
+getLocalVersion() {
+    pushd ../../../.. >/dev/null
+    nix eval --raw -f default.nix "$1".version
+    popd >/dev/null
+}
+
+getLocalHash() {
+    pushd ../../../.. >/dev/null
+    nix eval --raw -f default.nix "$1".src.drvAttrs.outputHash
+    popd >/dev/null
+}
+
+updateNightly() {
+    OLD_NIGHTLY_VERSION="$(getLocalVersion "citra-nightly")"
+    OLD_NIGHTLY_HASH="$(getLocalHash "citra-nightly")"
+
+    NEW_NIGHTLY_VERSION="$(curl -s ${GITHUB_TOKEN:+"-u \":$GITHUB_TOKEN\""} \
+        "https://api.github.com/repos/citra-emu/citra-nightly/releases?per_page=1" | jq -r '.[0].name' | cut -d"-" -f2 | cut -d" " -f2)"
+
+    if [[ "${OLD_NIGHTLY_VERSION}" = "${NEW_NIGHTLY_VERSION}" ]]; then
+        echo "citra-nightly is already up to date!"
+
+        [ "$KEEP_GOING" ] && return || exit
+    else
+        echo "citra-nightly: ${OLD_NIGHTLY_VERSION} -> ${NEW_NIGHTLY_VERSION}"
+    fi
+
+    echo "  Fetching source code..."
+
+    NEW_NIGHTLY_HASH="$(nix-prefetch-git --quiet --fetch-submodules --rev "nightly-${NEW_NIGHTLY_VERSION}" "https://github.com/citra-emu/citra-nightly" | jq -r '.sha256')"
+
+    echo "  Succesfully fetched. hash: ${NEW_NIGHTLY_HASH}"
+
+    sed -i "s/${OLD_NIGHTLY_VERSION}/${NEW_NIGHTLY_VERSION}/" ./default.nix
+    sed -i "s/${OLD_NIGHTLY_HASH}/${NEW_NIGHTLY_HASH}/" ./default.nix
+}
+
+updateCanary() {
+    OLD_CANARY_VERSION="$(getLocalVersion "citra-canary")"
+    OLD_CANARY_HASH="$(getLocalHash "citra-canary")"
+
+    NEW_CANARY_VERSION="$(curl -s ${GITHUB_TOKEN:+"-u \":$GITHUB_TOKEN\""} \
+        "https://api.github.com/repos/citra-emu/citra-canary/releases?per_page=1" | jq -r '.[0].name' | cut -d"-" -f2 | cut -d" " -f1)"
+
+    if [[ "${OLD_CANARY_VERSION}" = "${NEW_CANARY_VERSION}" ]]; then
+        echo "citra-canary is already up to date!"
+
+        [ "$KEEP_GOING" ] && return || exit
+    else
+        echo "citra-canary: ${OLD_CANARY_VERSION} -> ${NEW_CANARY_VERSION}"
+    fi
+
+    echo "  Fetching source code..."
+
+    NEW_CANARY_HASH="$(nix-prefetch-git --quiet --fetch-submodules --rev "canary-${NEW_CANARY_VERSION}" "https://github.com/citra-emu/citra-canary" | jq -r '.sha256')"
+
+    echo "  Succesfully fetched. hash: ${NEW_CANARY_HASH}"
+
+    sed -i "s/${OLD_CANARY_VERSION}/${NEW_CANARY_VERSION}/" ./default.nix
+    sed -i "s/${OLD_CANARY_HASH}/${NEW_CANARY_HASH}/" ./default.nix
+}
+
+if [[ "$BRANCH" = "nightly" ]]; then
+    updateNightly
+elif [[ "$BRANCH" = "early-access" ]]; then
+    updateCanary
+else
+    KEEP_GOING=1
+    updateNightly
+    updateCanary
+fi
diff --git a/pkgs/applications/misc/pgmodeler/default.nix b/pkgs/applications/misc/pgmodeler/default.nix
index 0a99d357e68f4..93d5d74ac731c 100644
--- a/pkgs/applications/misc/pgmodeler/default.nix
+++ b/pkgs/applications/misc/pgmodeler/default.nix
@@ -10,13 +10,13 @@
 
 mkDerivation rec {
   pname = "pgmodeler";
-  version = "0.9.3";
+  version = "0.9.4";
 
   src = fetchFromGitHub {
     owner = "pgmodeler";
     repo = "pgmodeler";
     rev = "v${version}";
-    sha256 = "1bci5x418dbnkny7hn0b5q5lxyajrgl3frv41ji0hcw9vivrds2g";
+    sha256 = "sha256-FwLPhIc2ofaB8Z2ZUYMFFt5XdoosEfEOwoIaI7pSxa0=";
   };
 
   nativeBuildInputs = [ pkg-config qmake ];
diff --git a/pkgs/development/compilers/gcc/10/default.nix b/pkgs/development/compilers/gcc/10/default.nix
index 88d4831812fdf..82269a395fee2 100644
--- a/pkgs/development/compilers/gcc/10/default.nix
+++ b/pkgs/development/compilers/gcc/10/default.nix
@@ -3,6 +3,7 @@
 , langAda ? false
 , langObjC ? stdenv.targetPlatform.isDarwin
 , langObjCpp ? stdenv.targetPlatform.isDarwin
+, langD ? false
 , langGo ? false
 , reproducibleBuild ? true
 , profiledCompiler ? false
@@ -65,6 +66,7 @@ let majorVersion = "10";
         sha256 = ""; # TODO: uncomment and check hash when available.
       }) */
       ++ optional langAda ../gnat-cflags.patch
+      ++ optional langD ../libphobos.patch
       ++ optional langFortran ../gfortran-driving.patch
       ++ optional (targetPlatform.libc == "musl" && targetPlatform.isPower) ../ppc-musl.patch
 
@@ -214,6 +216,7 @@ stdenv.mkDerivation ({
       enableShared
 
       langC
+      langD
       langCC
       langFortran
       langAda
@@ -254,14 +257,14 @@ stdenv.mkDerivation ({
 
   inherit
     (import ../common/extra-target-flags.nix {
-      inherit lib stdenv crossStageStatic libcCross threadsCross;
+      inherit lib stdenv crossStageStatic langD libcCross threadsCross;
     })
     EXTRA_FLAGS_FOR_TARGET
     EXTRA_LDFLAGS_FOR_TARGET
     ;
 
   passthru = {
-    inherit langC langCC langObjC langObjCpp langAda langFortran langGo version;
+    inherit langC langCC langObjC langObjCpp langAda langFortran langGo langD version;
     isGNU = true;
   };
 
diff --git a/pkgs/development/python-modules/lektor/default.nix b/pkgs/development/python-modules/lektor/default.nix
index 4688b7394cc33..0c0c5c108a46a 100644
--- a/pkgs/development/python-modules/lektor/default.nix
+++ b/pkgs/development/python-modules/lektor/default.nix
@@ -62,7 +62,6 @@ buildPythonPackage rec {
   checkInputs = [
     pytest-click
     pytest-mock
-    pytest-pylint
     pytestCheckHook
   ];
 
diff --git a/pkgs/development/python-modules/mkdocs-drawio-exporter/default.nix b/pkgs/development/python-modules/mkdocs-drawio-exporter/default.nix
new file mode 100644
index 0000000000000..9d95d72fee772
--- /dev/null
+++ b/pkgs/development/python-modules/mkdocs-drawio-exporter/default.nix
@@ -0,0 +1,33 @@
+{ buildPythonPackage
+, drawio-headless
+, fetchPypi
+, isPy3k
+, lib
+, mkdocs
+}:
+
+buildPythonPackage rec {
+  pname = "mkdocs-drawio-exporter";
+  version = "0.8.0";
+
+  disabled = !isPy3k;
+
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "sha256-9cvA186FS6bHmpOrv4OfPZ5kRfgfafBfaWxgWJIlwwA=";
+  };
+
+  propagatedBuildInputs = [ mkdocs drawio-headless ];
+
+  pythonImportsCheck = [ "mkdocsdrawioexporter" ];
+
+  meta = with lib; {
+    description = "Exports your Draw.io diagrams at build time for easier embedding into your documentation.";
+    homepage = "https://github.com/LukeCarrier/mkdocs-drawio-exporter/";
+    license = licenses.mit;
+    maintainers = with maintainers; [ snpschaaf ];
+    longDescription = ''
+      Exports your Draw.io diagrams at build time for easier embedding into your documentation.
+    '';
+  };
+}
diff --git a/pkgs/development/python-modules/pamqp/default.nix b/pkgs/development/python-modules/pamqp/default.nix
index 1785a8593102b..a367a180807d0 100644
--- a/pkgs/development/python-modules/pamqp/default.nix
+++ b/pkgs/development/python-modules/pamqp/default.nix
@@ -1,28 +1,46 @@
 { lib
 , buildPythonPackage
-, fetchPypi
-, mock
-, nose
-, pep8
-, pylint
-, mccabe
+, pythonOlder
+, fetchFromGitHub
+, pytestCheckHook
 }:
 
 buildPythonPackage rec {
   version = "3.1.0";
   pname = "pamqp";
 
-  src = fetchPypi {
-    inherit pname version;
-    sha256 = "e4f0886d72c6166637a5513626148bf5a7e818073a558980e9aaed8b4ccf30da";
+  disabled = pythonOlder "3.7";
+
+  format = "setuptools";
+
+  src = fetchFromGitHub {
+    owner = "gmr";
+    repo = "pamqp";
+    rev = version;
+    hash = "sha256-qiYfQsyYvG6pyRFDt3pyYKNNWNP88maj+VAeGD68OmY=";
   };
 
-  buildInputs = [ mock nose pep8 pylint mccabe ];
+  checkInputs = [
+    pytestCheckHook
+  ];
+
+  pythonImportsCheck = [
+    "pamqp.base"
+    "pamqp.body"
+    "pamqp.commands"
+    "pamqp.common"
+    "pamqp.decode"
+    "pamqp.encode"
+    "pamqp.exceptions"
+    "pamqp.frame"
+    "pamqp.header"
+    "pamqp.heartbeat"
+  ];
 
   meta = with lib; {
     description = "RabbitMQ Focused AMQP low-level library";
-    homepage = "https://pypi.python.org/pypi/pamqp";
+    homepage = "https://github.com/gmr/pamqp";
     license = licenses.bsd3;
+    maintainers = with maintainers; [ dotlambda ];
   };
-
 }
diff --git a/pkgs/development/python-modules/pulumi-aws/default.nix b/pkgs/development/python-modules/pulumi-aws/default.nix
new file mode 100644
index 0000000000000..1b6eed0d31a63
--- /dev/null
+++ b/pkgs/development/python-modules/pulumi-aws/default.nix
@@ -0,0 +1,44 @@
+{ lib
+, buildPythonPackage
+, fetchFromGitHub
+, fetchpatch
+, pulumi
+, parver
+, semver
+, isPy27
+}:
+
+buildPythonPackage rec {
+  pname = "pulumi-aws";
+  # version is independant of pulumi's.
+  version = "5.3.0";
+  disabled = isPy27;
+
+  src = fetchFromGitHub {
+    owner = "pulumi";
+    repo = "pulumi-aws";
+    rev = "v${version}";
+    sha256 = "sha256-LrWiNYJeQQvXJDOxklRO86VSiaadvkOepQVPhh2BBkk=";
+  };
+
+  propagatedBuildInputs = [
+    pulumi
+    parver
+    semver
+  ];
+
+  postPatch = ''
+    cd sdk/python
+  '';
+
+  # checks require cloud resources
+  doCheck = false;
+  pythonImportsCheck = ["pulumi_aws"];
+
+  meta = with lib; {
+    description = "Pulumi python amazon web services provider";
+    homepage = "https://github.com/pulumi/pulumi-aws";
+    license = licenses.asl20;
+    maintainers = with maintainers; [ costrouc ];
+  };
+}
diff --git a/pkgs/development/python-modules/pulumi/default.nix b/pkgs/development/python-modules/pulumi/default.nix
new file mode 100644
index 0000000000000..e38157c69071c
--- /dev/null
+++ b/pkgs/development/python-modules/pulumi/default.nix
@@ -0,0 +1,89 @@
+{ lib
+, buildPythonPackage
+, fetchpatch
+, fetchFromGitHub
+, protobuf
+, dill
+, grpcio
+, pulumi-bin
+, isPy27
+, semver
+, pyyaml
+, six
+
+
+# for tests
+, tox
+, go
+, pulumictl
+, bash
+, pylint
+, pytest
+, pytest-timeout
+, coverage
+, black
+, wheel
+, pytest-asyncio
+
+, mypy
+}:
+let
+  data = import ./data.nix {};
+in
+buildPythonPackage rec {
+  pname = "pulumi";
+  version = pulumi-bin.version;
+  disabled = isPy27;
+
+  src = fetchFromGitHub {
+    owner = "pulumi";
+    repo = "pulumi";
+    rev = "v${pulumi-bin.version}";
+    sha256 = "sha256-vqEZEHTpJV65a3leWwYhyi3dzAsN67BXOvk5hnTPeuI=";
+  };
+
+  propagatedBuildInputs = [
+    semver
+    protobuf
+    dill
+    grpcio
+    pyyaml
+    six
+  ];
+
+  checkInputs = [
+    pulumi-bin
+    pulumictl
+    mypy
+    bash
+    go
+    tox
+    pytest
+    pytest-timeout
+    coverage
+    pytest-asyncio
+    wheel
+    black
+  ];
+
+  pythonImportsCheck = ["pulumi"];
+
+  postPatch = ''
+    cp README.md sdk/python/lib
+    patchShebangs .
+    cd sdk/python/lib
+
+    substituteInPlace setup.py \
+      --replace "{VERSION}" "${version}"
+  '';
+
+  # disabled because tests try to fetch go packages from the net
+  doCheck = false;
+
+  meta = with lib; {
+    description = "Modern Infrastructure as Code. Any cloud, any language";
+    homepage = "https://github.com/pulumi/pulumi";
+    license = licenses.asl20;
+    maintainers = with maintainers; [ teto ];
+  };
+}
diff --git a/pkgs/development/python-modules/pytile/default.nix b/pkgs/development/python-modules/pytile/default.nix
index a94201b037d47..b64418226d060 100644
--- a/pkgs/development/python-modules/pytile/default.nix
+++ b/pkgs/development/python-modules/pytile/default.nix
@@ -4,7 +4,6 @@
 , buildPythonPackage
 , fetchFromGitHub
 , poetry-core
-, pylint
 , pytest-aiohttp
 , pytest-asyncio
 , pytestCheckHook
@@ -31,7 +30,6 @@ buildPythonPackage rec {
 
   propagatedBuildInputs = [
     aiohttp
-    pylint
   ];
 
   checkInputs = [
diff --git a/pkgs/os-specific/linux/apfs/default.nix b/pkgs/os-specific/linux/apfs/default.nix
index eedaa9ef96872..44cfefe680882 100644
--- a/pkgs/os-specific/linux/apfs/default.nix
+++ b/pkgs/os-specific/linux/apfs/default.nix
@@ -1,6 +1,7 @@
 { lib
 , stdenv
 , fetchFromGitHub
+, fetchpatch
 , kernel
 }:
 
@@ -15,6 +16,15 @@ stdenv.mkDerivation {
     sha256 = "sha256-3T1BNc6g3SDTxb0VrronLUIp/CWbwnzXTsc8Qk5c4jY=";
   };
 
+  patches = [
+    # Fix build for Linux 5.18+.
+    # https://github.com/linux-apfs/linux-apfs-rw/pull/24
+    (fetchpatch {
+      url = "https://github.com/linux-apfs/linux-apfs-rw/commit/93b93767acab614c4e6426c9fd38bdf9af00bc13.patch";
+      sha256 = "1ss7cal851qadcmkn3jcckpa2f003nzb03xsx1g8vkb1cl0n8gi7";
+    })
+  ];
+
   hardeningDisable = [ "pic" ];
   nativeBuildInputs = kernel.moduleBuildDependencies;
 
diff --git a/pkgs/os-specific/linux/systemd/default.nix b/pkgs/os-specific/linux/systemd/default.nix
index 14d5e29c372a8..dad537a1564dd 100644
--- a/pkgs/os-specific/linux/systemd/default.nix
+++ b/pkgs/os-specific/linux/systemd/default.nix
@@ -688,7 +688,7 @@ stdenv.mkDerivation {
     # runtime; otherwise we can't and we need to reboot.
     interfaceVersion = 2;
 
-    inherit withCryptsetup util-linux kmod kbd;
+    inherit withCryptsetup withHostnamed withImportd withLocaled withMachined withTimedated util-linux kmod kbd;
 
     tests = {
       inherit (nixosTests) switchTest;
diff --git a/pkgs/os-specific/linux/zenpower/default.nix b/pkgs/os-specific/linux/zenpower/default.nix
index f3f6e420a2a29..1ba01a1c88fbd 100644
--- a/pkgs/os-specific/linux/zenpower/default.nix
+++ b/pkgs/os-specific/linux/zenpower/default.nix
@@ -2,13 +2,13 @@
 
 stdenv.mkDerivation rec {
   pname = "zenpower";
-  version = "0.1.13";
+  version = "unstable-2022-04-13";
 
   src = fetchFromGitHub {
     owner = "Ta180m";
     repo = "zenpower3";
-    rev = "v${version}";
-    sha256 = "sha256-2QScHDwOKN3Psui0M2s2p6D97jjbfe3Us5Nkn2srKC0=";
+    rev = "c36a86c64b802e9b90b5166caee6a8e8eddaeb56";
+    sha256 = "1i9ap7xgab421f3c68mcmad25xs4h8pfz0g0f9yzg7hxpmb0npxi";
   };
 
   hardeningDisable = [ "pic" ];
@@ -24,7 +24,7 @@ stdenv.mkDerivation rec {
   meta = with lib; {
     description = "Linux kernel driver for reading temperature, voltage(SVI2), current(SVI2) and power(SVI2) for AMD Zen family CPUs.";
     homepage = "https://github.com/Ta180m/zenpower3";
-    license = licenses.gpl2;
+    license = licenses.gpl2Plus;
     maintainers = with maintainers; [ alexbakker artturin ];
     platforms = [ "x86_64-linux" ];
     broken = versionOlder kernel.version "4.14";
diff --git a/pkgs/servers/home-assistant/default.nix b/pkgs/servers/home-assistant/default.nix
index ff5c69b04fb8e..b23b9bc32520a 100644
--- a/pkgs/servers/home-assistant/default.nix
+++ b/pkgs/servers/home-assistant/default.nix
@@ -282,9 +282,6 @@ in python.pkgs.buildPythonApplication rec {
     respx
     stdlib-list
     tqdm
-    # required by tests/pylint
-    astroid
-    pylint
     # required by tests/auth/mfa_modules
     pyotp
   ] ++ lib.concatMap (component: getPackages component python.pkgs) [
@@ -308,6 +305,8 @@ in python.pkgs.buildPythonApplication rec {
   ];
 
   disabledTestPaths = [
+    # we don't care about code quality
+    "tests/pylint"
     # don't bulk test all components
     "tests/components"
     # pyotp since v2.4.0 complains about the short mock keys, hass pins v2.3.0
diff --git a/pkgs/tools/admin/pulumi/update-pulumi-shell.nix b/pkgs/tools/admin/pulumi/update-pulumi-shell.nix
new file mode 100644
index 0000000000000..cf69e640550d4
--- /dev/null
+++ b/pkgs/tools/admin/pulumi/update-pulumi-shell.nix
@@ -0,0 +1,8 @@
+{ nixpkgs ? import ../../../.. { } }:
+with nixpkgs;
+mkShell {
+  packages = [
+    pkgs.gh
+  ];
+}
+
diff --git a/pkgs/tools/admin/pulumi/update.sh b/pkgs/tools/admin/pulumi/update.sh
index fadc64cf1dfef..1097759c3bd6d 100755
--- a/pkgs/tools/admin/pulumi/update.sh
+++ b/pkgs/tools/admin/pulumi/update.sh
@@ -1,5 +1,5 @@
 #!/usr/bin/env nix-shell
-#!nix-shell -i bash -p gh
+#!nix-shell update-pulumi-shell.nix -i bash
 # shellcheck shell=bash
 # Bash 3 compatible for Darwin
 
diff --git a/pkgs/tools/networking/isync/default.nix b/pkgs/tools/networking/isync/default.nix
index e26526dc68d57..8e21ccee10847 100644
--- a/pkgs/tools/networking/isync/default.nix
+++ b/pkgs/tools/networking/isync/default.nix
@@ -29,5 +29,6 @@ stdenv.mkDerivation rec {
     license = licenses.gpl2Plus;
     platforms = platforms.unix;
     maintainers = with maintainers; [ primeos lheckemann ];
+    mainProgram = "mbsync";
   };
 }
diff --git a/pkgs/top-level/aliases.nix b/pkgs/top-level/aliases.nix
index bb88c91d1c870..8d5f06f4fbbe6 100644
--- a/pkgs/top-level/aliases.nix
+++ b/pkgs/top-level/aliases.nix
@@ -170,6 +170,7 @@ mapAliases ({
   chunkwm = throw "chunkwm has been removed: abandoned by upstream"; # Added 2022-01-07
   cifs_utils = throw "'cifs_utils' has been renamed to/replaced by 'cifs-utils'"; # Converted to throw 2022-02-22
   cipherscan = throw "cipherscan was removed from nixpkgs, as it was unmaintained"; # added 2021-12-11
+  citra = citra-nightly; # added 2022-05-17
   ckb = throw "'ckb' has been renamed to/replaced by 'ckb-next'"; # Converted to throw 2022-02-22
   inherit (libsForQt5.mauiPackages) clip; # added 2022-05-17
   cpp-ipfs-api = cpp-ipfs-http-client; # Project has been renamed. Added 2022-05-15
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index f46e86606e3a6..a7657a14ba03d 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -1255,6 +1255,8 @@ with pkgs;
     wxGTK = wxGTK30;
   };
 
+  box64 = callPackage ../applications/emulators/box64 { };
+
   caprice32 = callPackage ../applications/emulators/caprice32 { };
 
   ccemux = callPackage ../applications/emulators/ccemux { };
@@ -1265,7 +1267,13 @@ with pkgs;
 
   cen64 = callPackage ../applications/emulators/cen64 { };
 
-  citra = libsForQt5.callPackage ../applications/emulators/citra { };
+  citra-canary = callPackage ../applications/emulators/citra {
+    branch = "canary";
+  };
+
+  citra-nightly = callPackage ../applications/emulators/citra {
+    branch = "nightly";
+  };
 
   collapseos-cvm = callPackage ../applications/emulators/collapseos-cvm { };
 
@@ -10443,6 +10451,10 @@ with pkgs;
 
   sozu = callPackage ../servers/sozu { };
 
+  sparrow = callPackage ../applications/blockchains/sparrow {
+    openimajgrabber = callPackage ../applications/blockchains/sparrow/openimajgrabber.nix {};
+  };
+
   sparsehash = callPackage ../development/libraries/sparsehash { };
 
   spectre-meltdown-checker = callPackage ../tools/security/spectre-meltdown-checker { };
diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix
index dd21231dfecd0..a93482bb7842b 100644
--- a/pkgs/top-level/python-packages.nix
+++ b/pkgs/top-level/python-packages.nix
@@ -1105,6 +1105,10 @@ in {
 
   babelgladeextractor = callPackage ../development/python-modules/babelgladeextractor { };
 
+  pulumi = callPackage ../development/python-modules/pulumi { };
+
+  pulumi-aws = callPackage ../development/python-modules/pulumi-aws { };
+
   backcall = callPackage ../development/python-modules/backcall { };
 
   backoff = callPackage ../development/python-modules/backoff { };
@@ -5329,6 +5333,7 @@ in {
   mizani = callPackage ../development/python-modules/mizani { };
 
   mkdocs = callPackage ../development/python-modules/mkdocs { };
+  mkdocs-drawio-exporter = callPackage ../development/python-modules/mkdocs-drawio-exporter { };
   mkdocs-material = callPackage ../development/python-modules/mkdocs-material { };
   mkdocs-material-extensions = callPackage ../development/python-modules/mkdocs-material/mkdocs-material-extensions.nix { };
   mkdocs-minify = callPackage ../development/python-modules/mkdocs-minify { };