about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRyan Lahfa <masterancpp@gmail.com>2024-05-12 16:28:36 +0200
committerGitHub <noreply@github.com>2024-05-12 16:28:36 +0200
commitdf0bced72574a24e004018e9a50b98f87a01b202 (patch)
tree7425e1fdce3c79451e835b32c9aac7b8022dc498
parent3545243f10c0c3f4194a03bc2795a04401d3343a (diff)
parent3388179c48fa673ae466f12d15cd7864b8e7cd3c (diff)
Merge pull request #310194 from RaitoBezarius/lix
lix: init at 2.90-beta.1
-rw-r--r--maintainers/team-list.nix10
-rw-r--r--nixos/tests/misc.nix340
-rw-r--r--pkgs/tools/package-management/lix/common.nix286
-rw-r--r--pkgs/tools/package-management/lix/default.nix60
-rw-r--r--pkgs/tools/package-management/lix/doc/default.nix12
-rw-r--r--pkgs/top-level/all-packages.nix10
6 files changed, 557 insertions, 161 deletions
diff --git a/maintainers/team-list.nix b/maintainers/team-list.nix
index 2a50f6f98d095..8b609bce4f269 100644
--- a/maintainers/team-list.nix
+++ b/maintainers/team-list.nix
@@ -723,6 +723,16 @@ with lib.maintainers; {
     enableFeatureFreezePing = true;
   };
 
