From 08090fa25cf272e399c660b2d63d7a4fe77e9e4a Mon Sep 17 00:00:00 2001 From: Mohammad Rafiq Date: Wed, 9 Jul 2025 04:20:46 +0800 Subject: [PATCH] feat(nix): add scripts for zk, edit, commit and rebuild --- nix/homes/rafiq/_scripts/commit.nix | 71 +++++++++++++ nix/homes/rafiq/_scripts/edit.nix | 12 +++ nix/homes/rafiq/_scripts/note.nix | 9 ++ nix/homes/rafiq/_scripts/rebuild.nix | 148 +++++++++++++++++++++++++++ nix/homes/rafiq/default.nix | 13 +-- 5 files changed, 244 insertions(+), 9 deletions(-) create mode 100644 nix/homes/rafiq/_scripts/commit.nix create mode 100644 nix/homes/rafiq/_scripts/edit.nix create mode 100644 nix/homes/rafiq/_scripts/note.nix create mode 100644 nix/homes/rafiq/_scripts/rebuild.nix diff --git a/nix/homes/rafiq/_scripts/commit.nix b/nix/homes/rafiq/_scripts/commit.nix new file mode 100644 index 0000000..f017e1d --- /dev/null +++ b/nix/homes/rafiq/_scripts/commit.nix @@ -0,0 +1,71 @@ +{ pkgs, ... }: +pkgs.writeShellScriptBin "commit" # bash + '' + if git diff-index --quiet HEAD --; then exit 0; fi + + PROMPT="Please generate a commit message for this diff." + GUIDELINES="1. Use conventional commit syntax, following the context. 2. Cap the commit message at 80 characters, preferably less. You must not go beyond this limit. 3. Do not include backticks. Only generate the raw text. 4. Be as succint as possible. Each commit should be atomic. You may throw a warning if it is not." + NUM_ANCESTORS=0 + PUSH=false + + # Parse arguments + while [[ $# -gt 0 ]]; do + case "$1" in + --num-ancestors | -n) + NUM_ANCESTORS="$2" + shift 2 + ;; + --push | -u) + PUSH=true + shift + ;; + *) + echo "Unrecognised argument: $1. Exiting..." + exit 1 + ;; + esac + done + + # Get context and diff + CONTEXT=$(git --no-pager log -n 10) + DIFF=$(git --no-pager diff HEAD~$NUM_ANCESTORS) + + # Generate initial response + RESPONSE=$(aichat "$PROMPT\nGuidelines: $GUIDELINES\nContext from git log:\n$CONTEXT\nDiff from git diff HEAD:\n$DIFF") + + while true; do + echo "$RESPONSE" + echo + echo "Choose an action:" + read -p "Options: [y]es, [r]eroll, [e]dit, [q]uit? " -n 1 -r choice + echo + + case "$choice" in + y | yes) + git commit -am "$RESPONSE" + echo "Committed successfully." + if $PUSH; then + git push + echo "Pushed successfully." + fi + exit 0 + ;; + r | reroll) + RESPONSE=$(aichat "$PROMPT\nGuidelines: $GUIDELINES\nContext from git log:\n$CONTEXT\nDiff from git diff HEAD:\n$DIFF") + ;; + e | edit) + echo "$RESPONSE" > /tmp/commit_msg.txt + "$EDITOR" /tmp/commit_msg.txt + RESPONSE=$(cat /tmp/commit_msg.txt) + rm /tmp/commit_msg.txt + ;; + q | quit | "") + echo "Aborted." + exit 1 + ;; + *) + echo "Invalid choice. Please choose again." + ;; + esac + done + '' diff --git a/nix/homes/rafiq/_scripts/edit.nix b/nix/homes/rafiq/_scripts/edit.nix new file mode 100644 index 0000000..bc5e973 --- /dev/null +++ b/nix/homes/rafiq/_scripts/edit.nix @@ -0,0 +1,12 @@ +{ pkgs, ... }: +let + finder = "${pkgs.fzf}/bin/fzf --preview 'cat {}'"; +in +pkgs.writeShellScriptBin "edit" # sh + '' + if [ $# -gt 0 ]; then + $EDITOR $(${finder} -q $*) + else + $EDITOR $(${finder}) + fi + '' diff --git a/nix/homes/rafiq/_scripts/note.nix b/nix/homes/rafiq/_scripts/note.nix new file mode 100644 index 0000000..0470fc2 --- /dev/null +++ b/nix/homes/rafiq/_scripts/note.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: +pkgs.writeShellScriptBin "note" # bash + '' + zk edit -i + pushd ~/notebook > /dev/null + git add . + commit -u + popd > /dev/null + '' diff --git a/nix/homes/rafiq/_scripts/rebuild.nix b/nix/homes/rafiq/_scripts/rebuild.nix new file mode 100644 index 0000000..223a4db --- /dev/null +++ b/nix/homes/rafiq/_scripts/rebuild.nix @@ -0,0 +1,148 @@ +{ pkgs }: +let + inherit (pkgs.lib) getExe; +in +pkgs.writeShellScriptBin "rebuild" # sh + '' + QUICK=false + NO_GENERATION_CHECK=false + TEST_SHELL=false + REMOTE_HOSTS=() + REBUILDING_ALL=false + # ANSI color codes + GREEN='\033[0;32m' + ORANGE='\033[0;33m' + RED='\033[0;31m' + NC='\033[0m' + + info() { + timestamp=$(date "+%Y-%m-%d %H:%M:%S") + echo -e "''${GREEN}''${timestamp} INFO: $1''${NC}" + } + + warn() { + timestamp=$(date "+%Y-%m-%d %H:%M:%S") + echo -e "''${ORANGE}''${timestamp} WARN: $1''${NC}" + } + + err() { + timestamp=$(date "+%Y-%m-%d %H:%M:%S") + echo -e "''${RED}''${timestamp} ERROR: $1''${NC}" + } + + prompt() { + local PROMPT="$1" + shift + read -p "$PROMPT? (y/n) [n]: " -n 1 -r REPLY + echo + if [[ "$REPLY" =~ ^[Yy]$ ]]; then + "$*" + else + info "$PROMPT aborted." + fi + } + + spawn_test_shell() { + info "Spawning test shell on $1..." + (export PS1="Test shell> " + exec ${pkgs.bash}/bin/bash ssh "$1") || { + ${pkgs.cowsay}/bin/cowsay "You aborted." + exit 1 + } + } + + rebuild_remote() { + local args=(".#nixosConfigurations.$1" "--target-host" "$1") + local CURRENT_GENERATION=$(ssh "$1" readlink /nix/var/nix/profiles/system | cut -d- -f2) + + if "$TEST_SHELL"; then + info "Testing $1..." + ${getExe pkgs.nh} os test "''${args[@]}" || exit 1 + git diff HEAD --color=always --stat --patch + spawn_test_shell "$1" + info "Rebuilding $1..." + ${getExe pkgs.nh} os boot "''${args[@]}" || exit 1 + else + info "Rebuilding $1 on $HOSTNAME..." + ${getExe pkgs.nh} os switch "''${args[@]}" || exit 1 + fi + + if ! "$NO_GENERATION_CHECK"; then + local NEW_GENERATION=$(ssh "$1" readlink /nix/var/nix/profiles/system | cut -d- -f2) + info "$1 - New generation is $NEW_GENERATION. Current is $CURRENT_GENERATION." + if [ ! $NEW_GENERATION -gt $CURRENT_GENERATION ]; then + warn "New config was not added to bootloader." + fi + fi + } + + info "Starting rebuild script." + + if [ ! -f "flake.nix" ]; then + err "flake.nix not found in the current directory. Exiting." + exit 1 # Indicate an error + fi + + while [[ $# -gt 0 ]]; do + case "$1" in + --quick | -q) + QUICK=true + shift + ;; + --no-generation-check | -n) + NO_GENERATION_CHECK=true + shift + ;; + --test-shell | -t) + TEST_SHELL=true + shift + ;; + --all | -a) + reachable_hosts=() + hostnames=$(nix flake show --all-systems --json | , jq -r '.nixosConfigurations | keys | .[]') + for host in ''${hostnames[@]}; do + info "Checking if $host is reachable..." + if ping -c 1 -W 1 "$host" > /dev/null 2>&1 ; then + info "$host is reachable." + reachable_hosts+=("$host") + else + warn "$host is unreachable." + fi + done + REMOTE_HOSTS=(''${reachable_hosts[@]}) + REBUILDING_ALL=true + shift + ;; + *) + if [ !REBUILDING_ALL ]; then + if ping -c 1 -W 1 "$1" > /dev/null 2>&1 ; then + REMOTE_HOSTS+=("$1") + else + err "$1 is unreachable. Exiting." + exit 1 + fi + fi + shift + ;; + esac + done + + if [ ''${#REMOTE_HOSTS[@]} == 0 ]; then + info "No hostnames provided." + REMOTE_HOSTS=("$HOSTNAME") + fi + + git add . + + for host in "''${REMOTE_HOSTS[@]}"; do + rebuild_remote $host + done + + if ! "$QUICK"; then + prompt "Commit changes" commit + prompt "Reboot system" sudo systemctl reboot + fi + + info "Rebuild script completed successfully." + exit 0 + '' diff --git a/nix/homes/rafiq/default.nix b/nix/homes/rafiq/default.nix index 02cdd25..ed01690 100644 --- a/nix/homes/rafiq/default.nix +++ b/nix/homes/rafiq/default.nix @@ -38,15 +38,10 @@ in fastfetch ripgrep aichat - (pkgs.writeShellScriptBin "note" # bash - '' - zk edit -i - pushd ~/notebook > /dev/null - git add . - commit -u - popd > /dev/null - '' - ) + (import ./_scripts/edit.nix { inherit pkgs; }) + (import ./_scripts/commit.nix { inherit pkgs; }) + (import ./_scripts/note.nix { inherit pkgs; }) + (import ./_scripts/rebuild.nix { inherit pkgs; }) ]; }; programs = {