diff --git a/nyx/bash/nyx-cleanup.sh b/nyx/bash/nyx-cleanup.sh new file mode 100644 index 0000000..2bf0bdd --- /dev/null +++ b/nyx/bash/nyx-cleanup.sh @@ -0,0 +1,249 @@ +#!/usr/bin/env bash +# nyx-cleanup.sh — tokenized template +# Tokens replaced by Nix: +# @LOG_DIR@ @KEEP_GENERATIONS@ @AUTO_PUSH@ @GIT_BIN@ @VERSION@ + +nyx-cleanup() { + set -euo pipefail + + ######################################################################## + # CONFIG (injected by Nix) + ######################################################################## + log_dir="@LOG_DIR@" + keep_generations="@KEEP_GENERATIONS@" + auto_push="@AUTO_PUSH@" + git_bin="@GIT_BIN@" + version="@VERSION@" + + # Paths + log_dir_rebuild="${log_dir}/rebuild" + log_dir_cleanup="${log_dir}/cleanup" + timestamp=$(date '+%Y-%m-%d_%H-%M-%S') + summary_log="${log_dir_cleanup}/cleanup-${timestamp}.log" + + ######################################################################## + # COLORS + ######################################################################## + if [[ -t 1 ]]; then + RED=$'\e[31m'; GREEN=$'\e[32m'; YELLOW=$'\e[33m' + BLUE=$'\e[34m'; MAGENTA=$'\e[35m'; CYAN=$'\e[36m' + BOLD=$'\e[1m'; RESET=$'\e[0m' + else + RED=""; GREEN=""; YELLOW=""; BLUE=""; MAGENTA=""; CYAN=""; BOLD=""; RESET="" + fi + + ######################################################################## + # UTIL + ######################################################################## + say() { echo -e "$*"; } + action(){ say "${BOLD}${BLUE}➤ $*${RESET}"; } + ok() { say "${GREEN}✓${RESET} $*"; } + warn() { say "${YELLOW}!${RESET} $*"; } + nope() { say "${RED}✗${RESET} $*"; } + log() { echo -e "$*" | tee -a "$summary_log"; } + print_line() { log "\n${BOLD}==================================================${RESET}\n"; } + + # Lightweight git helpers (mirrors rebuild’s style) + g() { "$git_bin" "$@"; } + git_in_repo() { + local dir="$1" + [[ -d "$dir/.git" ]] || (cd "$dir" && g rev-parse --git-dir >/dev/null 2>&1) + } + git_commit_if_staged() { + if ! g diff --cached --quiet; then + g commit -m "$1" || true + return 0 + fi + return 1 + } + git_push_if_enabled() { + if [[ "$auto_push" == "true" ]]; then g push || true; fi + } + + ######################################################################## + # ARGS + ######################################################################## + DRYRUN=false + OVERRIDE_KEEP="" + while [[ $# -gt 0 ]]; do + case "$1" in + --dry-run) DRYRUN=true; shift;; + --keep) OVERRIDE_KEEP="${2:-}"; shift 2;; + -h|--help) + cat </dev/null 2>&1; then + nyx-tool "Nyx" "nyx-cleanup" "$version" \ + "Prune old NixOS generations, GC store, tidy logs" \ + "by Peritia-System" \ + "https://github.com/Peritia-System/Nyx-Tools" \ + "https://github.com/Peritia-System/Nyx-Tools/issues" \ + "Clean. Lean. Serene." + else + say "Nyx Tools — nyx-cleanup v${version}" + fi + + ######################################################################## + # PREP + ######################################################################## + mkdir -p "$log_dir_cleanup" + start_human=$(date '+%Y-%m-%d %H:%M:%S') + start_s=$(date +%s) + log "Started: ${start_human}" + print_line + + ######################################################################## + # STEP 1: Ensure sudo ticket + ######################################################################## + action "Checking sudo access…" + if sudo -n true 2>/dev/null; then + ok "Sudo already available." + else + say "Getting sudo ticket (you may be prompted)…" + if ! sudo -v; then nope "Cannot get sudo."; exit 1; fi + fi + + ######################################################################## + # STEP 2: Prune old *system* generations (keep newest K) + ######################################################################## + print_line + action "Pruning NixOS system generations (keeping ${keep_generations})…" + + # List generations oldest->newest + mapfile -t gens < <(sudo nix-env -p /nix/var/nix/profiles/system --list-generations | awk '{print $1}') + if (( ${#gens[@]} == 0 )); then + ok "No system generations found." + else + if (( ${#gens[@]} > keep_generations )); then + to_del_count=$(( ${#gens[@]} - keep_generations )) + to_del=( "${gens[@]:0:to_del_count}" ) + if [[ "$DRYRUN" == true ]]; then + log "[dry-run] sudo nix-env -p /nix/var/nix/profiles/system --delete-generations ${to_del[*]}" + else + sudo nix-env -p /nix/var/nix/profiles/system --delete-generations "${to_del[@]}" + ok "Removed ${to_del_count}; kept newest ${keep_generations}." + fi + else + ok "Generations (${#gens[@]}) ≤ keep (${keep_generations}); nothing to prune." + fi + fi + + ######################################################################## + # STEP 3: Garbage collect unreferenced store paths + ######################################################################## + print_line + action "Running Nix GC (and store optimise)…" + if [[ "$DRYRUN" == true ]]; then + log "[dry-run] sudo nix-collect-garbage -d" + log "[dry-run] sudo nix store optimise" + else + sudo nix-collect-garbage -d + # Optimise: dedup store (if subcommand exists) + if command -v nix >/dev/null 2>&1 && nix --help 2>&1 | grep -q 'store optimise'; then + sudo nix store optimise || true + fi + ok "GC complete." + fi + + ######################################################################## + # STEP 4: Tidy logs (rebuild + cleanup) + ######################################################################## + print_line + action "Tidying logs…" + + removed_any=false + + # (a) Remove unfinished rebuild logs + if [[ -d "$log_dir_rebuild" ]]; then + for pat in "rebuild-*.log" "Current-Error*.txt"; do + if compgen -G "${log_dir_rebuild}/${pat}" >/dev/null; then + if [[ "$DRYRUN" == true ]]; then + log "[dry-run] rm ${log_dir_rebuild}/${pat}" + else + rm -f ${log_dir_rebuild}/${pat} + removed_any=true + fi + fi + done + + # (b) Keep newest K final rebuild logs (nixos-gen_*-switch-*.log) + mapfile -t final_logs < <(ls -1 "${log_dir_rebuild}"/nixos-gen_*-switch-*.log 2>/dev/null | sort) + if (( ${#final_logs[@]} > keep_generations )); then + del_count=$(( ${#final_logs[@]} - keep_generations )) + to_del=( "${final_logs[@]:0:del_count}" ) + if [[ "$DRYRUN" == true ]]; then + log "[dry-run] rm ${to_del[*]}" + else + rm -f "${to_del[@]}" + removed_any=true + fi + ok "Rebuild logs: kept newest ${keep_generations}, removed ${del_count}." + else + ok "Rebuild logs count (${#final_logs[@]}) ≤ keep (${keep_generations}); nothing to delete." + fi + else + warn "Rebuild log dir not found: ${log_dir_rebuild}" + fi + + # (c) Keep cleanup dir itself trimmed (optional: keep last 10 summaries) + mapfile -t cleanup_logs < <(ls -1 "${log_dir_cleanup}"/cleanup-*.log 2>/dev/null | sort) + if (( ${#cleanup_logs[@]} > 10 )); then + del_count=$(( ${#cleanup_logs[@]} - 10 )) + to_del=( "${cleanup_logs[@]:0:del_count}" ) + if [[ "$DRYRUN" == true ]]; then + log "[dry-run] rm ${to_del[*]}" + else + rm -f "${to_del[@]}" + removed_any=true + fi + ok "Cleanup logs: kept newest 10, removed ${del_count}." + fi + + # (d) Commit/push log changes if logs live in a git repo + if [[ "$DRYRUN" == false && "$removed_any" == true ]]; then + log_root="$(dirname "$log_dir")" + if git_in_repo "$log_root"; then + ( + cd "$log_root" + g add "$(basename "$log_dir")" + git_commit_if_staged "cleanup: pruned logs & system generations" + git_push_if_enabled + ) + ok "Logged cleanup committed${auto_push:+ and pushed}." + fi + fi + + ######################################################################## + # SUMMARY + ######################################################################## + print_line + end_s=$(date +%s) + log "${BOLD}${CYAN}Cleanup Summary${RESET}" + log " Started: ${start_human}" + log " Duration: $(( end_s - start_s )) sec" + (( ${#gens[@]:-0} > 0 )) && log " Gens kept: ${keep_generations} (of ${#gens[@]})" + ok "Done." +} + +# Execute when sourced as a script +nyx-cleanup "$@" diff --git a/nyx/bash/nyx-rebuild.sh b/nyx/bash/nyx-rebuild.sh new file mode 100644 index 0000000..899e997 --- /dev/null +++ b/nyx/bash/nyx-rebuild.sh @@ -0,0 +1,387 @@ +#!/usr/bin/env bash +nyx-rebuild() { + set -euo pipefail + + ######################################################################## + # CONFIGURATION (injected by Nix) + ######################################################################## + nix_dir="@NIX_DIR@" + log_dir="@LOG_DIR@" + start_editor="@START_EDITOR@" + enable_formatting="@ENABLE_FORMATTING@" + editor_cmd="@EDITOR@" + formatter_cmd="@FORMATTER@" + git_bin="@GIT_BIN@" + nom_bin="@NOM_BIN@" + auto_push="@AUTO_PUSH@" + version="@VERSION@" + + ######################################################################## + # ARGUMENT PARSING + ######################################################################## + do_repair=false + do_update=false + while [[ $# -gt 0 ]]; do + case "$1" in + --repair) do_repair=true; shift;; + --update) do_update=true; shift;; + -h|--help) + cat <" + and remove any unfinished logs (Current-Error*.txt and rebuild-*.log + that are not final nixos-gen_* logs). + + --update Before rebuilding, update the flake in nix_dir using: + nix flake update +EOF + return 0 + ;; + *) echo "Unknown argument: $1" >&2; return 2;; + esac + done + + ######################################################################## + # COLORS (TTY only) + ######################################################################## + if [[ -t 1 ]]; then + RED=$'\e[31m'; GREEN=$'\e[32m'; YELLOW=$'\e[33m' + BLUE=$'\e[34m'; MAGENTA=$'\e[35m'; CYAN=$'\e[36m' + BOLD=$'\e[1m'; RESET=$'\e[0m' + else + RED=""; GREEN=""; YELLOW="" + BLUE=""; MAGENTA=""; CYAN="" + BOLD=""; RESET="" + fi + + ######################################################################## + # LIGHTWEIGHT GIT HELPERS + ######################################################################## + g() { "$git_bin" "$@"; } + + git_in_repo() { + local dir="$1" + [[ -d "$dir/.git" ]] || (cd "$dir" && g rev-parse --git-dir >/dev/null 2>&1) + } + + git_has_uncommitted_changes() { + # prints true if there are changes + [[ -n "$(g status --porcelain)" ]] + } + + git_pause_if_dirty() { + local attempts=0 + while git_has_uncommitted_changes; do + if (( attempts == 0 )); then + echo "${YELLOW}Uncommitted changes detected!${RESET}" + echo "${RED}Pausing for 5 seconds to allow cancel (Ctrl-C) before attempting repair...${RESET}" + sleep 5 + echo "Attempting repair..." + repair || true # never let a no-op commit kill the script + echo "repair ran" + ((attempts++)) || true + # loop will re-check cleanliness + else + echo "${YELLOW}Uncommitted changes still present after repair.${RESET}" + echo "${RED}Needs manual review. Continuing in 5 seconds...${RESET}" + sleep 5 + break + fi + done + } + + + + git_pull_rebase() { + g pull --rebase + } + + git_add_path() { + g add "$@" + } + + git_commit_if_staged() { + # commit if there is something staged; ignore empty + if ! g diff --cached --quiet; then + g commit -m "$1" || true + fi + } + + git_commit_message() { + local msg="$1" + g commit -m "$msg" + } + + git_push_if_enabled() { + if [[ "${auto_push}" == "true" ]]; then + g push + fi + } + + git_safe_add_commit_push() { + # Convenience: add paths, commit message, optional push + local msg="$1"; shift + git_add_path "$@" + if git_commit_if_staged "$msg"; then + git_push_if_enabled + fi + } + + + ######################################################################## + # REPAIR MODE + ######################################################################## + repair() { + cd "$nix_dir" || { echo "ERROR: Cannot cd into nix_dir: $nix_dir" >&2; return 1; } + + ts="$(date '+%Y-%m-%d_%H-%M-%S')" + echo "Starting repair at ${ts}..." + + # Remove unfinished logs (not final logs) + log_dir_rebuild="${log_dir}/rebuild" + if [[ -d "$log_dir_rebuild" ]]; then + echo "Checking for unfinished logs in: $log_dir_rebuild" + if find "$log_dir_rebuild" -type f \ + ! -name 'nixos-gen_*' \ + \( -name 'rebuild-*.log' -o -name 'Current-Error*.txt' \) | grep -q .; then + echo "Removing unfinished logs..." + find "$log_dir_rebuild" -type f \ + ! -name 'nixos-gen_*' \ + \( -name 'rebuild-*.log' -o -name 'Current-Error*.txt' \) \ + -exec rm -v {} + + echo "Unfinished logs removed." + else + echo "No unfinished logs found." + fi + else + echo "No rebuild log directory found." + fi + + echo "Staging all changes in $nix_dir..." + g add -A + + # Oed; avoid set nly commit if something is stag-e failure on empty commit + if ! g diff --cached --quiet --; then + echo "Committing repair changes..." + g commit -m "rebuild - repair ${ts}" + echo "Repair commit created." + else + echo "No changes to commit." + fi + + } + + + + + ######################################################################## + # LOGGING / COMMON HELPERS + ######################################################################## + start_time=$(date +%s) + start_human=$(date '+%Y-%m-%d %H:%M:%S') + stats_duration=0 + stats_gen="?" + stats_errors=0 + stats_last_error_lines="" + rebuild_success=false + exit_code=1 + + timestamp=$(date '+%Y-%m-%d_%H-%M-%S') + log_dir_rebuild="${log_dir}/rebuild" + build_log="${log_dir_rebuild}/rebuild-${timestamp}.log" + error_log="${log_dir_rebuild}/Current-Error-${timestamp}.txt" + + console-log() { echo -e "$@" | tee -a "$build_log"; } + print_line() { console-log ""; console-log "${BOLD}==================================================${RESET}"; console-log ""; } + + run_with_log() { + local tmp; tmp=$(mktemp) + ( "$@" 2>&1; echo $? > "$tmp" ) | tee -a "$build_log" + local s; s=$(<"$tmp"); rm "$tmp"; return "$s" + } + + run_with_log_rebuild() { + local tmp; tmp=$(mktemp) + ( "$@" 2>&1; echo $? > "$tmp" ) | tee -a "$build_log" | $nom_bin + local s; s=$(<"$tmp"); rm "$tmp"; return "$s" + } + + ######################################################################## + # EARLY REPAIR MODE CHECK + ######################################################################## + if [[ "$do_repair" == true ]]; then + ######################################################################## + # BANNER + ######################################################################## + echo + nyx-tool "Nyx" "nyx-rebuild --repair" "$version" \ + "Smart NixOS configuration repair" \ + "by Peritia-System" \ + "https://github.com/Peritia-System/Nyx-Tools" \ + "https://github.com/Peritia-System/Nyx-Tools/issues" \ + "Fixing our mistake... or yours" + echo + repair + rebuild_success=true + return 0 + fi + + finish_nyx_rebuild() { + stats_duration=$(( $(date +%s) - start_time )) + echo + if [[ "$rebuild_success" == true ]]; then + echo "${GREEN}${BOLD}NixOS Rebuild Complete${RESET}" + echo "${BOLD}${CYAN}Summary:${RESET}" + echo " Started: $start_human" + echo " Duration: ${stats_duration} sec" + echo " Generation: $stats_gen" + else + echo "${RED}${BOLD}NixOS Rebuild Failed${RESET}" + echo "${BOLD}${RED}Error Stats:${RESET}" + echo " Started: $start_human" + echo " Duration: ${stats_duration} sec" + echo " Error lines: ${stats_errors}" + [[ -n "$stats_last_error_lines" ]] && echo -e "${YELLOW}Last few errors:${RESET}$stats_last_error_lines" + fi + } + trap finish_nyx_rebuild EXIT + + ######################################################################## + # BANNER + ######################################################################## + echo + nyx-tool "Nyx" "nyx-rebuild" "$version" \ + "Smart NixOS configuration rebuilder" \ + "by Peritia-System" \ + "https://github.com/Peritia-System/Nyx-Tools" \ + "https://github.com/Peritia-System/Nyx-Tools/issues" \ + "Always up to date for you!" + echo + + ######################################################################## + # PREP + ######################################################################## + mkdir -p "$log_dir_rebuild" + cd "$nix_dir" || { echo "Cannot cd into nix_dir: $nix_dir" >&2; exit_code=1; return $exit_code; } + + ######################################################################## + # GIT DIRTY CHECK + ######################################################################## + echo -e "${BOLD}${BLUE}Checking Git status...${RESET}" + git_pause_if_dirty + + ######################################################################## + # NORMAL REBUILD FLOW... + ######################################################################## + + console-log "${BOLD}${BLUE}Pulling latest changes...${RESET}" + if ! run_with_log git pull --rebase; then + exit_code=1; return $exit_code + fi + + ######################################################################## + # OPTIONAL: editor + ######################################################################## + if [[ "$start_editor" == "true" ]]; then + console-log "${BOLD}${BLUE}Opening editor...${RESET}" + console-log "Started editing: $(date)" + run_with_log "$editor_cmd" + console-log "Finished editing: $(date)" + console-log "${BOLD}${CYAN}Changes summary:${RESET}" + run_with_log git diff --compact-summary + fi + + ######################################################################## + # OPTIONAL: formatter + ######################################################################## + if [[ "$enable_formatting" == "true" ]]; then + console-log "${BOLD}${MAGENTA}Running formatter...${RESET}" + run_with_log "$formatter_cmd" . + fi + + ######################################################################## + # REBUILD + ######################################################################## + + # Check if update: + print_line + if [[ "$do_update" == true ]]; then + console-log "${BOLD}${BLUE}Updating flake...${RESET}" + print_line + run_with_log nix flake update --verbose + if git_has_uncommitted_changes; then + git_add_path flake.lock + git_commit_if_staged "flake update: $(date '+%Y-%m-%d %H:%M:%S')" + fi + print_line + fi + + + console-log "${BOLD}${BLUE}Starting system rebuild...${RESET}" + + if find ~ -type f -name '*delme-HMbackup' | grep -q .; then + print_line + console-log "Removing old HM conf" + run_with_log find ~ -type f -name '*delme-HMbackup' -exec rm -v {} + + print_line + fi + + + if sudo -n true 2>/dev/null; then + console-log "Sudo rights already available" + else + console-log "Getting sudo ticket (please enter your password)" + run_with_log sudo whoami > /dev/null + fi + + print_line + console-log "Rebuild started: $(date)" + print_line + + run_with_log_rebuild sudo nixos-rebuild switch --flake "$nix_dir" + rebuild_status=$? + + if [[ $rebuild_status -ne 0 ]]; then + echo "${RED}Rebuild failed at $(date).${RESET}" > "$error_log" + stats_errors=$(grep -Ei -A 1 'error|failed' "$build_log" | tee -a "$error_log" | wc -l || true) + stats_last_error_lines=$(tail -n 10 "$error_log" || true) + + # capture and push error artifacts + git_add_path "$log_dir_rebuild" + g commit -m "Rebuild failed: errors logged" || true + git_push_if_enabled + + exit_code=1 + return $exit_code + fi + + ######################################################################## + # SUCCESS PATH + ######################################################################## + rebuild_success=true + exit_code=0 + + gen=$(nixos-rebuild list-generations | grep True | awk '{$1=$1};1' || true) + stats_gen=$(echo "$gen" | awk '{printf "%04d", $1}' || echo "0000") + + # Append summary to build log (before rotating file name) + finish_nyx_rebuild >> "$build_log" + + # Commit config changes (if any) + git_add_path -u + if git_commit_if_staged "Rebuild: $gen"; then + echo "${BLUE}Commit message:${RESET}${GREEN}Rebuild: $gen${RESET}" + fi + + # Move and add final log + final_log="$log_dir_rebuild/nixos-gen_${stats_gen}-switch-${timestamp}.log" + mv "$build_log" "$final_log" + git_add_path "$final_log" + git_commit_if_staged "log for $gen" || echo "${YELLOW}No changes in logs to commit.${RESET}" + + git_push_if_enabled && echo "${GREEN}Changes pushed to remote.${RESET}" || true +} + +# Execute when sourced as a script +nyx-rebuild "$@" diff --git a/other/bash/nyx-tool.sh b/nyx/bash/nyx-tool.sh similarity index 57% rename from other/bash/nyx-tool.sh rename to nyx/bash/nyx-tool.sh index b9d4c13..f8b3140 100644 --- a/other/bash/nyx-tool.sh +++ b/nyx/bash/nyx-tool.sh @@ -51,51 +51,4 @@ nyx-tool() { echo "" } -# Spinner with timing -nyx-show_spinner() { - local pid=$1 - local spinner_delay=0.1 - local spinstr='|/-\' - local start_time - start_time=$(date +%s%3N) - - local CYAN="\033[38;5;51m" - local GREEN="\033[38;5;82m" - local RESET="\033[0m" - - echo -ne "${CYAN}⏳ Starting rebuild...${RESET} " - - ( - while kill -0 "$pid" 2>/dev/null; do - local now elapsed seconds milliseconds clock_time - now=$(date +%s%3N) - elapsed=$((now - start_time)) - seconds=$((elapsed / 1000)) - milliseconds=$((elapsed % 1000)) - clock_time=$(date +%T) - - for i in $(seq 0 3); do - printf "\r${CYAN}⏳ [%s] %s [%d.%03ds] ${RESET}" "$clock_time" "${spinstr:$i:1}" "$seconds" "$milliseconds" - sleep "$spinner_delay" - done - done - ) & - local spinner_pid=$! - - wait "$pid" - local exit_status=$? - - kill "$spinner_pid" 2>/dev/null - wait "$spinner_pid" 2>/dev/null - - local end_time total_elapsed total_sec total_ms end_clock_time - end_time=$(date +%s%3N) - total_elapsed=$((end_time - start_time)) - total_sec=$((total_elapsed / 1000)) - total_ms=$((total_elapsed % 1000)) - end_clock_time=$(date +%T) - - echo -e "\r${GREEN}✅ Completed at ${end_clock_time}, total: ${total_sec}.${total_ms}s${RESET} " - - return $exit_status -} +nyx-tool "$@" diff --git a/nyx/default.nix b/nyx/default.nix index 75328dc..b8217ac 100644 --- a/nyx/default.nix +++ b/nyx/default.nix @@ -1,17 +1,53 @@ -# Import all modules so only needs to Import nyx.nix - - -{ config, pkgs, lib, nixDirectory, ... }: +# nyx.nix +{ config, lib, ... }: +with lib; { + ################################################################ + # Global Nyx Options + ################################################################ + options.nyx = { + enable = mkEnableOption "Enable all Nyx tools"; + + username = mkOption { + type = types.str; + description = "Username for Nyx tools"; + }; + + nixDirectory = mkOption { + type = types.path; + description = "Path to NixOS flake directory"; + }; + + logDir = mkOption { + type = types.path; + default = "/home/${config.nyx.username}/.nyx/logs"; + description = "Directory for Nyx logs"; + }; + + autoPush = mkOption { + type = types.bool; + default = false; + description = "Automatically push changes after rebuild/cleanup"; + }; + }; + + ################################################################ + # Import submodules + ################################################################ imports = [ - # System modules - # Rebuild ./nyx-rebuild.nix - # Custom Banner - ./nyx-tool.nix - # Nyx cleanup ./nyx-cleanup.nix + ./nyx-tool.nix ]; + ################################################################ + # Global disable logic + ################################################################ + config = mkIf (!config.nyx.enable) { + nyx.nyx-rebuild.enable = false; + nyx.nyx-cleanup.enable = false; + nyx.nyx-tool.enable = false; + }; + } diff --git a/nyx/nyx-cleanup.nix b/nyx/nyx-cleanup.nix index 841e86d..b9f1587 100644 --- a/nyx/nyx-cleanup.nix +++ b/nyx/nyx-cleanup.nix @@ -1,40 +1,35 @@ { config, lib, pkgs, ... }: let - cfg = config.nyx.nyx-cleanup; - logDirDefault = "/home/${toString cfg.username}/.nyx/nyx-cleanup/logs"; -in + nyxCfg = config.nyx or {}; + cfg = nyxCfg."nyx-cleanup" or {}; + # Read the cleanup script template and replace tokens + cleanupScript = + let + src = builtins.readFile ./bash/nyx-cleanup.sh; # Script with @TOKENS@ + in + builtins.replaceStrings + [ + "@LOG_DIR@" "@KEEP_GENERATIONS@" "@AUTO_PUSH@" "@GIT_BIN@" "@VERSION@" + ] + [ + (toString nyxCfg.logDir) + (toString (cfg.keepGenerations or 5)) + (if (nyxCfg.autoPush or false) then "true" else "false") + "${pkgs.git}/bin/git" + "1.0.0" + ] + src; +in { - options.nyx.nyx-cleanup = { + options.nyx."nyx-cleanup" = { enable = lib.mkEnableOption "Enable nyx-cleanup script"; - username = lib.mkOption { - type = lib.types.str; - description = "The user this module applies to."; - }; - - nixDirectory = lib.mkOption { - type = lib.types.path; - description = "Path to NixOS flake configuration."; - }; - - logDir = lib.mkOption { - type = lib.types.str; - default = logDirDefault; - description = "Directory for storing cleanup logs."; - }; - keepGenerations = lib.mkOption { type = lib.types.int; default = 5; - description = "Number of NixOS generations to keep."; - }; - - autoPush = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Whether to auto-push git commits after cleanup."; + description = "Number of NixOS *system* generations to keep."; }; enableAlias = lib.mkOption { @@ -44,132 +39,12 @@ in }; }; - config = lib.mkIf cfg.enable { + config = lib.mkIf ((nyxCfg.enable or false) && (cfg.enable or false)) { home.packages = [ - (pkgs.writeShellScriptBin "nyx-cleanup" '' - - #!/usr/bin/env bash - nyx-cleanup(){ - set -euo pipefail - - # === CONFIGURATION === - log_dir="${toString cfg.logDir}" - keep_generations=${toString cfg.keepGenerations} - auto_push=${if cfg.autoPush then "true" else "false"} - git_bin="${pkgs.git}/bin/git" - - # Derived repo dir (assumes: ~/.nyx/nyx-cleanup/logs → ~/.nyx) - repo_dir="$(dirname "$(dirname "$log_dir")")" - - # === INITIAL SETUP === - version="1.0.0" - start_time=$(date +%s) - start_human=$(date '+%Y-%m-%d %H:%M:%S') - cleanup_success=false - exit_code=1 - - # === COLORS === - if [[ -t 1 ]]; then - RED=$'\e[31m'; GREEN=$'\e[32m'; YELLOW=$'\e[33m' - BLUE=$'\e[34m'; MAGENTA=$'\e[35m'; CYAN=$'\e[36m' - BOLD=$'\e[1m'; RESET=$'\e[0m' - else - RED=""; GREEN=""; YELLOW="" - BLUE=""; MAGENTA=""; CYAN="" - BOLD=""; RESET="" - fi - - # === LOGGING === - mkdir -p "$log_dir" - timestamp=$(date '+%Y-%m-%d_%H-%M-%S') - cleanup_log="$log_dir/cleanup-''${timestamp}.log" - - console-log() { - echo -e "$@" | tee -a "$cleanup_log" - } - - print_line() { - console-log "" - console-log "''${BOLD}==================================================''${RESET}" - console-log "" - } - - finish_cleanup() { - duration=$(( $(date +%s) - start_time )) - if [[ "$cleanup_success" == true ]]; then - echo -e "''${GREEN}''${BOLD} -############################## -# ✅ Nyx Cleanup Complete! # -##############################''${RESET}" - echo -e "''${CYAN}''${BOLD}📋 Stats:''${RESET}" - echo " 🕒 Started: $start_human" - echo " ⏱️ Duration: ''${duration} sec" - else - echo -e "''${RED}''${BOLD} -############################## -# ❌ Nyx Cleanup Failed! # -##############################''${RESET}" - echo " 🕒 Started: $start_human" - echo " ⏱️ Duration: ''${duration} sec" - fi - } - - trap finish_cleanup EXIT - - print_line - console-log "''${BLUE}''${BOLD}🧹 Starting cleanup...''${RESET}" - - # === REMOVE OLD LOGS === - console-log "''${CYAN}''${BOLD}🗑️ Removing logs older than 30 days...''${RESET}" - find "$log_dir" -type f -mtime +30 -print -delete - - # === REMOVE HOME MANAGER BACKUPS === - print_line - console-log "''${CYAN}''${BOLD}📁 Deleting Home Manager backup files...''${RESET}" - find ~ -type f -name '*delme-HMbackup' -print -delete - - # === GARBAGE COLLECTION === - print_line - console-log "''${MAGENTA}''${BOLD}🧼 Running Nix garbage collection...''${RESET}" - sudo nix-collect-garbage -d | tee -a "$cleanup_log" - - # === GIT SETUP === - print_line - if [[ ! -d "$repo_dir/.git" ]]; then - console-log "''${YELLOW}⚠️ No git repo in: $repo_dir. Initializing...''${RESET}" - "$git_bin" -C "$repo_dir" init | tee -a "$cleanup_log" - fi - - # === GIT AUTO PUSH === - if [[ "$auto_push" == "true" ]]; then - print_line - console-log "''${BLUE}''${BOLD}🚀 Auto-pushing git commits in $repo_dir...''${RESET}" - cd "$repo_dir" - - if "$git_bin" remote | grep -q .; then - "$git_bin" add . - "$git_bin" commit -m "chore(cleanup): auto cleanup $(date)" || true - "$git_bin" push - else - console-log "''${YELLOW}⚠️ No git remote configured. Skipping push.''${RESET}" - console-log "''${YELLOW}📂 Check logs in: $log_dir''${RESET}" - fi - fi - - cleanup_success=true - exit_code=0 - - print_line - console-log "''${GREEN}🎉 Cleanup finished successfully!''${RESET}" - print_line - } - nyx-cleanup - - - '') + (pkgs.writeShellScriptBin "nyx-cleanup" cleanupScript) ]; - home.shellAliases = lib.mkIf cfg.enableAlias { + home.shellAliases = lib.mkIf (cfg.enableAlias or true) { nc = "nyx-cleanup"; }; }; diff --git a/nyx/nyx-rebuild.nix b/nyx/nyx-rebuild.nix index 61e6c62..a543fc7 100644 --- a/nyx/nyx-rebuild.nix +++ b/nyx/nyx-rebuild.nix @@ -1,295 +1,51 @@ { config, lib, pkgs, ... }: let - cfg = config.nyx.nyx-rebuild; - nixDirStr = toString cfg.nixDirectory; - logDirDefault = "/home/${cfg.username}/.nyx/nyx-rebuild/logs"; + nyxCfg = config.nyx; + cfg = nyxCfg."nyx-rebuild"; + + # Read template and inject values + rebuiltScript = + let + src = builtins.readFile ./bash/nyx-rebuild.sh; # uses @TOKENS@, not ${...} + in + builtins.replaceStrings + [ + "@NIX_DIR@" "@LOG_DIR@" "@START_EDITOR@" "@ENABLE_FORMATTING@" + "@EDITOR@" "@FORMATTER@" "@GIT_BIN@" "@NOM_BIN@" "@AUTO_PUSH@" "@VERSION@" + ] + [ + (toString nyxCfg.nixDirectory) + (toString nyxCfg.logDir) + (if cfg.startEditor then "true" else "false") + (if cfg.enableFormatting then "true" else "false") + cfg.editor + cfg.formatter + "${pkgs.git}/bin/git" + "${pkgs.nix-output-monitor}/bin/nom" + (if nyxCfg.autoPush then "true" else "false") + "1.0.0" + ] + src; in { - options.nyx.nyx-rebuild = { + options.nyx."nyx-rebuild" = { enable = lib.mkEnableOption "Enable nyx-rebuild script"; - username = lib.mkOption { - type = lib.types.str; - description = "User this module applies to."; - }; - - nixDirectory = lib.mkOption { - type = lib.types.path; - description = "Path to NixOS flake configuration."; - }; - - logDir = lib.mkOption { - type = lib.types.str; - default = logDirDefault; - description = "Directory for storing cleanup logs."; - }; - - editor = lib.mkOption { - type = lib.types.str; - default = "nvim"; - description = "Editor for manual editing step."; - }; - - formatter = lib.mkOption { - type = lib.types.str; - default = "alejandra"; - description = "Formatter to use before rebuild."; - }; - - startEditor = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Start editor before rebuild."; - }; - - enableFormatting = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Format Nix files before rebuild."; - }; - - autoPushLog = lib.mkOption { - type = lib.types.bool; - default = false; - description = "If true, automatically push $git_bin commits containing rebuild logs."; - }; - - autoPushNixDir = lib.mkOption { - type = lib.types.bool; - default = false; - description = "If true, push $git_bin commits in nixDirectory (configuration repo) after rebuild."; - }; - - enableAlias = lib.mkOption { - type = lib.types.bool; - default = true; - description = "Add 'nr' alias for nyx-rebuild."; - }; + editor = lib.mkOption { type = lib.types.str; default = "nvim"; }; + formatter = lib.mkOption { type = lib.types.str; default = "alejandra"; }; + startEditor = lib.mkOption { type = lib.types.bool; default = false; }; + enableFormatting = lib.mkOption { type = lib.types.bool; default = false; }; + enableAlias = lib.mkOption { type = lib.types.bool; default = true; }; }; - config = lib.mkIf cfg.enable { - programs.zsh.enable = lib.mkDefault true; - - home.packages = [ - # Add formatter if selected - ] ++ lib.optional (cfg.enableFormatting && cfg.formatter == "alejandra") pkgs.alejandra - ++ [ - # Main script - (pkgs.writeShellScriptBin "nyx-rebuild" '' -#!/usr/bin/env bash -nyx-rebuild () { -set -euo pipefail - -# === CONFIGURATION === -nix_dir="${nixDirStr}" -log_dir="${toString cfg.logDir}" -start_editor="${if cfg.startEditor then "true" else "false"}" -enable_formatting="${if cfg.enableFormatting then "true" else "false"}" -editor_cmd="${cfg.editor}" -formatter_cmd="${cfg.formatter}" -auto_push_log="${if cfg.autoPushLog then "true" else "false"}" -auto_push_nixdir="${if cfg.autoPushNixDir then "true" else "false"}" -git_bin="${pkgs.git}/bin/git" -nom_bin="${pkgs.nix-output-monitor}/bin/nom" - -# === INITIAL SETUP === -version="beta-2.0.0" -start_time=$(date +%s) -start_human=$(date '+%Y-%m-%d %H:%M:%S') -stats_duration=0 -stats_gen="?" -stats_errors=0 -stats_last_error_lines="" -rebuild_success=false -exit_code=1 - -# === COLORS === -if [[ -t 1 ]]; then - RED=$'\e[31m'; GREEN=$'\e[32m'; YELLOW=$'\e[33m' - BLUE=$'\e[34m'; MAGENTA=$'\e[35m'; CYAN=$'\e[36m' - BOLD=$'\e[1m'; RESET=$'\e[0m' -else - RED=""; GREEN=""; YELLOW="" - BLUE=""; MAGENTA=""; CYAN="" - BOLD=""; RESET="" -fi - -# === LOGGING SETUP === -hostname=$(hostname) -mkdir -p "$log_dir" -timestamp=$(date '+%Y-%m-%d_%H-%M-%S') -build_log="$log_dir/build-''${timestamp}.log" -error_log="$log_dir/Current-Error-''${timestamp}.txt" - -# === HELPERS === -console-log() { - echo -e "$@" | tee -a "$build_log" -} - -print_line() { - console-log "" - console-log "''${BOLD}==================================================''${RESET}" - console-log "" -} - -run_with_log() { - local cmd_output - cmd_output=$(mktemp) - ( - "$@" 2>&1 - echo $? > "$cmd_output" - ) | tee -a "$build_log" - local status - status=$(<"$cmd_output") - rm "$cmd_output" - return "$status" -} - -run_with_log_rebuild() { - local cmd_output - cmd_output=$(mktemp) - ( - "$@" 2>&1 - echo $? > "$cmd_output" - ) | tee -a "$build_log" | $nom_bin - local status - status=$(<"$cmd_output") - rm "$cmd_output" - return "$status" -} - -finish_nyx_rebuild() { - stats_duration=$(( $(date +%s) - start_time )) - echo - if [[ "$rebuild_success" == true ]]; then - echo "''${GREEN}''${BOLD} -############################## -# ✅ NixOS Rebuild Complete! # -##############################''${RESET}" - echo "''${BOLD}''${CYAN}🎯 Success Stats:''${RESET}" - echo " 🕒 Started: $start_human" - echo " ⏱️ Duration: ''${stats_duration} sec" - echo " 📦 Gen: $stats_gen" - else - echo "''${RED}''${BOLD} -############################## -# ❌ NixOS Rebuild Failed! # -##############################''${RESET}" - echo "''${BOLD}''${RED}🚨 Error Stats:''${RESET}" - echo " 🕒 Started: $start_human" - echo " ⏱️ Duration: ''${stats_duration} sec" - echo " ❌ Error lines: ''${stats_errors}" - [[ -n "$stats_last_error_lines" ]] && echo -e "\n''${YELLOW}🧾 Last few errors:''${RESET}\n$stats_last_error_lines" - fi -} - -trap finish_nyx_rebuild EXIT - -# === TOOL INFO === -echo -nyx-tool "Nyx" "nyx-rebuild" "$version" \ - "Smart NixOS configuration rebuilder" \ - "by Peritia-System" \ - "https://github.com/Peritia-System/Nyx-Tools" \ - "https://github.com/Peritia-System/Nyx-Tools/issues" \ - "Always up to date for you!" -echo - -# === PROJECT PREP === -cd "$nix_dir" || { exit_code=1; return $exit_code; } - -# === CHECK FOR UNCOMMITTED CHANGES === -echo "\n''${BOLD}''${BLUE}📁 Checking $git_bin status...''${RESET}" -if [[ -n $($git_bin status --porcelain) ]]; then - echo "''${YELLOW}⚠️ Uncommitted changes detected!''${RESET}" - echo "''${RED}⏳ 5s to cancel...''${RESET}" - sleep 5 -fi - -# === SCRIPT START === -print_line -console-log "''${BLUE}''${BOLD}🚀 Starting Nyx Rebuild...''${RESET}" - -# === GIT PULL === -console-log "\n''${BOLD}''${BLUE}⬇️ Pulling latest changes...''${RESET}" -run_with_log $git_bin pull --rebase || return 1 - -# === OPTIONAL: OPEN EDITOR === -if [[ "$start_editor" == "true" ]]; then - console-log "\n''${BOLD}''${BLUE}📝 Editing configuration...''${RESET}" - run_with_log "$editor_cmd" -fi - -# === OPTIONAL: FORMAT FILES === -if [[ "$enable_formatting" == "true" ]]; then - console-log "\n''${BOLD}''${MAGENTA}🎨 Running formatter...''${RESET}" - run_with_log "$formatter_cmd" . -fi - -# === GIT DIFF === -console-log "\n''${BOLD}''${CYAN}🔍 Changes summary:''${RESET}" -run_with_log $git_bin diff --compact-summary - -# === SYSTEM REBUILD === -print_line -console-log "''${BLUE}''${BOLD}🔧 Starting system rebuild...''${RESET}" -console-log "🛠️ Removing old HM conf" -run_with_log find ~ -type f -name '*delme-HMbackup' -exec rm -v {} + -print_line -console-log "Getting sudo ticket" -run_with_log sudo whoami > /dev/null -print_line -console-log "🛠️ Rebuild started: $(date)" - - -run_with_log_rebuild sudo nixos-rebuild switch --flake "$nix_dir" -rebuild_status=$? - -if [[ $rebuild_status -ne 0 ]]; then - echo "''${RED}❌ Rebuild failed at $(date).''${RESET}" > "$error_log" - stats_errors=$(grep -Ei -A 1 'error|failed' "$build_log" | tee -a "$error_log" | wc -l) - stats_last_error_lines=$(tail -n 10 "$error_log") - cd "$log_dir" - $git_bin add "$build_log" - $git_bin commit -m "chore(rebuild): failed rebuild on $(date)" || true - [[ "$auto_push_nixdir" == "true" ]] && (cd "$nix_dir" && $git_bin push || true) - cd "$nix_dir" - return 1 -fi - -# === SUCCESS FLOW === -rebuild_success=true -gen=$(nixos-rebuild list-generations | grep True | awk '{$1=$1};1') -stats_gen=$(echo "$gen" | awk '{printf "%04d\n", $1}') -finish_nyx_rebuild >> "$build_log" - -$git_bin add "$build_log" -$git_bin add -u -$git_bin commit -m "Rebuild: $gen" || true - -cd "$log_dir" -final_log="$log_dir/nixos-gen_''${stats_gen}-switch-''${timestamp}.log" -$git_bin add "$build_log" -mv "$build_log" "$final_log" -$git_bin add "$build_log" -$git_bin add "$final_log" -$git_bin commit -m "log for $gen" || true - -# === FINAL PUSH LOGS === -$git_bin add "$log_dir" -$git_bin commit -m "chore(rebuild): successful rebuild on $(date)" || true - -if [[ "$auto_push_log" == "true" ]]; then - (cd "$repo_dir" && $git_bin push || true) -fi -cd "$nix_dir" - -echo -e "\n''${GREEN}🎉 Nyx rebuild completed successfully!''${RESET}" -} -nyx-rebuild - '') - ]; + config = lib.mkIf (nyxCfg.enable && cfg.enable) { + home.packages = + lib.optionals (cfg.enableFormatting && cfg.formatter == "alejandra") [ pkgs.alejandra ] + ++ [ + # Ensure nyx-tool exists if you call it in the script + (pkgs.writeShellScriptBin "nyx-rebuild" rebuiltScript) + ]; home.shellAliases = lib.mkIf cfg.enableAlias { nr = "nyx-rebuild"; diff --git a/nyx/nyx-tool.nix b/nyx/nyx-tool.nix index d4fa58d..c27cb6f 100644 --- a/nyx/nyx-tool.nix +++ b/nyx/nyx-tool.nix @@ -5,75 +5,16 @@ let in { options.nyx.nyx-tool = { - enable = lib.mkEnableOption "Enable nyx-tool Script for Banner display."; - - nixDirectory = lib.mkOption { - type = lib.types.str; - description = "Path to the main Nix directory used for scripts."; - }; + enable = lib.mkEnableOption "Enable nyx-tool banner script"; }; config = lib.mkIf cfg.enable { programs.zsh.enable = lib.mkDefault true; - - home.packages = - [ pkgs.figlet ] - ++ [ - (pkgs.writeShellScriptBin "nyx-tool" '' -#!/usr/bin/env bash -nyx-tool() { -# nyx-tool: reusable metadata banner printer with Base16 theme - local logo="''${1:-Nyx}" - local name="''${2:-nix-script}" - local version="''${3:-Version Unknown - Please Open Issue}" - local description="''${4:-A Nix utility}" - local credit="''${5:-Peritia-System}" - local github="''${6:-https://github.com/example/repo}" - local issues="''${7:-''${github}/issues}" - local message="''${8:-Use responsibly}" - - # Base16 color palette (ANSI escape codes) - local RESET="\033[0m" - local BOLD="\033[1m" - local HEADER="\033[38;5;33m" # blue - local LABEL="\033[38;5;70m" # green - local VALUE="\033[38;5;250m" # gray - local EMPHASIS="\033[38;5;196m" # red - local CYAN="\033[38;5;51m" - local GREEN="\033[38;5;82m" - - local line - line=$(printf '=%.0s' $(seq 1 35)) - - echo "" - echo -e "''${HEADER}''${line}''${RESET}" - echo -e "''${HEADER}=====[ ''${BOLD}Peritia System Tools''${RESET}''${HEADER} ]=====''${RESET}" - echo -e "''${VALUE}''${BOLD}" - - # Figlet logo rendering - if command -v figlet &>/dev/null; then - figlet -f banner3 "$logo" | sed 's/#/█/g' - else - echo "$logo" - fi - - echo -e "''${RESET}''${HEADER}by Peritia-System''${RESET}" - echo -e "''${HEADER}''${line}''${RESET}" - echo "" - - echo -e "''${LABEL}🛠️ Name: ''${VALUE}''${name}''${RESET}" - echo -e "''${LABEL}🏷️ Version: ''${VALUE}''${version}''${RESET}" - echo -e "''${LABEL}📝 Description: ''${VALUE}''${description}''${RESET}" - echo -e "''${LABEL}👤 Credit: ''${VALUE}''${credit}''${RESET}" - echo -e "''${LABEL}🌐 GitHub: ''${VALUE}''${github}''${RESET}" - echo -e "''${LABEL}🐛 Issues: ''${VALUE}''${issues}''${RESET}" - echo "" - echo -e "''${LABEL}📌 Message: ''${BOLD}''${message}''${RESET}" - echo "" - - } - nyx-tool "$@" - '') - ]; + home.packages = [ + pkgs.figlet + (pkgs.writeShellScriptBin "nyx-tool" + (builtins.readFile ./bash/nyx-tool.sh) + ) + ]; }; } diff --git a/other/bash/nyx-rebuild.sh b/other/bash/nyx-rebuild.sh.old similarity index 100% rename from other/bash/nyx-rebuild.sh rename to other/bash/nyx-rebuild.sh.old diff --git a/other/example/configuration.nix b/other/example/example-configuration.nix similarity index 100% rename from other/example/configuration.nix rename to other/example/example-configuration.nix diff --git a/other/example/flake.nix b/other/example/example-flake.nix similarity index 100% rename from other/example/flake.nix rename to other/example/example-flake.nix diff --git a/other/example/home.nix b/other/example/example-home.nix similarity index 73% rename from other/example/home.nix rename to other/example/example-home.nix index fcbfb7b..b050bd8 100644 --- a/other/example/home.nix +++ b/other/example/example-home.nix @@ -16,33 +16,32 @@ # Nyx Tools Configuration ################################################################ - nyx.nyx-rebuild = { +nyx = { + + enable = true; + inherit username nixDirectory; + logDir = "/home/${username}/.nyx/logs"; + autoPush = false; + + nyx-rebuild = { enable = true; - inherit username nixDirectory; editor = "nvim"; formatter = "alejandra"; enableAlias = false; - autoPushLog = false; - autoPushNixDir = false; startEditor = false; - logDir = "/home/${username}/.nyx/nyx-rebuild/logs"; }; - nyx.nyx-cleanup = { + nyx-cleanup = { enable = true; - inherit username nixDirectory; - autoPush = false; keepGenerations = 5; enableAlias = false; - logDir = "/home/${username}/.nyx/nyx-cleanup/logs"; }; - nyx.nyx-tool = { + nyx-tool = { enable = true; - inherit nixDirectory; }; - +} ################################################################ # Basic Home Manager Setup ################################################################