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="" *args: #!/usr/bin/env -S bash -euo pipefail declare attrpath="${attrpath:-system.build.toplevel.outPath}" declare -a args=("${@:3}") [[ "$attrpath" =~ ^config\. ]] && attrpath="${attrpath:7}" ||: # pop optional 'config.' prefix set -x nix eval ".#nixosConfigurations.\"$hostname\".config.$attrpath" --show-trace "${args[@]}" eval-vm $hostname=`just _a_host` $attrpath="" *args: #!/usr/bin/env -S bash -euo pipefail declare attrpath="${attrpath:-system.build.toplevel.outPath}" declare -a args=("${@:3}") [[ "$attrpath" =~ ^config\. ]] && attrpath="${attrpath:7}" ||: # pop optional 'config.' prefix set -x # nix eval ".#nixosConfigurations.\"$hostname\".config.system.build.vm.outPath" --show-trace "${@:3}" nix eval ".#nixosConfigurations.\"$hostname\".config.virtualisation.vmVariant.$attrpath" --show-trace "${args[@]}" repl $hostname=`just _a_host`: NIX_NO_NOM=1 nixos-rebuild --flake .#"$hostname" repl 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 # todo: support system-manager # todo: support home-manager? build hostname="" *_: nixos-rebuild build --accept-flake-config --show-trace --flake .#"{{hostname}}" "${@:2}" build-vm hostname=`just _a_host` *_: nixos-rebuild build-vm --accept-flake-config --show-trace --flake .#"{{hostname}}" "${@:2}" build-vm-and-run $hostname=`just _a_host` *_: @# TODO: setup ports? @# TODO: attach serial instead of gui? @# TODO: headless and ssh? @just build-vm "$hostname" "${@:2}" ./result/bin/run-"$hostname"-vm test *_: sudo nixos-rebuild test --accept-flake-config --show-trace --flake . "$@" switch *_: sudo nixos-rebuild switch --accept-flake-config --show-trace --flake . "$@" boot *_: sudo nixos-rebuild boot --accept-flake-config --show-trace --flake . "$@" boot-and-reboot *_: sudo nixos-rebuild boot --accept-flake-config --show-trace --flake . "$@" sudo reboot push hostname=`just _a_host` cmd=`gum choose test switch boot --header "Select mode..."`: nixos-rebuild build --flake .#{{hostname}} @printf "%s\n" pushing... NIX_NO_NOM=1 nixos-rebuild {{cmd}} --flake .#{{hostname}} --target-host root@$(nix eval ".#nixosConfigurations.\"{{hostname}}\".config.networking.fqdn" --json | jq . -r) --use-substitutes #NIX_NO_NOM=1 NIX_SSHOPTS="-tt" nixos-rebuild {{cmd}} --flake .#"{{hostname}}" --use-remote-sudo --target-host $(nix eval .#nixosReports."{{hostname}}".fqdn --json | jq . -r) --use-substitutes 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 @_a_remote_label: just remote-list | gum filter --placeholder "Pick a remote..." | cut -d' ' -f2 @_some_remote_labels: just remote-list | gum filter --placeholder "Pick remotes..." --no-limit | cut -d' ' -f2 @_some_remote_label_names: just remote-list | gum filter --placeholder "Pick remotes..." --no-limit | tr ' ' '\t' | cut -f2,5 @_a_remote_fqdn: just remote-list | gum filter --placeholder "Pick a remote..." | cut -d' ' -f5- @_some_remote_fqdns: just remote-list | gum filter --placeholder "Pick remote..." --no-limit | cut -d' ' -f5- _remote_ensure $hostname=`just _a_fqdn`: #!/usr/bin/env -S bash -euo pipefail if test ! -s .remote.toml; then remote-init "$hostname" elif tomlq <.remote.toml '.hosts | to_entries[] |.value.host' -r | grep -q "$hostname"; then true else remote-add "$hostname" fi @_remote_label_from_fqdn hostname=`just _a_fqdn`: tomlq <.remote.toml '.hosts | to_entries[] | select(.value.host == "{{ hostname }}") | .key+1' -r remote-mprocs *cmd: #!/usr/bin/env -S bash -euo pipefail declare -a cmd=("$@") if [[ "${#cmd[@]}" -eq 0 ]]; then cmd=($(just --summary --unsorted | xargs printf "just %s\n" | gum filter --placeholder "Pick a recipie...")) [[ "${#cmd[@]}" -gt 0 ]] fi escaped_cmd="$(printf "%q " "${cmd[@]}")" declare -a labels=() declare -a names=() label_names=$(just _some_remote_label_names | grep .) readarray -td $'\n' labels < <( cut -f1 <<<"$label_names" ) readarray -td $'\n' names < <( cut -f2 <<<"$label_names" ) # TODO: when tmux exits the output is cleared # printf "remote --label=%q \"env NIX_NO_NOM=1 ${escaped_cmd//%/%%}\"\n" "${labels[@]}" | xargs -d'\n' mprocs --names "$(IFS=','; printf "%s" "${labels[*]}")" printf "tmux new \"remote --label=%q ${escaped_cmd//%/%%} ; read\" \; set-option destroy-unattached\n" "${labels[@]}" | xargs -d'\n' mprocs --names "$(IFS=','; printf "%s" "${names[*]}")" @remote-mprocs-init +$cmd=`printf "just %s\n" $(just --summary --unsorted) | gum filter --placeholder "Pick a recipie..."`: just _some_fqdns | xe -s 'just _remote_ensure "$1"; just _remote_label_from_fqdn "$1"' | sed -E 's/(.*)/remote --label="\1" "env NIX_NO_NOM=1 $cmd"/g' | xargs -d'\n' mprocs # TODO: support multiple labels, run in tmux #remote label=`just _a_remote_label` cmd=`printf "just %s\n" $(just --summary --unsorted) | gum filter --placeholder "Pick a recipie..."`: # remote --label={{label}} {{cmd}} # TODO: packaged as nix-web @gorgon: # https://codeberg.org/gorgon/gorgon/src/branch/main/nix-web # https://discourse.nixos.org/t/a-web-ui-for-the-nix-store-early-beta/35762 nix run 'git+https://codeberg.org/gorgon/gorgon#nix-web'