All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 35s
				
			Test / Sandbox (push) Successful in 2m21s
				
			Test / Sandbox (race detector) (push) Successful in 4m16s
				
			Test / Hpkg (push) Successful in 4m15s
				
			Test / Hakurei (race detector) (push) Successful in 4m58s
				
			Test / Hakurei (push) Successful in 2m16s
				
			Test / Flake checks (push) Successful in 1m28s
				
			This greatly reduces overhead. The iterator also significantly cleans up the usage code. Signed-off-by: Ophestra <cat@gensokyo.uk>
		
			
				
	
	
		
			347 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			347 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
packages:
 | 
						|
{
 | 
						|
  lib,
 | 
						|
  pkgs,
 | 
						|
  config,
 | 
						|
  ...
 | 
						|
}:
 | 
						|
 | 
						|
let
 | 
						|
  inherit (lib)
 | 
						|
    lists
 | 
						|
    attrsets
 | 
						|
    mkMerge
 | 
						|
    mkIf
 | 
						|
    mapAttrs
 | 
						|
    foldlAttrs
 | 
						|
    optional
 | 
						|
    optionals
 | 
						|
    ;
 | 
						|
 | 
						|
  cfg = config.environment.hakurei;
 | 
						|
 | 
						|
  getsubuid = fid: aid: 1000000 + fid * 10000 + aid;
 | 
						|
  getsubname = fid: aid: "u${toString fid}_a${toString aid}";
 | 
						|
  getsubhome = fid: aid: "${cfg.stateDir}/u${toString fid}/a${toString aid}";
 | 
						|
