Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nix, nix-*, nixos-rebuild, home-manager command aliases/wrappers #108

Open
zeorin opened this issue Aug 22, 2023 · 1 comment
Open

nix, nix-*, nixos-rebuild, home-manager command aliases/wrappers #108

zeorin opened this issue Aug 22, 2023 · 1 comment

Comments

@zeorin
Copy link

zeorin commented Aug 22, 2023

I just discovered your project, it looks very nice. I immediately wanted the full JSON-powered experience when calling home-manager switch, so I took a stab at implementing that.

Once I had that done, I nerd-sniped myself into trying to get it to work for nixos-rebuild, too. I could get this to work when using the --fast or --no-build-nix flags. Without those flags, nixos-rebuild builds/fetches a new version of nix and uses that instead.

I then created wrappers for the various nix commands, too. There's probably some edge cases in this code, but it's a starting point:

{ config, pkgs, lib, ... }:

let
  collectPathArgs = ''
    paths=()
    while [ "$#" -gt 0 ]; do
      arg="$1"
      [[ "$arg" =~ ^--?.+ ]] && break
      paths+=("$arg"); shift
    done
  '';
  pathArgs = ''"''${paths[@]}"'';
  collectFlakeFlags = ''
    flakeFlags=()
    while [ "$#" -gt 0 ]; do
      arg="$1"
      case "$arg" in
        ${
          builtins.concatStringsSep "|" [
            "build"
            "bundle"
            "copy"
            "daemon"
            "derivation"
            "develop"
            "doctor"
            "edit"
            "eval"
            "flake"
            "fmt"
            "hash"
            "help"
            "help-stores"
            "key"
            "log"
            "nar"
            "path-info"
            "print-dev-env"
            "profile"
            "realisation"
            "registry"
            "repl"
            "run"
            "search"
            "shell"
            "show-config"
            "store"
            "upgrade-nix"
            "why-depends"
          ]
        })
          break
          ;;
        *)
          flakeFlags+=("$arg"); shift
          ;;
      esac
    done
  '';
  flakeFlags = ''"''${flakeFlags[@]}"'';
  nixNomArgs = "--log-format internal-json --verbose";
  nixBuildCmdWithNomArgs = buildCmd: ''
    ${collectPathArgs}
    ${buildCmd} ${pathArgs} ${nixNomArgs} "$@"
  '';
  nixShellCmdWithNomArgs = shellCmd: ''
    ${shellCmd} ${nixNomArgs} "$@"
  '';
  nixStoreCmdWithNomArgs = storeCmd: ''
    operation="$1"; shift
    case "$operation" in
      --realise|-r)
        ${collectPathArgs}
        ${storeCmd} "$operation" ${pathArgs} ${nixNomArgs} "$@"
        ;;
      *)
        ${storeCmd} "$operation" "$@"
        ;;
    esac
  '';
  nixWithNomArgs = nix:
    pkgs.symlinkJoin {
      name = "nix-with-nom-args-${nix.version}";
      paths = (lib.attrsets.mapAttrsToList pkgs.writeShellScriptBin {
        nix = ''
          program="$(basename $0)"
          case "$program" in
            nix)
              ${collectFlakeFlags}
              command="$1"; shift
              case "$command" in
                build)
                  ${nixBuildCmdWithNomArgs "${nix}/bin/nix ${flakeFlags} build"}
                  ;;
                shell)
                  ${nixShellCmdWithNomArgs "${nix}/bin/nix ${flakeFlags} shell"}
                  ;;
                store)
                  ${nixStoreCmdWithNomArgs "${nix}/bin/nix ${flakeFlags} store"}
                  ;;
                *)
                  ${nix}/bin/nix ${flakeFlags} "$command" "$@"
                  ;;
              esac
              ;;
            *)
              "${nix}/bin/$program" "$@"
              ;;
          esac
        '';
        nix-build = nixBuildCmdWithNomArgs "${nix}/bin/nix-build";
        nix-shell = nixShellCmdWithNomArgs "${nix}/bin/nix-shell";
        nix-store = nixStoreCmdWithNomArgs "${nix}/bin/nix-store";
      }) ++ [ nix ];
    };
  nixNomPkgs = { nix ? null, nixos-rebuild ? null, home-manager ? null }:
    lib.attrsets.mapAttrs pkgs.writeShellScriptBin ((if nix != null then {
      nix = ''
        program="$(basename $0)"
        case "$program" in
          nix)
            ${collectFlakeFlags}
            command="$1"; shift
            case "$command" in
              build|shell|develop)
                ${pkgs.nix-output-monitor}/bin/nom ${flakeFlags} "$command" "$@"
                ;;
              *)
                ${nix}/bin/nix ${flakeFlags} "$command" "$@"
                ;;
            esac
            ;;
          *)
            "${nix}/bin/$program" "$@"
            ;;
        esac
      '';
      nix-build = ''
        ${pkgs.nix-output-monitor}/bin/nom-build "$@"
      '';
      nix-shell = ''
        ${pkgs.nix-output-monitor}/bin/nom-shell "$@"
      '';
      nix-store = ''
        ${nixWithNomArgs nix}/bin/nix-store "$@" \
          |& ${pkgs.nix-output-monitor}/bin/nom --json
      '';
    } else
      { }) // (if nixos-rebuild != null then {
        nixos-rebuild = ''
          ${pkgs.expect}/bin/unbuffer \
            ${
              nixos-rebuild.override (old: { nix = nixWithNomArgs old.nix; })
            }/bin/nixos-rebuild "$@" \
            |& ${pkgs.nix-output-monitor}/bin/nom --json
        '';
      } else
        { }) // (if home-manager != null then {
          home-manager = ''
            PATH="${nixWithNomArgs pkgs.nix}/bin:$PATH" \
              ${pkgs.expect}/bin/unbuffer \
              ${home-manager}/bin/home-manager "$@" \
              |& ${pkgs.nix-output-monitor}/bin/nom --json
          '';
        } else
          { }));
  nomAliases = pkgs:
    lib.attrsets.mapAttrs (name: pkg: "${pkg}/bin/${name}") (nixNomPkgs pkgs);
  wrapWithNom = let inherit (pkgs) symlinkJoin;
  in (pkgs:
    symlinkJoin {
      name = "wrapped-with-nom";
      paths = (builtins.attrValues (nixNomPkgs pkgs))
        ++ (builtins.attrValues pkgs);
    });

in {
  home.shellAliases =
    nomAliases { inherit (pkgs) nix nixos-rebuild home-manager; };

  # or

  home.packages = [
    (lib.hiPrio
      (wrapWithNom { inherit (pkgs) nix nixos-rebuild home-manager; }))
  ];
}

Personally, I only use the aliases, since if something isn't working due to the way I've wrapped it, I can just use command to use the un-wrapped version, e.g. command home-manager switch.

It works quite well so far. home-manager always triggers nix-output-monitor error: DerivationParseError "string" but other than that it's flawless.

home-manager switch:

asciicast

nixos-rebuild build --fast:

asciicast

@ChanceHarrison
Copy link

Related: #76

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants