set positional-arguments # makes variables accesible as $1 $2 $@ export invokedir := invocation_directory() export GUM_CHOOSE_HEIGHT := "15" export GUM_FILTER_HEIGHT := "15" export FZF_DEFAULT_OPTS := "--height 15 --cycle --bind 'ctrl-a:toggle-all' " + env('FZF_DEFAULT_OPTS', "") #export hosts_nixos := `2>/dev/null nix eval .\#nixosConfigurations --apply builtins.attrNames --json` #export hosts_fhs := `2>/dev/null nix eval .\#systemConfigs --apply builtins.attrNames --json` @_default: just "$(gum filter --placeholder "Pick a recipie..." $(just --summary --unsorted))" @eval $hostname=`just _a_host` $attrpath="system.build.toplevel.outPath" *args: set -x; nix eval --log-format raw ".#nixosConfigurations.\"$hostname\".config.$attrpath" --show-trace "${@:3}" @eval-vm $hostname=`just _a_host` $attrpath="system.build.toplevel.outPath" *args: # set -x; nix eval --log-format raw ".#nixosConfigurations.\"$hostname\".config.system.build.vm.outPath" --show-trace "${@:3}" set -x; nix eval --log-format raw ".#nixosConfigurations.\"$hostname\".config.virtualisation.vmVariant.$attrpath" --show-trace "${@:3}" @eval-pkgs $hostname $attrpath *args: set -x; nix eval --log-format raw ".#nixosConfigurations.\"$hostname\".pkgs.$attrpath" --show-trace "${@:3}" repl $hostname=`just _a_host`: NIX_NO_NOM=1 nixos-rebuild-ng --flake .#"$hostname" repl why-depends $hostname $attrpath: nix why-depends .#nixosConfigurations."$hostname".config.system.build.toplevel .#nixosConfigurations."$hostname".pkgs."$attrpath" why-depends-drv $hostname $attrpath: nix why-depends .#nixosConfigurations."$hostname".config.system.build.toplevel.drvPath .#nixosConfigurations."$hostname".pkgs."$attrpath" report hostname=`just _a_host`: nix eval .#nixosReports."{{hostname}}" --json --show-trace | yq . --yaml-output --width=999999 | bat --language yaml --style plain --paging never reports: nix eval .#nixosReports --json --show-trace | yq . --yaml-output --width=999999 | bat --language yaml --style plain --paging never update: git reset flake.lock git restore flake.lock git pull --rebase --autostash nix flake update --commit-lock-file @mkdir -p .direnv/ @printf "%s\n" "$(date +%Y-%m-%d)" > .direnv/pull-date @update-select: git reset flake.lock git restore flake.lock nix eval --file flake.nix --apply 'x: builtins.attrNames x.inputs' --json \ | (printf "%s\n" --commit-lock-file; jq '.[]' -r | tr '0123456789' '9876543210' | sort | tr '0123456789' '9876543210' | grep -v "^self$") \ | gum choose --no-limit \ | xargs nix flake update git add flake.lock pull-dconf: ./users/pbsds/home/profiles/desktop/gnome/dconf-pull.sh git diff ./users/pbsds/home/profiles/desktop/gnome/ -gum confirm "git add --patch?" --default=no \ && git add --patch ./users/pbsds/home/profiles/desktop/gnome/ -gum confirm "git checkout --path?" --default=no \ && git checkout --patch ./users/pbsds/home/profiles/desktop/gnome/ # todo: support system-manager? # todo: support nix-darwin? # todo: support nixbsd? # todo: support nixng? build $hostname="" *_: #!/usr/bin/env -S bash -euo pipefail if [[ "${hostname::1}" = "-" ]]; then echo >&2 "WARNING(just): 'hostname' starts with '-', moving it to nix args..." set -- "" "$@"; hostname="" fi set -x; nixos-rebuild-ng build --accept-flake-config --show-trace --flake .#"$hostname" "${@:2}" build-vm hostname=`just _a_host` *_: #!/usr/bin/env -S bash -euo pipefail if [[ "${hostname::1}" = "-" ]]; then echo >&2 "WARNING(just): 'hostname' starts with '-', moving it to nix args..." set -- "" "$@"; hostname="" fi set -x; nixos-rebuild-ng build-vm --accept-flake-config --show-trace --flake .#"$hostname" "${@:2}" build-vm-and-run $hostname=`just _a_host` *_: #!/usr/bin/env -S bash -euo pipefail [[ -n "$hostname" ]] # TODO: setup ports? # TODO: attach serial instead of gui? # TODO: headless and ssh? just build-vm "$hostname" "${@:2}" set -x; ./result/bin/run-"$hostname"-vm # compares new closure against /run/current-system build-diff $hostname="" *_: #!/usr/bin/env -S bash -euo pipefail current_system="/run/current-system" new_system="$(just build "$hostname" "${@:2}")" echo >&2; set -x # nvd diff "$current_system" "$new_system" # python based, slow dix "$current_system" "$new_system" # rust based, fast, nixos-unstable only build-closure-size $hostname="" *_: #!/usr/bin/env -S bash -euo pipefail new_system="$(just build "$hostname" "${@:2}")" echo; set -x # nix path-info --recursive --size --closure-size --human-readable "$new_system" | sort -nk3 # broki nix path-info --recursive --size --closure-size "$new_system" | sort -nk3 | numfmt --field=2,3 --to iec test *_: #!/usr/bin/env -S bash -euo pipefail if [[ $# -gt 0 && "${1:-}" = "" ]]; then echo >&2 "WARNING(just): first arg is empty, popping it off..."; shift elif [[ $# -gt 0 && "${1::1}" != "-" ]]; then echo >&2 "WARNING(just): first arg does not start with "-", is it a hostname?" fi set -x; sudo nixos-rebuild-ng test --accept-flake-config --show-trace --flake . "$@" switch *_: #!/usr/bin/env -S bash -euo pipefail if [[ $# -gt 0 && "${1:-}" = "" ]]; then echo >&2 "WARNING(just): first arg is empty, popping it off..."; shift elif [[ $# -gt 0 && "${1::1}" != "-" ]]; then echo >&2 "WARNING(just): first arg does not start with "-", is it a hostname?" fi set -x; sudo nixos-rebuild-ng switch --accept-flake-config --show-trace --flake . "$@" boot *_: #!/usr/bin/env -S bash -euo pipefail if [[ $# -gt 0 && "${1:-}" = "" ]]; then echo >&2 "WARNING(just): first arg is empty, popping it off..."; shift elif [[ $# -gt 0 && "${1::1}" != "-" ]]; then echo >&2 "WARNING(just): first arg does not start with "-", is it a hostname?" fi set -x; sudo nixos-rebuild-ng boot --accept-flake-config --show-trace --flake . "$@" boot-and-reboot *_: #!/usr/bin/env -S bash -euo pipefail if [[ $# -gt 0 && "${1:-}" = "" ]]; then echo >&2 "WARNING(just): first arg is empty, popping it off..."; shift elif [[ $# -gt 0 && "${1::1}" != "-" ]]; then echo >&2 "WARNING(just): first arg does not start with "-", is it a hostname?" fi set -x sudo nixos-rebuild-ng boot --accept-flake-config --show-trace --flake . "$@" sudo reboot # TODO: can i somehow ensure that the sudo hasn't timed out by this time? # TODO: nixos-rebuild-ng push $hostname=`just _a_host` cmd=`gum choose test switch boot --header "Select mode..."`: #!/usr/bin/env -S bash -euo pipefail remote_sudo=1 gum confirm "Use '--use-remote-sudo'?" || remote_sudo=0 # build once first for nom output (set -x; nixos-rebuild build --flake .#"$hostname") || exit $? # target_host="root@$(nix eval --log-format raw ".#nixosConfigurations.\"$hostname\".config.networking.fqdn" --json | jq . -r)" target_host="$hostname" printf "%s\n" pushing... # nixos-rebuild will perform a build still, meaning another full eval... # TODO: support a simple copy-closure with no activation on remote if [[ "$remote_sudo" -eq 1 ]]; then # set -x; NIX_NO_NOM=1 NIX_SSHOPTS="-t" nixos-rebuild {{cmd}} --flake .#"$hostname" --target-host "$target_host" --use-substitutes --use-remote-sudo set -x; NIX_NO_NOM=1 IX_SSHOPTS="-o RequestTTY=force" nixos-rebuild {{cmd}} --flake .#"$hostname" --target-host "$target_host" --use-substitutes --use-remote-sudo else set -x; NIX_NO_NOM=1 nixos-rebuild {{cmd}} --flake .#"$hostname" --target-host "root@$target_host" --use-substitutes fi home-why-depends $attrpath: #!/usr/bin/env -S bash -euo pipefail hostname="$(hostname)" username="$(whoami)" set -x # assumes useGlobalPkgs nix why-depends \ .#nixosConfigurations."${hostname}".config.home-manager.users."${username}".home.activationPackage \ .#nixosConfigurations."${hostname}".pkgs."$attrpath" home-eval $attrpath="home.activationPackage" *_: #!/usr/bin/env -S bash -euo pipefail hostname="$(hostname)" username="$(whoami)" set -x nix eval --log-format raw .#nixosConfigurations."${hostname}".config.home-manager.users."${username}"."$attrpath" --show-trace "${@:2}" # TODO: fallback to .#homeConfigurations.$(whoami) ? # TODO: alternative behaviour for system-manager and nix-darwin home-build *_: #!/usr/bin/env -S bash -euo pipefail # home-manager build --flake . # home-manager build --flake .#nixosConfigurations.$(hostname).config.home-manager.users.$(whoami) hostname="$(hostname)" username="$(whoami)" set -x nom build .#nixosConfigurations."${hostname}".config.home-manager.users."${username}".home.activationPackage "${@:1}" # TODO: fallback to .#homeConfigurations.$(whoami) ? # TODO: alternative behaviour for system-manager and nix-darwin home-build-diff *_: home-build #!/usr/bin/env -S bash -euo pipefail current_home="${XDG_STATE_HOME:-"$HOME/.local/state"}/home-manager/gcroots/current-home" new_home="$(just home-build --print-out-paths "${@:1}")" echo >&2; set -x # nvd diff "$current_home" "$new_home" # python based, slow dix "$current_home" "$new_home" # rust based, fast, nixos-unstable only home-build-closure-size *_: #!/usr/bin/env -S bash -euo pipefail new_home="$(just home-build --print-out-paths "${@:1}")" set -x # nix path-info --recursive --size --closure-size --human-readable "$new_home" | sort -nk3 # broki nix path-info --recursive --size --closure-size "$new_home" | sort -nk3 | numfmt --field=2,3 --to iec home-switch *_: #!/usr/bin/env -S bash -euo pipefail new_home="$(just home-build --print-out-paths "${@:1}")" set -x # ./result/activate "$new_home"/activate # QoL alias hm-build := home-build alias hm-build-diff := home-build-diff alias hm-build-closure-size := home-build-closure-size alias hm-switch := home-switch alias build-home := home-build alias build-diff-home := home-build-diff alias build-closure-size-home := home-build-closure-size alias switch-home := home-switch # test-files $hostname=`just _a_host` *filenames: # #!/usr/bin/env -S bash -euo pipefail # # TODO: remember previous choices # [[ -n "$hostname" ]] || { printf >&2 "%s\n" "ERROR: no hostname"; false; } # declare -a filenames=("${@:2}") # if [[ "${#filenames[@]}" -eq 0 ]]; then # etcfiles=$( # nix eval ".#nixosConfigurations.\"$hostname\".config.environment.etc" --json \ # --apply 'builtins.mapAttrs (k: v: { inherit (v) enable target mode; })' # ) # homekeys=$( # nix eval ".#nixosConfigurations.\"$hostname\".config.home-manager.users" --json \ # --apply 'builtins.mapAttrs (user: config: { inherit (config.home) homeDirectory; files = builtins.mapAttrs (k: v: { inherit (v) enable target recursive; }) config.home.file; } )' # # | jq 'to_entries[]| .key as $user | .value.homeDirectory as $homeDirectory | .value.files | to_entries[] | select(.value) | [ "config.home-manager.users.\"\($user)\".home.file.\"\(.key)\"", $homeDirectory + "/" + .value.target, .value.target, .key, $user, $homeDirectory] | @tsv' -r # ) # filepathindex=$( # jq --null-input -c \ # --arg hostname "$hostname" \ # --argjson etcfiles "$etcfiles" \ # --argjson homekeys "$homekeys" \ # '{ # "nixosConfigurations.\"\($hostname)\".config.environment.etc": ( # $etcfiles | with_entries( select(.value.enable) | { key, value: (.value + { target : ("/etc/" + .value.target) }) } ) # ) # } + ( # $homekeys | with_entries( # .key as $user | # .value.homeDirectory as $homeDirectory | # { # key: ("nixosConfigurations.\"\($hostname)\".config.home-manager.users.\"\($user)\".home.file"), # value: ( # .value.files | with_entries( # select(.value.enable) | { # key, # value: (.value + { # target: ($homeDirectory + "/" + .value.target), # }), # } # ) # ), # } # ) # )' # ) # # cache # if [[ "$UID" -ne 0 ]]; then # mkdir -p .direnv/ # cat <<<"$filepathindex" >.direnv/just-cache-test-files-"$hostname".json # fi # else # [[ -s .direnv/just-cache-test-files-"$hostname".json ]] || { printf >&2 "%s\n" "ERROR: no cache found"; false; } # filepathindex=$(cat .direnv/just-cache-test-files-"$hostname".json) # fi # if [[ "${#filenames[@]}" -eq 0 ]]; then # filenames=$( # set +e # jq <<<"$filepathindex" 'to_entries[] | .value | to_entries[] | .value' -r \ # | fzf --height=50% --reverse --multi -d$'\t' --with-nth 2 # ) # [[ -n "$selection" ]] # fi # # jq <<<"$filepathindex" . ; false # filepathindex_inverse=$( # jq <<<"$filepathindex" 'with_entries( .key as $attr | .value | to_entries[] | {key: .value.target, value: (.value + {attr: $attr, key})} )' -c # ) # # jq <<<"$filepathindex_inverse" . ; false # # jq <<<"$filepathindex" 'to_entries[] | .key as $attr | .value | to_entries[] | @sh "\(.value) \($attr).\("\""+.key+"\"")"' -r # nix_expr=$( # printf "%s\n" 'pkgs.writeScript "do" (' # printf '"%s\\n" +\n' '#!${pkgs.runtimeShell}' # printf '"%s\\n" +\n' 'set -euo pipefail' # printf '"%s\\n" +\n' 'sudo : && SUDO=sudo || SUDO=:' # printf "%s\n" "${filenames[@]}" | # jq -sR --argjson index "$filepathindex_inverse" ' # split("\n") | map(select(.==""|not) | $index[.] ) | group_by(.attr) | map( # " (let cfg = \(.[0].attr); in '"''"'" + (map( # if .target | startswith("/etc/") then # if .mode == "symlink" and false then " # $SUDO ln -sfn ${cfg.\"\(.key)\".source} \(.target | @sh ) # " else " # $SUDO rm -rf \(.target | @sh ) # $SUDO cp -a ${cfg.\"\(.key)\".source} \(.target | @sh ) # $SUDO chown -R ${toString cfg.\"\(.key)\".uid}:${toString cfg.\"\(.key)\".gid} \(.target | @sh ) # $SUDO chmod -R ${toString cfg.\"\(.key)\".uid}:${toString cfg.\"\(.key)\".gid} \(.target | @sh ) # # TODO: cfg.\"\(.key)\".user # # TODO: cfg.\"\(.key)\".group # " end # else # if .recursive then # "${lib.getExe pkgs.xorg.lndir} -silent ${cfg.\"\(.key)\".source} \(.target | @sh )\n" # else # "ln -sfn ${cfg.\"\(.key)\".source} \(.target | @sh )\n" # end # end # ) | join("")) + "'"''"')" # ) | join(" + \n") # ' -r # printf "%s\n" ')' # ) # # printf "%s\n" "$nix_expr" ; false # flake=$(nix flake archive . --json | jq .path -r) # nix build --impure --expr "with (builtins.getFlake ''$flake''); let inherit (nixosConfigurations.\"$hostname\") pkgs; in $nix_expr" --show-trace # false # # TODO: run the result inspect: nix run -- nixpkgs#nix-inspect -p . inspect-config host=`just _a_host` prefix="": nix run -- nixpkgs#nix-inspect -e '(builtins.getFlake "'"$PWD"'").nixosConfigurations."{{host}}".config{{ if prefix == "" { "" } else { "." + prefix } }}' _nixos_attrnames: #!/usr/bin/env -S bash -euo pipefail hostname=$(hostname) cachefile=.direnv/just-cache-nixos-attrnames.txt if [[ flake.nix -nt "$cachefile" ]]; then hostnames=$(nix eval .#nixosConfigurations --apply builtins.attrNames --json 2>/dev/null | jq '.[]' -r) if [[ "$(grep <<<"$hostnames" -Fx "$hostname" | wc -l)" -eq 1 ]]; then hostnames="$(printf "%s\n" "$hostname"; grep <<<"$hostnames" -v "^$hostname$")" fi if [[ "$UID" -ne 0 ]]; then mkdir -p .direnv/ cat <<<"$hostnames" >"$cachefile" fi else hostnames="$(cat $cachefile)" fi current_remote=$(just remote-current) if [[ -n "$current_remote" && "$current_remote" != "$hostname" && "$(grep <<<"$hostnames" -Fx "$current_remote" | wc -l)" -eq 1 ]]; then head -n1 <<<"$hostnames" printf "%s\n" "$current_remote" tail -n+2 <<<"$hostnames" | grep -vFx "$current_remote" else printf "%s\n" "$hostnames" fi @_a_host: # just _nixos_attrnames | gum filter --placeholder "Pick a host..." # just _nixos_attrnames | fzf --reverse just _nixos_attrnames | fzf @_some_hosts: # just _nixos_attrnames | gum filter --placeholder "Pick a host..." --no-limit # just _nixos_attrnames | fzf --reverse --multi just _nixos_attrnames | fzf --multi _nixos_fqdns: #!/usr/bin/env -S bash -euo pipefail cachefile=.direnv/just-cache-nixos-fqdns.json if [[ flake.nix -nt "$cachefile" ]]; then mkdir -p .direnv/ fqdns=$(nix eval .#nixosConfigurations --apply 'builtins.mapAttrs (_: x: x.config.networking.fqdn)' --json 2>/dev/null) if [[ "$UID" -ne 0 ]]; then cat <<<"$fqdns" >"$cachefile" fi else fqdns=$( cat "$cachefile" ) fi just _nixos_attrnames | jq -R --argjson fqdns "$fqdns" '$fqdns[.]' -r @_a_fqdn: # just _nixos_fqdns | gum filter --placeholder "Pick a host..." # just _nixos_fqdns | fzf --reverse just _nixos_fqdns | fzf @_some_fqdns: # just _nixos_fqdns | gum filter --placeholder "Pick a host..." --no-limit # just _nixos_fqdns | fzf --reverse --multi just _nixos_fqdns | fzf --multi @remote-current: # remote-host # slow test ! -s .remote.toml || \ printf "%s\n" "$(tomlq <.remote.toml '.hosts | to_entries[] | select(.value.default==true) | .value.host' -r)" @remote-list: tomlq <.remote.toml '.hosts | to_entries[] | "remote-set \(.key+1) # -> \(.value.host)"' -r @remote-set remote=`just remote-current >&2 && just _a_remote_label`: remote-set "{{remote}}" motd: #!/usr/bin/env -S bash -euo pipefail printf "%s\n" "Current remote: $(just remote-current)" just remote-list printf "\n" todos=$(rg 'TODO' | wc -l) if [[ "$todos" -gt 10 ]]; then printf "%s\n" "There are $todos 'TODO's" fi sops-pubkey-user: #!/usr/bin/env -S bash -euo pipefail keyfile="${XDG_CONFIG_HOME:-"$HOME"/.config}"/sops/age/keys.txt if [[ ! -s "$keyfile" ]]; then gum confirm "Generate a new age key at $(hostname):$keyfile?" # otherwise error ( set -x mkdir -p "$(dirname "$keyfile")" age-keygen -o "$keyfile" >/dev/null ) fi age-keygen -y "$keyfile" sops-pubkey-system: #!/usr/bin/env -S bash -euo pipefail ssh-to-age