in
 | 
						|
 | 
						|
{
 | 
						|
  imports = [ (import ./options.nix packages) ];
 | 
						|
 | 
						|
  config = mkIf cfg.enable {
 | 
						|
    assertions = [
 | 
						|
      (
 | 
						|
        let
 | 
						|
          conflictingApps = foldlAttrs (
 | 
						|
            acc: id: app:
 | 
						|
            (
 | 
						|
              acc
 | 
						|
              ++ foldlAttrs (
 | 
						|
                acc': id': app':
 | 
						|
                if id == id' || app.shareUid && app'.shareUid || app.identity != app'.identity then acc' else acc' ++ [ id ]
 | 
						|
              ) [ ] cfg.apps
 | 
						|
            )
 | 
						|
          ) [ ] cfg.apps;
 | 
						|
        in
 | 
						|
        {
 | 
						|
          assertion = (lists.length conflictingApps) == 0;
 | 
						|
          message = "the following hakurei apps have conflicting identities: " + (builtins.concatStringsSep ", " conflictingApps);
 | 
						|
        }
 | 
						|
      )
 | 
						|
    ];
 | 
						|
 | 
						|
    security.wrappers.hsu = {
 | 
						|
      source = "${cfg.hsuPackage}/bin/hsu";
 | 
						|
      setuid = true;
 | 
						|
      owner = "root";
 | 
						|
      group = "root";
 | 
						|
    };
 | 
						|
 | 
						|
    environment.etc.hsurc = {
 | 
						|
      mode = "0400";
 | 
						|
      text = foldlAttrs (
 | 
						|
        acc: username: fid:
 | 
						|
        "${toString config.users.users.${username}.uid} ${toString fid}\n" + acc
 | 
						|
      ) "" cfg.users;
 | 
						|
    };
 | 
						|
 | 
						|
    home-manager =
 | 
						|
      let
 | 
						|
        privPackages = mapAttrs (username: fid: {
 | 
						|
          home.packages = foldlAttrs (
 | 
						|
            acc: id: app:
 | 
						|
            [
 | 
						|
              (
 | 
						|
                let
 | 
						|
                  extendDBusDefault = id: ext: {
 | 
						|
                    filter = true;
 | 
						|
 | 
						|
                    talk = [ "org.freedesktop.Notifications" ] ++ ext.talk;
 | 
						|
                    own = [
 | 
						|
                      "${id}.*"
 | 
						|
                      "org.mpris.MediaPlayer2.${id}.*"
 | 
						|
                    ]
 | 
						|
                    ++ ext.own;
 | 
						|
 | 
						|
                    inherit (ext) call broadcast;
 | 
						|
                  };
 | 
						|
                  dbusConfig =
 | 
						|
                    let
 | 
						|
                      default = {
 | 
						|
                        talk = [ ];
 | 
						|
                        own = [ ];
 | 
						|
                        call = { };
 | 
						|
                        broadcast = { };
 | 
						|
                      };
 | 
						|
                    in
 | 
						|
                    {
 | 
						|
                      session_bus = if app.dbus.session != null then (app.dbus.session (extendDBusDefault id)) else (extendDBusDefault id default);
 | 
						|
                      system_bus = app.dbus.system;
 | 
						|
                    };
 | 
						|
                  command = if app.command == null then app.name else app.command;
 | 
						|
                  script = if app.script == null then ("exec " + command + " $@") else app.script;
 | 
						|
                  isGraphical = if app.gpu != null then app.gpu else app.enablements.wayland || app.enablements.x11;
 | 
						|
 | 
						|
                  conf = {
 | 
						|
                    inherit id;
 | 
						|
                    inherit (app) identity groups enablements;
 | 
						|
                    inherit (dbusConfig) session_bus system_bus;
 | 
						|
                    direct_wayland = app.insecureWayland;
 | 
						|
 | 
						|
                    container = {
 | 
						|
                      inherit (app)
 | 
						|
                        wait_delay
 | 
						|
                        devel
 | 
						|
                        userns
 | 
						|
                        device
 | 
						|
                        tty
 | 
						|
                        multiarch
 | 
						|
                        env
 | 
						|
                        ;
 | 
						|
                      map_real_uid = app.mapRealUid;
 | 
						|
                      host_net = app.hostNet;
 | 
						|
                      host_abstract = app.hostAbstract;
 | 
						|
                      share_runtime = app.shareRuntime;
 | 
						|
                      share_tmpdir = app.shareTmpdir;
 | 
						|
 | 
						|
                      filesystem =
 | 
						|
                        let
 | 
						|
                          bind = src: {
 | 
						|
                            type = "bind";
 | 
						|
                            inherit src;
 | 
						|
                          };
 | 
						|
                          optBind = src: {
 | 
						|
                            type = "bind";
 | 
						|
                            inherit src;
 | 
						|
                            optional = true;
 | 
						|
                          };
 | 
						|
                          optDevBind = src: {
 | 
						|
                            type = "bind";
 | 
						|
                            inherit src;
 | 
						|
                            dev = true;
 | 
						|
                            optional = true;
 | 
						|
                          };
 | 
						|
                        in
 | 
						|
                        [
 | 
						|
                          (bind "/bin")
 | 
						|
                          (bind "/usr/bin")
 | 
						|
                          (bind "/nix/store")
 | 
						|
                          (optBind "/sys/block")
 | 
						|
                          (optBind "/sys/bus")
 | 
						|
                          (optBind "/sys/class")
 | 
						|
                          (optBind "/sys/dev")
 | 
						|
                          (optBind "/sys/devices")
 | 
						|
                        ]
 | 
						|
                        ++ optionals app.nix [
 | 
						|
                          (bind "/nix/var")
 | 
						|
                        ]
 | 
						|
                        ++ optionals isGraphical [
 | 
						|
                          (optDevBind "/dev/dri")
 | 
						|
                          (optDevBind "/dev/nvidiactl")
 | 
						|
                          (optDevBind "/dev/nvidia-modeset")
 | 
						|
                          (optDevBind "/dev/nvidia-uvm")
 | 
						|
                          (optDevBind "/dev/nvidia-uvm-tools")
 | 
						|
                          (optDevBind "/dev/nvidia0")
 | 
						|
                        ]
 | 
						|
                        ++ optionals app.useCommonPaths cfg.commonPaths
 | 
						|
                        ++ app.extraPaths
 | 
						|
                        ++ [
 | 
						|
                          {
 | 
						|
                            type = "bind";
 | 
						|
                            dst = "/etc/";
 | 
						|
                            src = "/etc/";
 | 
						|
                            special = true;
 | 
						|
                          }
 | 
						|
                          {
 | 
						|
                            type = "link";
 | 
						|
                            dst = "/run/current-system";
 | 
						|
                            linkname = "/run/current-system";
 | 
						|
                            dereference = true;
 | 
						|
                          }
 | 
						|
                        ]
 | 
						|
                        ++ optionals (isGraphical && config.hardware.graphics.enable) (
 | 
						|
                          [
 | 
						|
                            {
 | 
						|
                              type = "link";
 | 
						|
                              dst = "/run/opengl-driver";
 | 
						|
                              linkname = config.systemd.tmpfiles.settings.graphics-driver."/run/opengl-driver"."L+".argument;
 | 
						|
                            }
 | 
						|
                          ]
 | 
						|
                          ++ optionals (app.multiarch && config.hardware.graphics.enable32Bit) [
 | 
						|
                            {
 | 
						|
                              type = "link";
 | 
						|
                              dst = "/run/opengl-driver-32";
 | 
						|
                              linkname = config.systemd.tmpfiles.settings.graphics-driver."/run/opengl-driver-32"."L+".argument;
 | 
						|
                            }
 | 
						|
                          ]
 | 
						|
                        )
 | 
						|
                        ++ [
 | 
						|
                          {
 | 
						|
                            type = "bind";
 | 
						|
                            src = getsubhome fid app.identity;
 | 
						|
                            write = true;
 | 
						|
                            ensure = true;
 | 
						|
                          }
 | 
						|
                        ];
 | 
						|
 | 
						|
                      username = getsubname fid app.identity;
 | 
						|
                      inherit (cfg) shell;
 | 
						|
                      home = getsubhome fid app.identity;
 | 
						|
 | 
						|
                      path =
 | 
						|
                        if app.path == null then
 | 
						|
                          pkgs.writeScript "${app.name}-start" ''
 | 
						|
                            #!${pkgs.zsh}${pkgs.zsh.shellPath}
 | 
						|
                            ${script}
 | 
						|
                          ''
 | 
						|
                        else
 | 
						|
                          app.path;
 | 
						|
                      args = if app.args == null then [ "${app.name}-start" ] else app.args;
 | 
						|
                    };
 | 
						|
                  };
 | 
						|
 | 
						|
                  checkedConfig =
 | 
						|
                    name: value:
 | 
						|
                    let
 | 
						|
                      file = pkgs.writeText name (builtins.toJSON value);
 | 
						|
                    in
 | 
						|
                    pkgs.runCommand "checked-${name}" { nativeBuildInputs = [ cfg.package ]; } ''
 | 
						|
                      ln -vs ${file} "$out"
 | 
						|
                      hakurei show --no-store ${file}
 | 
						|
                    '';
 | 
						|
                in
 | 
						|
                pkgs.writeShellScriptBin app.name ''
 | 
						|
                  exec hakurei${if app.verbose then " -v" else ""} app ${checkedConfig "hakurei-app-${app.name}.json" conf} $@
 | 
						|
                ''
 | 
						|
              )
 | 
						|
            ]
 | 
						|
            ++ (
 | 
						|
              let
 | 
						|
                pkg = if app.share != null then app.share else pkgs.${app.name};
 | 
						|
                copy = source: "[ -d '${source}' ] && cp -Lrv '${source}' $out/share || true";
 | 
						|
              in
 | 
						|
              optional (app.enablements.wayland || app.enablements.x11) (
 | 
						|
                pkgs.runCommand "${app.name}-share" { } ''
 | 
						|
                  mkdir -p $out/share
 | 
						|
                  ${copy "${pkg}/share/applications"}
 | 
						|
                  ${copy "${pkg}/share/pixmaps"}
 | 
						|
                  ${copy "${pkg}/share/icons"}
 | 
						|
                  ${copy "${pkg}/share/man"}
 | 
						|
 | 
						|
                  if test -d "$out/share/applications"; then
 | 
						|
                    substituteInPlace $out/share/applications/* \
 | 
						|
                      --replace-warn '${pkg}/bin/' "" \
 | 
						|
                      --replace-warn '${pkg}/libexec/' ""
 | 
						|
                  fi
 | 
						|
                ''
 | 
						|
              )
 | 
						|
            )
 | 
						|
            ++ acc
 | 
						|
          ) [ cfg.package ] cfg.apps;
 | 
						|
        }) cfg.users;
 | 
						|
      in
 | 
						|
      {
 | 
						|
        useUserPackages = false; # prevent users.users entries from being added
 | 
						|
 | 
						|
        users =
 | 
						|
          mkMerge
 | 
						|
            (foldlAttrs
 | 
						|
              (
 | 
						|
                acc: _: fid:
 | 
						|
                foldlAttrs
 | 
						|
                  (
 | 
						|
                    acc: _: app:
 | 
						|
                    (
 | 
						|
                      let
 | 
						|
                        key = getsubname fid app.identity;
 | 
						|
                      in
 | 
						|
                      {
 | 
						|
                        usernames = acc.usernames // {
 | 
						|
                          ${key} = true;
 | 
						|
                        };
 | 
						|
                        merge = acc.merge ++ [
 | 
						|
                          {
 | 
						|
                            ${key} = mkMerge (
 | 
						|
                              [
 | 
						|
                                app.extraConfig
 | 
						|
                                { home.packages = app.packages; }
 | 
						|
                              ]
 | 
						|
                              ++ lib.optional (!attrsets.hasAttrByPath [ key ] acc.usernames) cfg.extraHomeConfig
 | 
						|
                            );
 | 
						|
                          }
 | 
						|
                        ];
 | 
						|
                      }
 | 
						|
                    )
 | 
						|
                  )
 | 
						|
                  {
 | 
						|
                    inherit (acc) usernames;
 | 
						|
                    merge = acc.merge ++ [ { ${getsubname fid 0} = cfg.extraHomeConfig; } ];
 | 
						|
                  }
 | 
						|
                  cfg.apps
 | 
						|
              )
 | 
						|
              {
 | 
						|
                usernames = { };
 | 
						|
                merge = [ privPackages ];
 | 
						|
              }
 | 
						|
              cfg.users
 | 
						|
            ).merge;
 | 
						|
      };
 | 
						|
 | 
						|
    users =
 | 
						|
      let
 | 
						|
        getuser = fid: aid: {
 | 
						|
          isSystemUser = true;
 | 
						|
          createHome = true;
 | 
						|
          description = "Hakurei subordinate user ${toString aid} (u${toString fid})";
 | 
						|
          group = getsubname fid aid;
 | 
						|
          home = getsubhome fid aid;
 | 
						|
          uid = getsubuid fid aid;
 | 
						|
        };
 | 
						|
        getgroup = fid: aid: { gid = getsubuid fid aid; };
 | 
						|
      in
 | 
						|
      {
 | 
						|
        users = mkMerge (
 | 
						|
          foldlAttrs (
 | 
						|
            acc: _: fid:
 | 
						|
            acc
 | 
						|
            ++ foldlAttrs (
 | 
						|
              acc': _: app:
 | 
						|
              acc' ++ [ { ${getsubname fid app.identity} = getuser fid app.identity; } ]
 | 
						|
            ) [ { ${getsubname fid 0} = getuser fid 0; } ] cfg.apps
 | 
						|
          ) [ ] cfg.users
 | 
						|
        );
 | 
						|
 | 
						|
        groups = mkMerge (
 | 
						|
          foldlAttrs (
 | 
						|
            acc: _: fid:
 | 
						|
            acc
 | 
						|
            ++ foldlAttrs (
 | 
						|
              acc': _: app:
 | 
						|
              acc' ++ [ { ${getsubname fid app.identity} = getgroup fid app.identity; } ]
 | 
						|
            ) [ { ${getsubname fid 0} = getgroup fid 0; } ] cfg.apps
 | 
						|
          ) [ ] cfg.users
 | 
						|
        );
 | 
						|
      };
 | 
						|
  };
 | 
						|
}
 |