+  lix = {
+    members = [
+      raitobezarius
+      qyriad
+    ];
+    scope = "Maintain the Lix package manager inside of Nixpkgs.";
+    shortName = "Lix ecosystem";
+    enableFeatureFreezePing = true;
+  };
+
   module-system = {
     members = [
       infinisil
diff --git a/nixos/tests/misc.nix b/nixos/tests/misc.nix
index e7842debba7a2..aa9b9fbe29a52 100644
--- a/nixos/tests/misc.nix
+++ b/nixos/tests/misc.nix
@@ -1,164 +1,182 @@
 # Miscellaneous small tests that don't warrant their own VM run.
-
-import ./make-test-python.nix ({ lib, pkgs, ...} : let
-  foo = pkgs.writeText "foo" "Hello World";
-in {
-  name = "misc";
-  meta.maintainers = with lib.maintainers; [ eelco ];
-
-  nodes.machine =
-    { lib, ... }:
-    { swapDevices = lib.mkOverride 0
-        [ { device = "/root/swapfile"; size = 128; } ];
-      environment.variables.EDITOR = lib.mkOverride 0 "emacs";
-      documentation.nixos.enable = lib.mkOverride 0 true;
-      systemd.tmpfiles.rules = [ "d /tmp 1777 root root 10d" ];
-      systemd.tmpfiles.settings."10-test"."/tmp/somefile".d = {};
-      virtualisation.fileSystems = { "/tmp2" =
-        { fsType = "tmpfs";
-          options = [ "mode=1777" "noauto" ];
-        };
-        # Tests https://discourse.nixos.org/t/how-to-make-a-derivations-executables-have-the-s-permission/8555
-        "/user-mount/point" = {
-          device = "/user-mount/source";
-          fsType = "none";
-          options = [ "bind" "rw" "user" "noauto" ];
-        };
-        "/user-mount/denied-point" = {
-          device = "/user-mount/denied-source";
-          fsType = "none";
-          options = [ "bind" "rw" "noauto" ];
+{ pkgs, ... }:
+
+let
+  inherit (pkgs) lib;
+  tests = {
+    default = testsForPackage { nixPackage = pkgs.nix; };
+    lix = testsForPackage { nixPackage = pkgs.lix; };
+  };
+
+  testsForPackage = args: lib.recurseIntoAttrs {
+    miscFeatures = testMiscFeatures args;
+    passthru.override = args': testsForPackage (args // args');
+  };
+
+  testMiscFeatures = { nixPackage, ... }: pkgs.testers.nixosTest (
+  let
+    foo = pkgs.writeText "foo" "Hello World";
+  in {
+    name = "misc";
+    meta.maintainers = with lib.maintainers; [ raitobezarius ];
+
+    nodes.machine =
+      { lib, ... }:
+      { swapDevices = lib.mkOverride 0
+          [ { device = "/root/swapfile"; size = 128; } ];
+        environment.variables.EDITOR = lib.mkOverride 0 "emacs";
+        documentation.nixos.enable = lib.mkOverride 0 true;
+        systemd.tmpfiles.rules = [ "d /tmp 1777 root root 10d" ];
+        systemd.tmpfiles.settings."10-test"."/tmp/somefile".d = {};
+        virtualisation.fileSystems = { "/tmp2" =
+          { fsType = "tmpfs";
+            options = [ "mode=1777" "noauto" ];
+          };
+          # Tests https://discourse.nixos.org/t/how-to-make-a-derivations-executables-have-the-s-permission/8555
+          "/user-mount/point" = {
+            device = "/user-mount/source";
+            fsType = "none";
+            options = [ "bind" "rw" "user" "noauto" ];
+          };
+          "/user-mount/denied-point" = {
+            device = "/user-mount/denied-source";
+            fsType = "none";
+            options = [ "bind" "rw" "noauto" ];
+          };
         };
+        systemd.automounts = lib.singleton
+          { wantedBy = [ "multi-user.target" ];
+            where = "/tmp2";
+          };
+        users.users.sybil = { isNormalUser = true; group = "wheel"; };
+        users.users.alice = { isNormalUser = true; };
+        security.sudo = { enable = true; wheelNeedsPassword = false; };
+        boot.kernel.sysctl."vm.swappiness" = 1;
+        boot.kernelParams = [ "vsyscall=emulate" ];
+        system.extraDependencies = [ foo ];
+
+        nix.package = nixPackage;
       };
-      systemd.automounts = lib.singleton
-        { wantedBy = [ "multi-user.target" ];
-          where = "/tmp2";
-        };
-      users.users.sybil = { isNormalUser = true; group = "wheel"; };
-      users.users.alice = { isNormalUser = true; };
-      security.sudo = { enable = true; wheelNeedsPassword = false; };
-      boot.kernel.sysctl."vm.swappiness" = 1;
-      boot.kernelParams = [ "vsyscall=emulate" ];
-      system.extraDependencies = [ foo ];
-    };
-
-  testScript =
-    ''
-      import json
-
-
-      def get_path_info(path):
-          result = machine.succeed(f"nix --option experimental-features nix-command path-info --json {path}")
-          parsed = json.loads(result)
-          return parsed
-
-
-      with subtest("nix-db"):
-          info = get_path_info("${foo}")
-          print(info)
-
-          if (
-              info[0]["narHash"]
-              != "sha256-BdMdnb/0eWy3EddjE83rdgzWWpQjfWPAj3zDIFMD3Ck="
-          ):
-              raise Exception("narHash not set")
-
-          if info[0]["narSize"] != 128:
-              raise Exception("narSize not set")
-
-      with subtest("nixos-version"):
-          machine.succeed("[ `nixos-version | wc -w` = 2 ]")
-
-      with subtest("nixos-rebuild"):
-          assert "NixOS module" in machine.succeed("nixos-rebuild --help")
-
-      with subtest("Sanity check for uid/gid assignment"):
-          assert "4" == machine.succeed("id -u messagebus").strip()
-          assert "4" == machine.succeed("id -g messagebus").strip()
-          assert "users:x:100:" == machine.succeed("getent group users").strip()
-
-      with subtest("Regression test for GMP aborts on QEMU."):
-          machine.succeed("expr 1 + 2")
-
-      with subtest("the swap file got created"):
-          machine.wait_for_unit("root-swapfile.swap")
-          machine.succeed("ls -l /root/swapfile | grep 134217728")
-
-      with subtest("whether kernel.poweroff_cmd is set"):
-          machine.succeed('[ -x "$(cat /proc/sys/kernel/poweroff_cmd)" ]')
-
-      with subtest("whether the io cgroupv2 controller is properly enabled"):
-          machine.succeed("grep -q '\\bio\\b' /sys/fs/cgroup/cgroup.controllers")
-
-      with subtest("whether we have a reboot record in wtmp"):
-          machine.shutdown
-          machine.wait_for_unit("multi-user.target")
-          machine.succeed("last | grep reboot >&2")
-
-      with subtest("whether we can override environment variables"):
-          machine.succeed('[ "$EDITOR" = emacs ]')
-
-      with subtest("whether hostname (and by extension nss_myhostname) works"):
-          assert "machine" == machine.succeed("hostname").strip()
-          assert "machine" == machine.succeed("hostname -s").strip()
-
-      with subtest("whether systemd-udevd automatically loads modules for our hardware"):
-          machine.succeed("systemctl start systemd-udev-settle.service")
-          machine.wait_for_unit("systemd-udev-settle.service")
-          assert "mousedev" in machine.succeed("lsmod")
-
-      with subtest("whether systemd-tmpfiles-clean works"):
-          machine.succeed(
-              "touch /tmp/foo", "systemctl start systemd-tmpfiles-clean", "[ -e /tmp/foo ]"
-          )
-          # move into the future
-          machine.succeed(
-              'date -s "@$(($(date +%s) + 1000000))"',
-              "systemctl start systemd-tmpfiles-clean",
-          )
-          machine.fail("[ -e /tmp/foo ]")
-
-      with subtest("whether systemd-tmpfiles settings works"):
-          machine.succeed("[ -e /tmp/somefile ]")
-
-      with subtest("whether automounting works"):
-          machine.fail("grep '/tmp2 tmpfs' /proc/mounts")
-          machine.succeed("touch /tmp2/x")
-          machine.succeed("grep '/tmp2 tmpfs' /proc/mounts")
-
-      with subtest(
-          "Whether mounting by a user is possible with the `user` option in fstab (#95444)"
-      ):
-          machine.succeed("mkdir -p /user-mount/source")
-          machine.succeed("touch /user-mount/source/file")
-          machine.succeed("chmod -R a+Xr /user-mount/source")
-          machine.succeed("mkdir /user-mount/point")
-          machine.succeed("chown alice:users /user-mount/point")
-          machine.succeed("su - alice -c 'mount /user-mount/point'")
-          machine.succeed("su - alice -c 'ls /user-mount/point/file'")
-      with subtest(
-          "Whether mounting by a user is denied without the `user` option in  fstab"
-      ):
-          machine.succeed("mkdir -p /user-mount/denied-source")
-          machine.succeed("touch /user-mount/denied-source/file")
-          machine.succeed("chmod -R a+Xr /user-mount/denied-source")
-          machine.succeed("mkdir /user-mount/denied-point")
-          machine.succeed("chown alice:users /user-mount/denied-point")
-          machine.fail("su - alice -c 'mount /user-mount/denied-point'")
-
-      with subtest("shell-vars"):
-          machine.succeed('[ -n "$NIX_PATH" ]')
-
-      with subtest("nix-db"):
-          machine.succeed("nix-store -qR /run/current-system | grep nixos-")
-
-      with subtest("Test sysctl"):
-          machine.wait_for_unit("systemd-sysctl.service")
-          assert "1" == machine.succeed("sysctl -ne vm.swappiness").strip()
-          machine.execute("sysctl vm.swappiness=60")
-          assert "60" == machine.succeed("sysctl -ne vm.swappiness").strip()
-
-      with subtest("Test boot parameters"):
-          assert "vsyscall=emulate" in machine.succeed("cat /proc/cmdline")
-    '';
-})
+
+    testScript =
+      ''
+        import json
+
+
+        def get_path_info(path):
+            result = machine.succeed(f"nix --option experimental-features nix-command path-info --json {path}")
+            parsed = json.loads(result)
+            return parsed
+
+
+        with subtest("nix-db"):
+            info = get_path_info("${foo}")
+            print(info)
+
+            if (
+                info[0]["narHash"]
+                != "sha256-BdMdnb/0eWy3EddjE83rdgzWWpQjfWPAj3zDIFMD3Ck="
+            ):
+                raise Exception("narHash not set")
+
+            if info[0]["narSize"] != 128:
+                raise Exception("narSize not set")
+
+        with subtest("nixos-version"):
+            machine.succeed("[ `nixos-version | wc -w` = 2 ]")
+
+        with subtest("nixos-rebuild"):
+            assert "NixOS module" in machine.succeed("nixos-rebuild --help")
+
+        with subtest("Sanity check for uid/gid assignment"):
+            assert "4" == machine.succeed("id -u messagebus").strip()
+            assert "4" == machine.succeed("id -g messagebus").strip()
+            assert "users:x:100:" == machine.succeed("getent group users").strip()
+
+        with subtest("Regression test for GMP aborts on QEMU."):
+            machine.succeed("expr 1 + 2")
+
+        with subtest("the swap file got created"):
+            machine.wait_for_unit("root-swapfile.swap")
+            machine.succeed("ls -l /root/swapfile | grep 134217728")
+
+        with subtest("whether kernel.poweroff_cmd is set"):
+            machine.succeed('[ -x "$(cat /proc/sys/kernel/poweroff_cmd)" ]')
+
+        with subtest("whether the io cgroupv2 controller is properly enabled"):
+            machine.succeed("grep -q '\\bio\\b' /sys/fs/cgroup/cgroup.controllers")
+
+        with subtest("whether we have a reboot record in wtmp"):
+            machine.shutdown
+            machine.wait_for_unit("multi-user.target")
+            machine.succeed("last | grep reboot >&2")
+
+        with subtest("whether we can override environment variables"):
+            machine.succeed('[ "$EDITOR" = emacs ]')
+
+        with subtest("whether hostname (and by extension nss_myhostname) works"):
+            assert "machine" == machine.succeed("hostname").strip()
+            assert "machine" == machine.succeed("hostname -s").strip()
+
+        with subtest("whether systemd-udevd automatically loads modules for our hardware"):
+            machine.succeed("systemctl start systemd-udev-settle.service")
+            machine.wait_for_unit("systemd-udev-settle.service")
+            assert "mousedev" in machine.succeed("lsmod")
+
+        with subtest("whether systemd-tmpfiles-clean works"):
+            machine.succeed(
+                "touch /tmp/foo", "systemctl start systemd-tmpfiles-clean", "[ -e /tmp/foo ]"
+            )
+            # move into the future
+            machine.succeed(
+                'date -s "@$(($(date +%s) + 1000000))"',
+                "systemctl start systemd-tmpfiles-clean",
+            )
+            machine.fail("[ -e /tmp/foo ]")
+
+        with subtest("whether systemd-tmpfiles settings works"):
+            machine.succeed("[ -e /tmp/somefile ]")
+
+        with subtest("whether automounting works"):
+            machine.fail("grep '/tmp2 tmpfs' /proc/mounts")
+            machine.succeed("touch /tmp2/x")
+            machine.succeed("grep '/tmp2 tmpfs' /proc/mounts")
+
+        with subtest(
+            "Whether mounting by a user is possible with the `user` option in fstab (#95444)"
+        ):
+            machine.succeed("mkdir -p /user-mount/source")
+            machine.succeed("touch /user-mount/source/file")
+            machine.succeed("chmod -R a+Xr /user-mount/source")
+            machine.succeed("mkdir /user-mount/point")
+            machine.succeed("chown alice:users /user-mount/point")
+            machine.succeed("su - alice -c 'mount /user-mount/point'")
+            machine.succeed("su - alice -c 'ls /user-mount/point/file'")
+        with subtest(
+            "Whether mounting by a user is denied without the `user` option in  fstab"
+        ):
+            machine.succeed("mkdir -p /user-mount/denied-source")
+            machine.succeed("touch /user-mount/denied-source/file")
+            machine.succeed("chmod -R a+Xr /user-mount/denied-source")
+            machine.succeed("mkdir /user-mount/denied-point")
+            machine.succeed("chown alice:users /user-mount/denied-point")
+            machine.fail("su - alice -c 'mount /user-mount/denied-point'")
+
+        with subtest("shell-vars"):
+            machine.succeed('[ -n "$NIX_PATH" ]')
+
+        with subtest("nix-db"):
+            machine.succeed("nix-store -qR /run/current-system | grep nixos-")
+
+        with subtest("Test sysctl"):
+            machine.wait_for_unit("systemd-sysctl.service")
+            assert "1" == machine.succeed("sysctl -ne vm.swappiness").strip()
+            machine.execute("sysctl vm.swappiness=60")
+            assert "60" == machine.succeed("sysctl -ne vm.swappiness").strip()
+
+        with subtest("Test boot parameters"):
+            assert "vsyscall=emulate" in machine.succeed("cat /proc/cmdline")
+      '';
+  });
+  in
+  tests
diff --git a/pkgs/tools/package-management/lix/common.nix b/pkgs/tools/package-management/lix/common.nix
new file mode 100644
index 0000000000000..a544707b4f355
--- /dev/null
+++ b/pkgs/tools/package-management/lix/common.nix
@@ -0,0 +1,286 @@
+{
+  lib,
+  fetchFromGitHub,
+  version,
+  suffix ? "",
+  hash ? null,
+  src ? fetchFromGitHub {
+    owner = "lix-project";
+    repo = "lix";
+    rev = version;
+    inherit hash;
+  },
+  docCargoHash ? null,
+  patches ? [ ],
+  maintainers ? lib.teams.lix.members,
+}@args:
+assert (hash == null) -> (src != null);
+{
+  stdenv,
+  meson,
+  bash,
+  bison,
+  boehmgc,
+  boost,
+  brotli,
+  busybox-sandbox-shell,
+  bzip2,
+  callPackage,
+  coreutils,
+  curl,
+  cmake,
+  docbook_xsl_ns,
+  docbook5,
+  doxygen,
+  editline,
+  flex,
+  git,
+  gnutar,
+  gtest,
+  gzip,
+  jq,
+  lib,
+  libarchive,
+  libcpuid,
+  libgit2,
+  libsodium,
+  libxml2,
+  libxslt,
+  lowdown,
+  lsof,
+  man,
+  mercurial,
+  mdbook,
+  mdbook-linkcheck,
+  nlohmann_json,
+  ninja,
+  openssl,
+  toml11,
+  python3,
+  perl,
+  pkg-config,
+  rapidcheck,
+  Security,
+  sqlite,
+  util-linuxMinimal,
+  xz,
+  nixosTests,
+
+  enableDocumentation ? stdenv.hostPlatform == stdenv.buildPlatform,
+  enableStatic ? stdenv.hostPlatform.isStatic,
+  withAWS ? !enableStatic && (stdenv.isLinux || stdenv.isDarwin),
+  aws-sdk-cpp,
+  # RISC-V support in progress https://github.com/seccomp/libseccomp/pull/50
+  withLibseccomp ? lib.meta.availableOn stdenv.hostPlatform libseccomp,
+  libseccomp,
+
+  confDir,
+  stateDir,
+  storeDir,
+}:
+let
+  lix-doc = callPackage ./doc {
+    inherit src;
+    version = "${version}${suffix}";
+    cargoHash = docCargoHash;
+  };
+  self = stdenv.mkDerivation {
+    pname = "lix";
+
+    version = "${version}${suffix}";
+    VERSION_SUFFIX = suffix;
+
+    inherit src patches;
+
+    outputs =
+      [
+        "out"
+        "dev"
+      ]
+      ++ lib.optionals enableDocumentation [
+        "man"
+        "doc"
+      ];
+
+    strictDeps = true;
+
+    nativeBuildInputs =
+      [
+        pkg-config
+        bison
+        flex
+        jq
+        meson
+        ninja
+        cmake
+        python3
+        doxygen
+
+        # Tests
+        git
+        mercurial
+        jq
+        lsof
+      ]
+      ++ lib.optionals (enableDocumentation) [
+        (lib.getBin lowdown)
+        mdbook
+        mdbook-linkcheck
+      ]
+      ++ lib.optionals stdenv.isLinux [ util-linuxMinimal ];
+
+    buildInputs =
+      [
+        boost
+        brotli
+        bzip2
+        curl
+        editline
+        libsodium
+        openssl
+        sqlite
+        xz
+        gtest
+        libarchive
+        lowdown
+        rapidcheck
+        toml11
+        lix-doc
+      ]
+      ++ lib.optionals stdenv.isDarwin [ Security ]
+      ++ lib.optionals (stdenv.isx86_64) [ libcpuid ]
+      ++ lib.optionals withLibseccomp [ libseccomp ]
+      ++ lib.optionals withAWS [ aws-sdk-cpp ];
+
+    propagatedBuildInputs = [
+      boehmgc
+      nlohmann_json
+    ];
+
+    postPatch = ''
+      patchShebangs --build tests
+    '';
+
+    preConfigure =
+      # Copy libboost_context so we don't get all of Boost in our closure.
+      # https://github.com/NixOS/nixpkgs/issues/45462
+      lib.optionalString (!enableStatic) ''
+        mkdir -p $out/lib
+        cp -pd ${boost}/lib/{libboost_context*,libboost_thread*,libboost_system*} $out/lib
+        rm -f $out/lib/*.a
+        ${lib.optionalString stdenv.isLinux ''
+          chmod u+w $out/lib/*.so.*
+          patchelf --set-rpath $out/lib:${stdenv.cc.cc.lib}/lib $out/lib/libboost_thread.so.*
+        ''}
+        ${lib.optionalString stdenv.hostPlatform.isDarwin ''
+          for LIB in $out/lib/*.dylib; do
+            chmod u+w $LIB
+            install_name_tool -id $LIB $LIB
+            install_name_tool -delete_rpath ${boost}/lib/ $LIB || true
+          done
+          install_name_tool -change ${boost}/lib/libboost_system.dylib $out/lib/libboost_system.dylib $out/lib/libboost_thread.dylib
+        ''}
+      '';
+
+    mesonFlags =
+      [
+        (lib.mesonEnable "gc" true)
+        (lib.mesonBool "enable-tests" true)
+        (lib.mesonBool "enable-docs" enableDocumentation)
+        (lib.mesonBool "enable-embedded-sandbox-shell" (stdenv.isLinux && stdenv.hostPlatform.isStatic))
+        (lib.mesonEnable "seccomp-sandboxing" withLibseccomp)
+
+        (lib.mesonOption "store-dir" storeDir)
+        (lib.mesonOption "state-dir" stateDir)
+        (lib.mesonOption "sysconfdir" confDir)
+      ]
+      ++ lib.optionals stdenv.isLinux [
+        (lib.mesonOption "sandbox-shell" "${busybox-sandbox-shell}/bin/busybox")
+      ];
+
+    # Needed for Meson to find Boost.
+    # https://github.com/NixOS/nixpkgs/issues/86131.
+    env = {
+      BOOST_INCLUDEDIR = "${lib.getDev boost}/include";
+      BOOST_LIBRARYDIR = "${lib.getLib boost}/lib";
+    };
+
+    postInstall =
+      ''
+        mkdir -p $doc/nix-support
+        echo "doc manual $doc/share/doc/nix/manual" >> $doc/nix-support/hydra-build-products
+      ''
+      + lib.optionalString stdenv.hostPlatform.isStatic ''
+        mkdir -p $out/nix-support
+        echo "file binary-dist $out/bin/nix" >> $out/nix-support/hydra-build-products
+      ''
+      + lib.optionalString stdenv.isDarwin ''
+        for lib in libnixutil.dylib libnixexpr.dylib; do
+          install_name_tool \
+            -change "${lib.getLib boost}/lib/libboost_context.dylib" \
+            "$out/lib/libboost_context.dylib" \
+            "$out/lib/$lib"
+        done
+      '';
+
+    doCheck = true;
+    mesonCheckFlags = [ "--suite=check" ];
+    checkInputs = [
+      gtest
+      rapidcheck
+    ];
+
+    doInstallCheck = true;
+    mesonInstallCheckFlags = [ "--suite=installcheck" ];
+
+    preInstallCheck = lib.optionalString stdenv.hostPlatform.isDarwin ''
+      # socket path becomes too long otherwise
+      export TMPDIR=$NIX_BUILD_TOP
+      # Prevent crashes in libcurl due to invoking Objective-C `+initialize` methods after `fork`.
+      # See http://sealiesoftware.com/blog/archive/2017/6/5/Objective-C_and_fork_in_macOS_1013.html.
+      export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
+    '';
+
+    installCheckPhase = ''
+      runHook preInstallCheck
+      flagsArray=($mesonInstallCheckFlags "''${mesonInstallCheckFlagsArray[@]}")
+      meson test --no-rebuild "''${flagsArray[@]}"
+      runHook postInstallCheck
+    '';
+    # strictoverflow is disabled because we trap on signed overflow instead
+    hardeningDisable = [ "strictoverflow" ] ++ lib.optional stdenv.hostPlatform.isStatic "pie";
+    # hardeningEnable = lib.optionals (!stdenv.isDarwin) [ "pie" ];
+    # hardeningDisable = lib.optional stdenv.hostPlatform.isMusl "fortify";
+    separateDebugInfo = stdenv.isLinux && !enableStatic;
+    enableParallelBuilding = true;
+
+    passthru = {
+      inherit aws-sdk-cpp boehmgc;
+      tests = {
+        misc = nixosTests.misc.lix.passthru.override { nixPackage = self; };
+      };
+    };
+
+    # point 'nix edit' and ofborg at the file that defines the attribute,
+    # not this common file.
+    pos = builtins.unsafeGetAttrPos "version" args;
+    meta = with lib; {
+      description = "Powerful package manager that makes package management reliable and reproducible";
+      longDescription = ''
+        Lix (a fork of Nix) is a powerful package manager for Linux and other Unix systems that
+        makes package management reliable and reproducible. It provides atomic
+        upgrades and rollbacks, side-by-side installation of multiple versions of
+        a package, multi-user package management and easy setup of build
+        environments.
+      '';
+      homepage = "https://lix.systems";
+      license = licenses.lgpl21Plus;
+      inherit maintainers;
+      platforms = platforms.unix;
+      outputsToInstall = [ "out" ] ++ optional enableDocumentation "man";
+      mainProgram = "nix";
+      broken = enableStatic;
+    };
+  };
+in
+self
diff --git a/pkgs/tools/package-management/lix/default.nix b/pkgs/tools/package-management/lix/default.nix
new file mode 100644
index 0000000000000..9a03e64f8b8fc
--- /dev/null
+++ b/pkgs/tools/package-management/lix/default.nix
@@ -0,0 +1,60 @@
+{
+  lib,
+  aws-sdk-cpp,
+  boehmgc,
+  callPackage,
+  fetchFromGitHub,
+  Security,
+
+  storeDir ? "/nix/store",
+  stateDir ? "/nix/var",
+  confDir ? "/etc",
+}:
+let
+  boehmgc-nix_2_3 = boehmgc.override { enableLargeConfig = true; };
+
+  boehmgc-nix = boehmgc-nix_2_3.overrideAttrs (drv: {
+    patches = (drv.patches or [ ]) ++ [
+      # Part of the GC solution in https://github.com/NixOS/nix/pull/4944
+      ../nix/patches/boehmgc-coroutine-sp-fallback.patch
+    ];
+  });
+
+  aws-sdk-cpp-nix =
+    (aws-sdk-cpp.override {
+      apis = [
+        "s3"
+        "transfer"
+      ];
+      customMemoryManagement = false;
+    }).overrideAttrs
+      {
+        # only a stripped down version is build which takes a lot less resources to build
+        requiredSystemFeatures = [ ];
+      };
+
+  common =
+    args:
+    callPackage (import ./common.nix ({ inherit lib fetchFromGitHub; } // args)) {
+      inherit
+        Security
+        storeDir
+        stateDir
+        confDir
+        ;
+      boehmgc = boehmgc-nix;
+      aws-sdk-cpp = aws-sdk-cpp-nix;
+    };
+in
+lib.makeExtensible (self: ({
+  lix_2_90 = (
+    common {
+      version = "2.90-beta.1";
+      hash = "sha256-REWlo2RYHfJkxnmZTEJu3Cd/2VM+wjjpPy7Xi4BdDTQ=";
+      docCargoHash = "sha256-oH248kR4Of0MhcY2DYxNX0A+/XJ3L+UuIpBKn3sJt54=";
+    }
+  );
+
+  latest = self.lix_2_90;
+  stable = self.lix_2_90;
+}))
diff --git a/pkgs/tools/package-management/lix/doc/default.nix b/pkgs/tools/package-management/lix/doc/default.nix
new file mode 100644
index 0000000000000..a3c1d7d9ccc5a
--- /dev/null
+++ b/pkgs/tools/package-management/lix/doc/default.nix
@@ -0,0 +1,12 @@
+{
+  src,
+  rustPlatform,
+  version,
+  cargoHash,
+}:
+
+rustPlatform.buildRustPackage {
+  pname = "lix-doc";
+  sourceRoot = "${src.name}/lix-doc";
+  inherit version src cargoHash;
+}
diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
index 8f4e2cba31d53..f2dcbdedb778d 100644
--- a/pkgs/top-level/all-packages.nix
+++ b/pkgs/top-level/all-packages.nix
@@ -39589,6 +39589,16 @@ with pkgs;
 
   nixStatic = pkgsStatic.nix;
 
+  lixVersions = recurseIntoAttrs (callPackage ../tools/package-management/lix {
+    storeDir = config.nix.storeDir or "/nix/store";
+    stateDir = config.nix.stateDir or "/nix/var";
+    inherit (darwin.apple_sdk.frameworks) Security;
+  });
+
+  lix = lixVersions.stable;
+
+  lixStatic = pkgsStatic.lix;
+
   inherit (callPackages ../applications/networking/cluster/nixops { })
     nixops_unstable_minimal