diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 15780df..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -.backup \ No newline at end of file diff --git a/nyx/bash/lib/git.sh b/nyx/bash/lib/git.sh deleted file mode 100644 index 1f62ff5..0000000 --- a/nyx/bash/lib/git.sh +++ /dev/null @@ -1,407 +0,0 @@ -######################################################################## -# Default Variables -######################################################################## -#echo "Debug - git.sh loaded" -setup_git_vars () { - # Enforce dependencies between flags - if [[ "$auto_commit" == "true" ]]; then - if [[ "$auto_stage" != "true" ]]; then - log_warn "autoStage is disabled" - log_debug_warn "auto_stage is $auto_stage" - auto_commit=false - log_warn "Disabling autoCommit" - log_debug_warn "Setting auto_commit to $auto_commit" - log_warn "Please enable autoStage if you want to use this feature" - fi - fi - if [[ "$auto_push" == "true" ]]; then - if [[ "$auto_commit" != "true" ]]; then - log_warn "autoCommit is disabled" - log_debug_warn "auto_stage is $auto_stage" - auto_push=false - log_warn "Disabling autoPush" - log_debug_warn "Setting autoPush to $auto_push" - log_warn "Please enable autoCommit if you want to use this feature" - fi - fi -} - - - -######################################################################## -# Git wrapper -######################################################################## -git_wrapped_git() { - # Local variable for arguments just in case - local args=("$@") - "$git_bin" "${args[@]}" - return $? -} - -######################################################################## -# Layer 1 - No logs or tell out -######################################################################## -git_add_raw() { - local file="$1" - git_wrapped_git add "$file" - return $? -} - -git_commit_raw() { - local message="$1" - git_wrapped_git commit -m "$message" - return $? -} - -git_push_raw() { - git_wrapped_git push - return $? -} - -git_pull_rebase_raw() { - git_wrapped_git pull --rebase - return $? -} -git_pull_raw() { - git_wrapped_git --rebase - return $? -} - -git_reset_raw() { - local mode="${1:-soft}" # default mode: soft - local target="${2:-HEAD}" # default reset target: HEAD - git_wrapped_git reset "--$mode" "$target" - return $? -} - - - -######################################################################## -# Layer 2 - Logs or Tell out - Mainly Debug Logs -######################################################################## - -git_check_autoStage_enabled () { - if [[ "$auto_stage" == "true" ]]; then - log_debug_info "Auto Stage is enabled will execute function further" - return 0 - else - log_debug_warn "Auto Stage is disabled will not execute function further" - return 1 - fi -} - - -git_check_if_file_stage_valid () { - local file="$1" - # note file can also be a folder it was just easier - if [[ -e "$file" ]]; then - log_debug_ok "found file $file" - # check if the file has changes - if git_wrapped_git diff -- "$file" | grep -q .; then - log_debug_ok "file $file has changes" - return 0 - else - log_debug_warn "file $file has no changes and will be skipped" - return 1 - fi - else - log_debug_error "Did not find file $file." - return 1 - fi -} - -git_check_autoCommit_enabled () { - if [[ "$auto_commit" == "true" ]]; then - log_debug_info "Auto Commit is enabled will execute function further" - return 0 - else - log_debug_warn "Auto Commit is disabled will not execute function further" - return 1 - fi -} - -git_check_has_staged_files() { - local staged_files - # git diff --cached --name-only lists staged files - # If no output, there are no staged files to commit - staged_files=$(git_wrapped_git diff --cached --name-only) - if [[ -n "$staged_files" ]]; then - log_debug_ok "Found staged files to commit" - log_debug_info "Staged files:" - log_debug_info "$staged_files" - return 0 - else - log_debug_warn "No staged files found" - return 1 - fi -} - -git_check_autoPush_enabled () { - if [[ "$auto_push" == "true" ]]; then - log_debug_info "Auto Push is enabled will execute function further" - return 0 - else - log_debug_warn "Auto Push is disabled will not execute function further" - return 1 - fi -} - - - -git_check_has_staged_files() { - local staged_files - # git diff --cached --name-only lists staged files - # If no output, there are no staged files to commit - staged_files=$(git_wrapped_git diff --cached --name-only) - if [[ -n "$staged_files" ]]; then - log_debug_warn "Found staged files to commit" - log_debug_info "Staged files:" - log_debug_info "$staged_files" - return 0 - else - log_debug_ok "No staged files found - Nothing uncommitted" - return 1 - fi -} - -# Returns 0 if there are unstaged -git_check_has_unstaged_files() { - local unstaged_files - # git diff --name-only lists unstaged files - staged_files=$(git_wrapped_git diff --name-only) - if [[ -n "$staged_files" ]]; then - log_debug_warn "Unstaged files detected" - log_debug_info "Unstaged files:" - log_debug_info "$unstaged_files" - return 0 - else - log_debug_warn "No unstaged files" - return 1 - fi -} - - -git_check_if_dir_is_in_repo() { - local file="${1:-.}" # defaults to current dir if no file passed - if [[ -e "$file" ]]; then - log_debug_ok "found file $file" - # note file can also be a folder it was just easier to name it like so - if git_wrapped_git -C "$file" rev-parse --is-inside-work-tree >/dev/null 2>&1; then - log_debug_ok "file $file is in git repo" - return 0 - else - log_debug_error "file $file is not in a git repo" - return 1 - fi - else - log_debug_error "Did not find file $file." - return 1 - fi -} - -git_check_necessary_for_rebase() { - # Reuse: first check if we are behind upstream - if ! git_check_if_behind_upstream; then - log_debug_info "No rebase necessary: branch is not behind upstream" - return 1 - fi - - local branch ahead behind - branch=$(git_wrapped_git rev-parse --abbrev-ref HEAD 2>/dev/null) - ahead=$(git_wrapped_git rev-list --count "@{u}..${branch}") - behind=$(git_wrapped_git rev-list --count "${branch}..@{u}") - - if [[ $ahead -gt 0 && $behind -gt 0 ]]; then - log_debug_ok "Branch $branch has diverged (ahead: $ahead, behind: $behind), rebase required" - return 0 - fi - - log_debug_info "Branch $branch has no divergence (ahead: $ahead, behind: $behind)" - return 1 -} - -git_check_if_behind_upstream() { - # First make sure we are in a git repo - if ! git_check_if_dir_is_in_repo; then - log_debug_error "Not inside a git repository" - return 1 - fi - - # Make sure we have a tracking branch - if ! git_wrapped_git rev-parse --abbrev-ref "@{u}" >/dev/null 2>&1; then - log_debug_warn "Current branch has no upstream, cannot check if behind" - return 1 - fi - - git_wrapped_git fetch --quiet - - local behind_count - behind_count=$(git_wrapped_git rev-list --count "HEAD..@{u}") - - if [[ "$behind_count" -gt 0 ]]; then - log_debug_ok "Branch is behind upstream by $behind_count commits" - return 0 - else - log_debug_info "Branch is up to date with upstream" - return 1 - fi -} - - -######################################################################## -# Layer 3 - Logs or Tell out - Also used in Main Script directly -######################################################################## - -git_add () { - local file="$1" - # note file can also be a folder it was just easier - if git_check_autoStage_enabled; then - if git_check_if_file_stage_valid "$file"; then - if git_add_raw "$file"; then - log_ok "Added file: \"$file\"" - return 0 - else - log_error "Failed to add file: \"$file\"" - return 1 - fi - else - log_verbose_warn "Did not Stage: $file" - return 1 - fi - else - return 1 - fi -} - -git_commit () { - local message="$1" - if git_check_autoCommit_enabled; then - if git_check_has_staged_files; then - if git_commit_raw "$message"; then - log_ok "Committed with Message: \"$message\"" - return 0 - else - log_error "Commit failed with Message: \"$message\"" - return 1 - fi - else - log_verbose_warn "Nothing to commit. Would've committed with Message: \"$message\"" - return 1 - fi - else - return 1 - fi -} - -git_push () { - # Check if auto-push is enabled first - if git_check_autoPush_enabled; then - if git_push_raw; then - log_ok "Pushed to remote successfully" - return 0 - else - log_error "Push to remote failed" - return 1 - fi - else - log_verbose_warn "Auto Push disabled, skipping push" - return 1 - fi -} - -git_pull_rebase() { - - # check if current dir is in git repo - if ! git_wrapped_git rev-parse --is-inside-work-tree >/dev/null 2>&1; then - log_error "Not inside a git repository, cannot pull" - return 1 - fi - - if git_check_necessary_for_rebase; then - # Rebase mode: we have local commits and are behind upstream - if git_wrapped_git pull --rebase; then - log_ok "Pulled from remote and rebased successfully" - return 0 - else - log_error "Pull with rebase failed" - return 1 - fi - elif git_check_if_behind_upstream; then - # Behind but no local commits โ†’ simple fast-forward pull - if git_wrapped_git pull; then - log_ok "Pulled from remote successfully (fast-forward)" - return 0 - else - log_error "Pull from remote failed" - return 1 - fi - else - log_info "Branch is already up to date, no pull required" - return 0 - fi -} - -git_reset() { - local mode="${1:-soft}" # default reset mode is soft - local target="${2:-HEAD}" # commit hash, branch, or tag - - log_info "Resetting to target: $target (mode: $mode)" - if git_reset_raw "$mode" "$target"; then - log_ok "Successfully reset to $target with --$mode" - return 0 - else - log_error "Failed to reset to $target" - return 1 - fi -} - - -git_store_starting_commit () { - # Get the current HEAD commit hash - local commit - commit=$(git_wrapped_git rev-parse HEAD 2>/dev/null) - - if [[ $? -eq 0 && -n "$commit" ]]; then - git_starting_commit="$commit" - log_debug_info "Stored starting commit: $git_starting_commit" - return 0 - else - log_debug_error "Unable to retrieve current commit hash" - return 1 - fi -} - -######################################################################## -# COMPILED FUNCTION SUMMARY -# -######################################################################## -# SETUP -######################################################################## -# setup_git_vars() -# Ensures auto_stage / auto_commit / auto_push flags are consistent. -# If dependencies are not satisfied, disables dependent flags and logs warnings. -# -######################################################################## -# LAYER 3: MAIN FUNCTIONS -######################################################################## -# git_add -# Stages file if auto_stage is enabled and file is valid. -# -# git_commit -# Commits staged files if auto_commit is enabled and there are staged files. -# -# git_push -# Pushes current branch if auto_push is enabled. -# -# git_pull_rebase -# Pulls latest changes. Uses rebase if local commits exist and branch has diverged. -# Falls back to fast-forward pull if only behind. Logs appropriately if up to date. -# -######################################################################## -# VARIABLES -######################################################################## -# auto_stage=true -# auto_commit=true -# auto_push=true -# -######################################################################## diff --git a/nyx/bash/lib/logging.sh b/nyx/bash/lib/logging.sh deleted file mode 100644 index 196de53..0000000 --- a/nyx/bash/lib/logging.sh +++ /dev/null @@ -1,201 +0,0 @@ -######################################################################## -# CONFIGURATION -######################################################################## -#echo "Debug - logging.sh loaded" - - -setup_logging_vars () { - local verbosity=${1:-3} # Default to max verbosity if not provided - NYX_VERBOSITY=$verbosity - log_to_file_disable -} -setup_logging_basic () { - - log_info "Log set to $NYX_VERBOSITY" - # Default log directory - log_info "Setting up LogDir in $log_subdir" - mkdir -p "$log_subdir" - - logPath="$log_subdir/log_$(date '+%Y-%m-%d_%H-%M-%S').log" - log_info "Full log is saved under $logPath" -} - - -######################################################################## -# Control whether logs are written to file -######################################################################## -log_to_file_enable () { - if [[ "$log_to_file" == "true" ]]; then - log_debug_info "log_to_file is already true" - log_debug_warn "log_to_file is $log_to_file" - else - log_to_file=true - log_verbose_warn "log_to_file is enabled" - log_debug_warn "log_to_file is $log_to_file" - fi -} - -log_to_file_disable () { - if [[ "$log_to_file" == "true" ]]; then - log_to_file=false - log_verbose_warn "log_to_file is disabled" - log_debug_warn "log_to_file is $log_to_file" - else - log_debug_info "log_to_file is already false" - log_debug_warn "log_to_file is $log_to_file" - fi -} - - -######################################################################## -# Write a log line to the file -######################################################################## -write_log() { - local line="$1" - echo "$line" >> "$logPath" -} - -######################################################################## -# Output with timestamp, level, color, and verbosity -######################################################################## -tell_out() { - local message="$1" - local level="${2:-INFO}" # Default level: INFO - local verbosity_level="${3:-1}" # Default verbosity level for message - local timestamp - timestamp=$(date '+%Y-%m-%d %H:%M:%S') - - # Append diagnostic info for errors - if [[ "$level" == "ERROR" ]]; then - tell_out "$message # $(what_messed_up)" "DEBUG" "3" - fi - - local log_line="[$timestamp][$level] $message" - local line="[$level] $message" - - # Only output messages if verbosity level is sufficient - if [[ $NYX_VERBOSITY -ge $verbosity_level ]]; then - case "$level" in - INFO) echo -e "\033[0;37m$line\033[0m" ;; # Gray - OK) echo -e "\033[0;32m$line\033[0m" ;; # Green - WARN) echo -e "\033[1;33m$line\033[0m" ;; # Yellow - ERROR) echo -e "\033[0;31m$line\033[0m" ;; # Red - CMD) echo -e "\033[0;36m$line\033[0m" ;; # Cyan - OTHER) echo -e "\033[0;35m$line\033[0m" ;; # Magenta - LINE) echo -e "\033[1;30m$line\033[0m" ;; # Dark Gray - *) echo -e "$line" ;; # Default no color - esac - fi - - # Always write to log file if enabled - if [[ "$log_to_file" == "true" ]]; then - write_log "$log_line" - fi -} - - -######################################################################## -# Separator line for logs -######################################################################## -log_separator() { - local verbosity="${1:-0}" - tell_out "===========================================" "LINE" $verbosity -} - -######################################################################## -# Execute a command with logging and error handling -######################################################################## -execute() { - local command="$1" - local cmd_verbosity="${2:-2}" - - tell_out "Executing: $command" "CMD" "$cmd_verbosity" - tell_out "### Log from $command start ###" "CMD" "$cmd_verbosity" - log_separator "$cmd_verbosity" - - # Use a subshell and a pipe to tee both stdout and stderr to the log - # while preserving the exit code - local status - { - # Redirect stderr to stdout so both are captured - eval "$command" 2>&1 | while IFS= read -r line; do - tell_out "$line" "CMD" "$cmd_verbosity" - done - } - status=${PIPESTATUS[0]} # Capture exit code of eval, not the while loop - - log_separator "$cmd_verbosity" - - tell_out "### Log from $command end ###" "CMD" "$cmd_verbosity" - - # Log success or failure - if (( status == 0 )); then - tell_out "Execution successful: $command" "OK" "$cmd_verbosity" - else - tell_out "Error executing command: $command (exit code $status)" "ERROR" 0 - fi - - return $status -} - -######################################################################## -# Call stack helper for debugging -######################################################################## -what_messed_up() { - local stack=("${FUNCNAME[@]}") - local call_chain="" - #unset 'stack[0]' # remove current function - #unset 'stack[1]' # remove direct caller (log_error etc.) - #unset 'stack[-1]' # remove "main" - - # Join the remaining stack elements with " -> " - for function in "${stack[@]}"; do - if [[ -z "$call_chain" ]]; then - call_chain="$function" - else - call_chain="$call_chain -> $function" - fi - done - - echo "$call_chain" -} - - - -######################################################################## -# Verbosity helper functions -######################################################################## -log_debug_info() { tell_out "$1" "INFO" 3; } -log_debug_warn() { tell_out "$1" "WARN" 3; } -log_debug_ok() { tell_out "$1" "OK" 3; } -log_debug_error() { tell_out "$1" "ERROR" 3; } - - -log_verbose_ok () { tell_out "$1" "OK" 2; } -log_verbose_info () { tell_out "$1" "INFO" 2; } -log_verbose_warn () { tell_out "$1" "WARN" 2; } -log_verbose_error () { tell_out "$1" "ERROR" 2; } -log_verbose_end () { tell_out "$1" "END" 2; } - -log_ok() { tell_out "$1" "OK" 1; } -log_info() { tell_out "$1" "INFO" 1; } -log_warn() { tell_out "$1" "WARN" 1; } -log_error() { tell_out "$1" "ERROR" 0; } -log_end() { tell_out "$1" "END" 0; } - -######################################################################## -# USAGE SUMMARY -# -######################################################################## -# LOGGING FUNCTIONS -######################################################################## -# log_debug_* "Message" # with variations -# log_verbose "Message" # Shown at verbosity 2+ -# log_info "Message" # Standard info message (verbosity 1+) -# log_warn "Message" # Warning message (verbosity 1+) -# log_error "Message" # Error message (always shown) -# -# log_to_file_enable # Enable writing all logs to $logPath -# log_to_file_disable # Disable log file writing -# -######################################################################## diff --git a/nyx/bash/lib/sudo.sh b/nyx/bash/lib/sudo.sh deleted file mode 100644 index d16dcfc..0000000 --- a/nyx/bash/lib/sudo.sh +++ /dev/null @@ -1,56 +0,0 @@ -#echo "Debug - sudo.sh loaded" - - -check_if_run_with_sudo() { - log_debug_info "Checking if the script is being run with sudo or as root..." - - # Check if running as root - if [[ "$EUID" -eq 0 ]]; then - log_error "This script must NOT be run as root or with sudo." - log_debug_error "Detected EUID=0 (root). Please run as a normal user." - exit 1 - fi - - # Check if running through sudo - if [[ -n "$SUDO_USER" ]]; then - log_error "This script must NOT be run with sudo." - log_debug_error "Detected SUDO_USER='$SUDO_USER'. Run without sudo." - exit 1 - fi - - log_verbose_ok "Sudo/root check passed. Running as a normal user: $USER" - return 0 -} - -get_sudo_ticket() { - log_verbose_info "Checking if sudo rights are already available..." - - # Check if sudo permissions are currently active - if sudo -n true 2>/dev/null; then - log_verbose_ok "Sudo rights are already active. No password required." - return 0 - fi - - log_info "Sudo permissions required. Prompting for password..." - - # Attempt to refresh or request sudo credentials - if sudo -v; then - log_ok "Sudo rights successfully acquired." - return 0 - else - log_error "Failed to acquire sudo permissions. Incorrect password or sudo not available." - return 1 - fi -} - -######################################################################## -# -# Sudo/Root Handling Functions: -# check_if_run_with_sudo -# - Exits if the script is run as root or with sudo. -# -# get_sudo_ticket -# - Checks if sudo permissions are cached. -# - If not, prompts for password to acquire them. -# -######################################################################## \ No newline at end of file diff --git a/nyx/bash/nyx-rebuild.sh b/nyx/bash/nyx-rebuild.sh index 5637632..899e997 100644 --- a/nyx/bash/nyx-rebuild.sh +++ b/nyx/bash/nyx-rebuild.sh @@ -1,593 +1,387 @@ #!/usr/bin/env bash - -######################################################################## -# CONFIGURATION -######################################################################## -flake_directory="@FLAKE_DIRECTORY@" -log_dir="@LOG_DIR@" -enable_formatting="@ENABLE_FORMATTING@" -formatter_cmd="@FORMATTER@" -git_bin="@GIT_BIN@" -nom_bin="@NOM_BIN@" -auto_stage="@AUTO_STAGE@" -auto_commit="@AUTO_COMMIT@" -auto_push="@AUTO_PUSH@" -auto_repair=true -version="@VERSION@" -rebuild_success=false -nixos_generation="" -git_starting_commit="" - -debug_print_vars () { - log_debug_info "###### Debug - Vars ######" - log_debug_info "main() started with action: $rebuild_action, verbosity: $NYX_VERBOSITY" - log_debug_info "FLAKE_DIRECTORY: $flake_directory" - log_debug_info "LOG_DIR: $log_dir" - log_debug_info "ENABLE_FORMATTING: $enable_formatting" - log_debug_info "FORMATTER: $formatter_cmd" - log_debug_info "GIT_BIN: $git_bin" - log_debug_info "NOM_BIN: $nom_bin" - log_debug_info "AUTO_STAGE: $auto_stage" - log_debug_info "AUTO_COMMIT: $auto_commit" - log_debug_info "AUTO_PUSH: $auto_push" - log_debug_info "VERSION: $version" - log_debug_info "###### Debug - Vars ######" -} - - - -######################################################################## -# FORMATTER -######################################################################## -run_formatter() { - if [[ "$enable_formatting" == "true" ]]; then - log_info "Running formatter..." - execute "$formatter_cmd ." "2" - git_add $flake_directory - git_commit "Formatted by $formatter_cmd" - fi -} - - -######################################################################## -# Repair -######################################################################## -repair_waited_before=false -repair_wait_time=3 - -repair_wait () { - if [[ "$auto_repair" == "true" ]]; then - if [[ "$repair_waited_before" == "true" ]]; then - log_debug_info "Waited before so it will start the repair" - else - log_warn "Will repair in $repair_wait_time seconds" - log_warn "Use \"CTRL + C\" to cancel if you don't want that" - for (( waited_time=1; waited_time<=repair_wait_time; waited_time++ )); do - log_info "Will repair in $((repair_wait_time - waited_time + 1))..." - sleep 1 - done - log_warn "Start Repair" - repair_waited_before=true - fi - fi -} - - -check_and_repair () { - - if git_check_has_staged_files; then - log_warn "Repo has uncommitted files" - log_debug_info "auto_commit is $auto_commit" - if [[ "$auto_repair" == "true" ]]; then - log_info "Starting Repair Uncommitted" - if repair_uncommitted; then - log_debug_ok "repair_uncommitted Returned 0 (success)" - else - log_error "I have no Idea but it has sth to do with git_check_has_staged_files in nyx-rebuild.sh" - FATAL - fi - else - log_error "Due to auto_repair being $auto_repair repair not attempted" - log_error "Commit your staged commits or enable \$auto_repair" - FATAL - fi - fi - - - if git_check_has_unstaged_files ; then - log_warn "Repo has unstaged files" - log_debug_warn "auto_stage is $auto_stage" - if [[ "$auto_repair" == "true" ]]; then - log_info "Starting Repair unstaged" - if repair_unstaged; then - log_debug_ok "repair_unstaged Returned 0 (success)" - else - log_error "I have no Idea but it has sth to do with git_check_has_unstaged_files in nyx-rebuild.sh" - fi - else - log_error "Due to auto_repair being $auto_repair repair not attempted" - log_error "Stage your unstaged files or enable \$auto_repair" - FATAL - fi - fi - -} - -repair_unstaged () { - repair_wait - if [[ "$auto_repair" == "true" ]]; then - if [[ "$auto_stage" == "true" ]]; then - log_debug_info "Will attempt to stage files" - git_add $flake_directory - log_info "Added unstaged files" - repair_uncommitted - return 0 - else - log_error "Due to autoStage being disabled repair not attempted" - log_debug_error "Due to auto_stage being $auto_stage repair not attempted" - log_error "Stage your unstaged files or enable autoStage" - FATAL - fi - else - log_error "This shouldn't exist #repair_unstaged" - return 1 - fi - -} - -repair_uncommitted () { - repair_wait - if [[ "$auto_repair" == "true" ]]; then - if [[ "$auto_commit" == "true" ]]; then - log_debug_info "Will attempt to commit" - git_commit "Auto repair commit - $(date '+%Y-%m-%d_%H-%M-%S')" - log_info "Repaired uncommitted changes" - return 0 - else - log_error "Due to autoCommit being disabled repair not attempted" - log_debug_error "Due to auto_commit being $auto_commit repair not attempted" - log_error "Commit your staged commits or enable autoCommit" - FATAL - fi - else - log_error "This shouldn't exist #repair_uncommitted" - return 1 - fi - -} - - - -######################################################################## -# SUDO HANDLING -######################################################################## -ensure_sudo() { - get_sudo_ticket -} - -######################################################################## -# NIXOS REBUILD -######################################################################## -run_nixos_rebuild() { - local tmp_log tmp_status status - tmp_log=$(mktemp /tmp/nyx-tmp-log.XXXXXX) - tmp_status=$(mktemp /tmp/nyx-status.XXXXXX) - - log_debug_info "Running nixos-rebuild command: $*" - log_debug_info "Build log: $build_log" - log_debug_info "Error log: $error_log" - log_debug_info "Using nom binary: $nom_bin" - log_debug_info "Temp log: $tmp_log" - log_debug_info "Temp status file: $tmp_status" - - set -o pipefail - ( - "$@" 2>&1 - echo $? > "$tmp_status" - ) | tee -a "$tmp_log" | "$nom_bin" - - status=$(<"$tmp_status") - execute "rm -f '$tmp_status'" "2" - - log_debug_info "Exit code: $status" - - if [[ $status -eq 0 ]]; then - if grep -Ei -A1 'error|failed' "$tmp_log" >/dev/null; then - log_error "Build reported errors despite successful exit code" - rebuild_success=false - execute "cp '$tmp_log' '$error_log'" "2" - else - log_ok "Build succeeded" - rebuild_success=true - execute "cp '$tmp_log' '$build_log'" "2" - # Populate generation number for finish_rebuild - nixos_generation=$(nixos-rebuild list-generations | grep True | awk '{print $1}') - fi - else - if grep -Ei -A1 'error|failed' "$tmp_log" >/dev/null; then - log_error "Build failed with exit code $status" - rebuild_success=false - execute "cp '$tmp_log' '$error_log'" "2" - else - log_error "Build exited with $status but no explicit error lines found" - rebuild_success=false - execute "cp '$tmp_log' '$error_log'" "2" - fi - fi - - # Send output line by line - while IFS= read -r line; do - tell_out "$line" "CMD" 2 - done < "$tmp_log" - - execute "rm -f '$tmp_log'" "2" - return "$status" -} - - - - - -######################################################################## -# MAIN REBUILD PROCESS -######################################################################## -nyx_rebuild() { - start_time=$(date +%s) - rebuild_success=false - git_store_starting_commit - cd "$flake_directory" || { - log_error "Could not change directory to $flake_directory" - return 1 - } - - # Ensure we are inside a git repo before proceeding - if git_check_if_dir_is_in_repo "$flake_directory"; then - log_debug_info "Passed Git repo check" - else - log_error "Git repo not detected. Aborting rebuild" - return 1 - fi - - check_and_repair - git_pull_rebase - - log_to_file_enable - run_formatter - - log_separator - log_info "Rebuild started: $(date)" - log_separator - - ensure_sudo - - run_nixos_rebuild sudo nixos-rebuild "$rebuild_action" --flake "$flake_directory" - local rebuild_status=$? - - finish_rebuild "$start_time" >/dev/null 2>&1 - - # Only stage/commit logs if rebuild succeeded - if [[ "$rebuild_success" == true ]]; then - logs_stage_and_commit "Rebuild '$rebuild_action' completed successfully" - else - log_error "Rebuild failed" - git_reset "soft" "$git_starting_commit" - logs_stage_and_commit "Error: Rebuild Failed" - finish_rebuild "$start_time" - trap - EXIT - log_debug_info "EXIT trap removed" - exit 1 - fi - - return $rebuild_status -} - - -######################################################################## -# FINISH -######################################################################## -finish_rebuild() { - local start_time=$1 - local duration=$(( $(date +%s) - start_time )) - - # Build failure notes from grep output (one per line) - if [[ "$rebuild_success" != true ]]; then - finish_failure_notes="" - if [[ -f "$error_log" ]]; then - while IFS= read -r line; do - finish_failure_notes+=$'\n'" $line" - done < <(grep -Ei -A1 'error|failed' "$error_log" | tee -a "$error_log" || true) - fi - fi - - log_separator - if [[ "$rebuild_success" == true ]]; then - log_end "###############################################" - log_end " Nyx-Rebuild Completed Successfully" - log_end "###############################################" - log_end "Action: $rebuild_action" - log_end "Flake: $flake_directory" - log_end "Result: Build succeeded" - log_end "Duration: ${duration}s" - log_end "System Generation: $nixos_generation" - [[ -n "$finish_success_notes" ]] && log_end "Notes: $finish_success_notes" - log_end "Build log: $build_log" - log_end "###############################################" - else - log_end "###############################################" - log_end " Nyx-Rebuild Failed" - log_end "###############################################" - log_end "Action: $rebuild_action" - log_end "Flake: $flake_directory" - log_end "Result: Build failed" - log_end "Duration: ${duration}s" - log_end "System Generation: $nixos_generation" - if [[ -n "$finish_failure_notes" ]]; then - log_end "Notes:" - while IFS= read -r note; do - log_end "$note" - done <<< "$finish_failure_notes" - fi - log_end "Error log: $error_log" - log_end "###############################################" - fi - log_separator -} - - -logs_stage_and_commit() { - log_debug_info "logs_stage_and_commit called and is disabling the Logs to Push them" - log_to_file_disable - local message="$1" - git_add "Logs" - git_commit "$message" - git_push -} - - - - - -######################################################################## -# helper: -######################################################################## - -interpret_flags() { - local opt - local verbosity=1 - local action="" - - # Reset OPTIND to handle multiple calls in same shell - OPTIND=1 - - while getopts ":hv:" opt; do - case "$opt" in - h) - print_help - exit 0 - ;; - v) - if [[ "$OPTARG" =~ ^[0-9]+$ ]]; then - verbosity="$OPTARG" - else - echo "Invalid verbosity level: $OPTARG" >&2 - exit 1 - fi - ;; - :) - echo "Option -$OPTARG requires an argument" >&2 - exit 1 - ;; - \?) - echo "Unknown option: -$OPTARG" >&2 - exit 1 - ;; - esac - done - - shift $((OPTIND - 1)) - - # First positional arg after options = action - if [[ $# -gt 0 ]]; then - action="$1" - shift - else - action="test" - fi - - rebuild_action="$action" - NYX_VERBOSITY="$verbosity" - - # Any extra args after action can be captured if needed - remaining_args=("$@") -} - - -print_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 + } -######################################################################## -# Setup -######################################################################## + git_add_path() { + g add "$@" + } - -setup_nyxrebuild_vars () { - if [[ "$auto_repair" == "true" ]]; then - # Enforce dependencies between flags - if [[ "$auto_stage" != "true" ]]; then - log_warn "autoStage is disabled" - log_debug_warn "auto_stage is $auto_stage" - auto_repair=false - log_warn "Disabling autoRepair" - log_debug_warn "Setting auto_repair to $auto_repair" - log_warn "Please enable autoStage if you want to use this feature" - fi - if [[ "$auto_commit" != "true" ]]; then - log_warn "autoCommit is disabled" - log_debug_warn "auto_commit is $auto_commit" - auto_repair=false - log_warn "Disabling autoRepair" - log_debug_warn "Setting auto_repair to $auto_repair" - log_warn "Please enable autoCommit if you want to use this feature" - fi - - #if [[ "$auto_push" != "true" ]]; then - # log_warn "autoPush is disabled" - # log_debug_warn "auto_push is $auto_push" - # auto_push=false - # log_warn "Disabling autoRepair" - # log_debug_warn "Setting auto_repair to $auto_repair" - # log_warn "Please enable autoPush if you want to use this feature" - #fi + git_commit_if_staged() { + # commit if there is something staged; ignore empty + if ! g diff --cached --quiet; then + g commit -m "$1" || true fi + } - if [[ "$enable_formatting" == "true" ]]; then - # Enforce dependencies between flags - if [[ "$auto_stage" != "true" ]]; then - log_warn "autoStage is disabled" - log_debug_warn "auto_stage is $auto_stage" - enable_formatting=false - log_warn "Disabling enableFormatting" - log_debug_warn "Setting enable_formatting to $enable_formatting" - log_warn "Please enable autoStage if you want to use this feature" - fi + git_commit_message() { + local msg="$1" + g commit -m "$msg" + } - if [[ "$auto_commit" != "true" ]]; then - log_warn "autoCommit is disabled" - log_debug_warn "auto_commit is $auto_commit" - enable_formatting=false - log_warn "Disabling enableFormatting" - log_debug_warn "Setting enable_formatting to $enable_formatting" - log_warn "Please enable autoCommit if you want to use this feature" - fi - - #if [[ "$auto_push" != "true" ]]; then - # log_warn "autoPush is disabled" - # log_debug_warn "auto_push is $auto_push" - # enable_formatting=false - # log_warn "Disabling enableFormatting" - # log_debug_warn "Setting enable_formatting to $enable_formatting" - # log_warn "Please enable autoPush if you want to use this feature" - #fi + 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 + } -FATAL() { - log_error "nyx-rebuild encountered a fatal error" - log_error "Script ended due to error. Check $logPath" - if [[ -n "$git_starting_commit" ]]; then - log_error "Resetting repository to starting commit: $git_starting_commit" - if git_reset "soft" "$git_starting_commit"; then - log_ok "Repository successfully reset to starting commit" - else - log_error "Failed to reset repository to starting commit" - 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 - log_warn "No starting commit stored, cannot reset repository" + echo "No rebuild log directory found." fi - log_debug_error "Last called function: $(what_messed_up)" - log_error "If this is a bug in nyx-rebuild, open an issue and include logs" - - exit 1 -} - -trap_on_exit() { - local exit_code=$? - if [[ $exit_code -eq 0 ]]; then - log_debug_ok "Script completed successfully (exit code 0)" - finish_rebuild "$start_time" + 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 - log_error "Script exited with error (exit code $exit_code)" - # Only run FATAL if we are not already inside it - if [[ "${FUNCNAME[1]}" != "FATAL" ]]; then - FATAL - fi + echo "No changes to commit." fi -} -######################################################################## -# ENTRY POINT -######################################################################## -main () { - rebuild_action="$1" + } - #interpret_flags "$@" - - nyx-tool "Nyx" "nyx-rebuild" "$version" \ - "Smart NixOS configuration rebuilder" \ + + + + ######################################################################## + # 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" \ - "Always up to date for you!" + "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 - # to do make this a flag: verbosity - local verbosity=1 + ######################################################################## + # 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 - #source all the files - generated by the .nix file - source_all + ######################################################################## + # 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 - # the interger decides verbosity level - setup_logging_vars $verbosity + ######################################################################## + # 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 - # From now on Logging functions can safely be called: - log_debug_info "Checking that script is NOT run with sudo..." - check_if_run_with_sudo + console-log "${BOLD}${BLUE}Starting system rebuild...${RESET}" - # Logging stuff - log_debug_info "Initializing logging..." - log_subdir="${log_dir}/rebuild" - mkdir -p "$log_subdir" - timestamp=$(date '+%Y-%m-%d_%H-%M-%S') - - # lib/logging.sh - log_debug_info "Setting up basic logging (directories, log file)..." - setup_logging_basic - - build_log="${logPath%.log}-rebuild.log" - error_log="${logPath%.log}-Current-Error.txt" + 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 - # lib/git.sh - log_debug_info "Configuring git-related variables..." - setup_git_vars + 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 - log_debug_info "Configuring nyx-rebuild variables..." - setup_nyxrebuild_vars + print_line + console-log "Rebuild started: $(date)" + print_line + run_with_log_rebuild sudo nixos-rebuild switch --flake "$nix_dir" + rebuild_status=$? - debug_print_vars - trap trap_on_exit EXIT - nyx_rebuild "$rebuild_action" + 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 } - -main "$@" \ No newline at end of file +# Execute when sourced as a script +nyx-rebuild "$@" diff --git a/nyx/default.nix b/nyx/default.nix index a29d1ed..b4391b8 100644 --- a/nyx/default.nix +++ b/nyx/default.nix @@ -25,18 +25,6 @@ with lib; description = "Directory for Nyx logs"; }; - autoStage = mkOption { - type = types.bool; - default = false; - description = "Automatically stage changes after rebuild/cleanup"; - }; - - autoCommit = mkOption { - type = types.bool; - default = false; - description = "Automatically commit changes after rebuild/cleanup"; - }; - autoPush = mkOption { type = types.bool; default = false; diff --git a/nyx/nyx-rebuild.nix b/nyx/nyx-rebuild.nix index 00cb0c5..6967326 100644 --- a/nyx/nyx-rebuild.nix +++ b/nyx/nyx-rebuild.nix @@ -4,78 +4,46 @@ let nyxCfg = config.nyx; cfg = nyxCfg."nyx-rebuild"; - # Function to put a file from lib/ into the Nix store - libFile = file: - builtins.toFile - (builtins.baseNameOf file) - (builtins.readFile ./bash/lib/${file}); - - # List of files you want to source - filesToSource = [ - "git.sh" - "logging.sh" - "sudo.sh" -# "nyx-rebuild-logic.sh" - ]; - - # Build sourcing lines dynamically - sourcingLines = - builtins.concatStringsSep "\n" - (map (f: "source ${libFile f}") filesToSource); - # Read template and inject values rebuiltScript = let - src = builtins.readFile ./bash/nyx-rebuild.sh; + src = builtins.readFile ./bash/nyx-rebuild.sh; # uses @TOKENS@, not ${...} in - builtins.replaceStrings - [ - "@FLAKE_DIRECTORY@" - "@LOG_DIR@" - "@ENABLE_FORMATTING@" - "@FORMATTER@" - "@GIT_BIN@" - "@NOM_BIN@" - "@AUTO_STAGE@" - "@AUTO_COMMIT@" - "@AUTO_PUSH@" - "@VERSION@" - ] - [ - (toString nyxCfg.nixDirectory) - (toString nyxCfg.logDir) - (if cfg.enableFormatting then "true" else "false") - cfg.formatter - "${pkgs.git}/bin/git" - "${pkgs.nix-output-monitor}/bin/nom" - (if nyxCfg.autoStage then "true" else "false") - (if nyxCfg.autoCommit then "true" else "false") - (if nyxCfg.autoPush then "true" else "false") - "1.2.0" - ] - ( - "#!/usr/bin/env bash\n" - + "source_all () {\n" - + sourcingLines - + "\n}\n" - + src - ); - + 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.2.0" + ] + src; in { options.nyx."nyx-rebuild" = { - enable = lib.mkEnableOption "Enable nyx-rebuild script"; - formatter = lib.mkOption { type = lib.types.str; default = "alejandra"; }; - enableFormatting = lib.mkOption { type = lib.types.bool; default = false; }; - enableAlias = lib.mkOption { type = lib.types.bool; default = true; }; + enable = lib.mkEnableOption "Enable nyx-rebuild script"; + + 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 (nyxCfg.enable && cfg.enable) { environment.systemPackages = - lib.optionals (cfg.enableFormatting && cfg.formatter == "alejandra") [ - pkgs.alejandra - ] + 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) ]; diff --git a/other/zsh/nyx-cleanup.zsh b/other/zsh/nyx-cleanup.zsh new file mode 100644 index 0000000..0afb4d8 --- /dev/null +++ b/other/zsh/nyx-cleanup.zsh @@ -0,0 +1,108 @@ + # Extract cfg values into local variables + nix_dir="${cfg.nixDirectory}" + start_editor="${toString cfg.startEditor}" + enable_formatting="${toString cfg.enableFormatting}" + editor_cmd="${cfg.editor}" + formatter_cmd="${cfg.formatter}" + auto_push="${toString cfg.autoPush}" + source "${scriptTargetPath}" + +function nyx-cleanup() { + ##### ๐Ÿ› ๏ธ CONFIGURATION ##### + local version="1.3.1" + local keep_generations="${keep_generations:-5}" + local start_human=$(date '+%Y-%m-%d %H:%M:%S') + local nix_cleanup_log="nixos-cleanup.log" + local optimize_store="${optimize_store:-false}" + local auto_push="${auto_push:-false}" + + local RED=$'\e[31m'; local GREEN=$'\e[32m'; local YELLOW=$'\e[33m' + local BLUE=$'\e[34m'; local MAGENTA=$'\e[35m'; local CYAN=$'\e[36m' + local BOLD=$'\e[1m'; local RESET=$'\e[0m' + + ##### ๐Ÿ“ PATH SETUP ##### + local timestamp=$(date '+%Y-%m-%d_%H-%M-%S') + local hostname_id=$(hostname) + local log_dir="$nix_dir/Misc/nyx/logs/$hostname_id" + mkdir -p "$log_dir" + local cleanup_log="$log_dir/cleanup-$timestamp.log" + local log_file="$log_dir/nixos-gen-cleanup-$timestamp.log" + + ##### ๐Ÿงฐ HELPERS ##### + console-log() { + echo -e "$@" | tee -a "$cleanup_log" + } + + print_line() { + console-log "${BOLD}$(printf '%*s\n' "${COLUMNS:-40}" '' | tr ' ' '=')${RESET}" + } + + format_bytes() { + num=$1 + echo $(numfmt --to=iec-i --suffix=B "$num") + } + + disk_usage() { + df --output=used /nix/store | tail -1 + } + + ##### ๐Ÿ“˜ TOOL INFO ##### + print_line + nyx-tool "Nyx" "nyx-cleanup" "$version" \ + "Smart NixOS configuration cleanup" \ + "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 + echo -e "${BOLD}${CYAN}๐Ÿงผ Nyx Cleanup v$version โ€” Starting...${RESET}" + print_line + + ##### ๐Ÿ“Š STATS: BEFORE ##### + local disk_before=$(disk_usage) + console-log "${CYAN}๐Ÿ“Š Disk used before cleanup: $(format_bytes $disk_before)${RESET}" + + ##### ๐Ÿงน EXECUTION ##### + console-log "\n${BLUE}๐Ÿ—‘๏ธ Collecting Nix garbage...${RESET}" + sudo nix-collect-garbage -d >> "$cleanup_log" 2>&1 + + console-log "\n${BLUE}๐Ÿงน Deleting old generations (keep $keep_generations)...${RESET}" + sudo nix-collect-garbage --delete-older-than "${keep_generations}d" >> "$cleanup_log" 2>&1 + + if [[ "$optimize_store" == "true" ]]; then + console-log "\n${MAGENTA}๐Ÿ”ง Optimizing the Nix store...${RESET}" + sudo nix-store --optimize >> "$cleanup_log" 2>&1 + fi + + ##### ๐Ÿ“Š STATS: AFTER ##### + local disk_after=$(disk_usage) + local space_freed=$((disk_before - disk_after)) + print_line + console-log "${GREEN}${BOLD}โœ… Cleanup Completed Successfully!${RESET}" + console-log "${CYAN}๐Ÿ•’ Finished at: $(date)${RESET}" + console-log "${CYAN}๐Ÿ“Š Disk used after cleanup: $(format_bytes $disk_after)${RESET}" + console-log "${CYAN}๐Ÿ’พ Space freed: $(format_bytes $space_freed)${RESET}" + print_line + + ##### ๐Ÿ“ GIT LOGGING ##### + local gen_nmbr=$(nixos-rebuild list-generations | grep True | awk '{print $1}' | tail -1 | xargs printf "%04d\n") + + cd "$nix_dir" || return 1 + mv "$nix_cleanup_log" "$log_file" + git add "$log_file" + + if ! git diff --cached --quiet; then + git commit -m "Cleanup log on $timestamp" + console-log "${GREEN}โœ… Cleanup log committed.${RESET}" + else + console-log "${YELLOW}โ„น๏ธ No new changes in logs to commit.${RESET}" + fi + + if [[ "$auto_push" == "true" ]]; then + console-log "${BLUE}๐Ÿš€ Auto-push enabled. Pushing to remote...${RESET}" + git push && console-log "${GREEN}โœ… Changes pushed to remote.${RESET}" + fi + + console-log "\n${GREEN}๐ŸŽ‰ Nyx cleanup finished!${RESET}" + print_line +} diff --git a/other/zsh/nyx-rebuild.zsh b/other/zsh/nyx-rebuild.zsh new file mode 100644 index 0000000..5a74f3a --- /dev/null +++ b/other/zsh/nyx-rebuild.zsh @@ -0,0 +1,204 @@ +function nyx-rebuild() { + + #################### ๐Ÿ”ง INITIAL SETUP #################### + local version="1.3.0" + local start_time=$(date +%s) + local start_human=$(date '+%Y-%m-%d %H:%M:%S') + local stats_duration=0 + local stats_gen="?" + local stats_errors=0 + local stats_last_error_lines="" + local rebuild_success=false + local exit_code=1 # default to failure + + trap finish_nyx_rebuild + + #################### ๐ŸŽจ ANSI 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 + + #################### ๐Ÿ“ PATH SETUP #################### + local log_dir="$nix_dir/Misc/nyx/logs/$(hostname)" + mkdir -p "$log_dir" + local timestamp=$(date '+%Y-%m-%d_%H-%M-%S') + local build_log="$log_dir/build-${timestamp}.log" + local error_log="$log_dir/Current-Error-${timestamp}.txt" + + #################### ๐Ÿงฐ HELPERS #################### + console-log() { + echo -e "$@" | tee -a "$build_log" + } + + print_line() { + console-log "${BOLD}$(printf '%*s\n' "${COLUMNS:-40}" '' | tr ' ' '=')${RESET}" + } + + run_with_log() { + local cmd_output + cmd_output=$(mktemp) + ( + "$@" 2>&1 + echo $? > "$cmd_output" + ) | tee -a "$build_log" + local exit_code=$(<"$cmd_output") + rm "$cmd_output" + return "$exit_code" + } + run_with_log_rebuild() { + local cmd_output + cmd_output=$(mktemp) + ( + "$@" 2>&1 + echo $? > "$cmd_output" + ) | tee -a "$build_log" | nom + local exit_code=$(<"$cmd_output") + rm "$cmd_output" + return "$exit_code" + } + + 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 "\n${YELLOW}๐Ÿงพ Last few errors:${RESET}\n$stats_last_error_lines" + fi + echo + return $exit_code + } + + #################### ๐Ÿ“˜ 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; } + + echo "\n${BOLD}${BLUE}๐Ÿ“ Checking Git status...${RESET}" + if [[ -n $(git status --porcelain) ]]; then + echo "${YELLOW}โš ๏ธ Uncommitted changes detected!${RESET}" + echo "${RED}โณ 5s to cancel...${RESET}" + sleep 5 + fi + + #################### ๐Ÿ”„ GIT PULL #################### + console-log "\n${BOLD}${BLUE}โฌ‡๏ธ Pulling latest changes...${RESET}" + if ! run_with_log git pull --rebase; then + exit_code=1; return $exit_code + fi + + #################### ๐Ÿ“ EDIT CONFIG #################### + if [[ "$start_editor" == "true" ]]; then + console-log "\n${BOLD}${BLUE}๐Ÿ“ Editing configuration...${RESET}" + console-log "Started editing: $(date)" + run_with_log $editor_cmd + console-log "Finished editing: $(date)" + fi + + #################### ๐ŸŽจ FORMAT #################### + 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 diff --compact-summary + + #################### ๐Ÿ› ๏ธ SYSTEM REBUILD #################### + console-log "\n${BOLD}${BLUE}๐Ÿ”ง Starting system rebuild...${RESET}" + print_line + console-log "๐Ÿ› ๏ธ Removing old HM conf " + run_with_log find ~ -type f -name '*delme-HMbackup' -exec rm -v {} + + print_line + ### Sudo session ticket: + console-log "Getting an \`sudo\`-\"Ticket\" to use \`nixos-rebuild\` with \"nom\" " + console-log "please enter your sudo credentials:" + run_with_log sudo whoami > /dev/null + ### Now rebuils_ + print_line + console-log "๐Ÿ› ๏ธ Rebuild started: $(date)" + print_line + + run_with_log_rebuild sudo nixos-rebuild switch --flake "$nix_dir" + local rebuild_status=$? + + if [[ $rebuild_status -ne 0 ]]; then + #console-log "\n${BOLD}${RED}โŒ Rebuild failed at $(date). Showing errors:${RESET}" + 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") + finish_nyx_rebuild | tee -a "$error_log" + + git add "$log_dir" + git commit -m "Rebuild failed: errors logged" + if [[ "$auto_push" == "true" ]]; then + run_with_log git push && console-log "${GREEN}โœ… Error log pushed to remote.${RESET}" + fi + exit_code=1 + return $exit_code + fi + + #################### โœ… SUCCESS FLOW #################### + rebuild_success=true + exit_code=0 + + + 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 add -u + if ! git diff --cached --quiet; then + git commit -m "Rebuild: $gen" + console-log "${BLUE}๐Ÿ”ง Commit message:${RESET}\n${GREEN}Rebuild: $gen${RESET}" + fi + + local final_log="$log_dir/nixos-gen_${stats_gen}-switch-${timestamp}.log" + mv "$build_log" "$final_log" + git add "$final_log" + + if ! git diff --cached --quiet; then + git commit -m "log for $gen" + echo "${YELLOW}โ„น๏ธ Added changes to git${RESET}" + else + echo "${YELLOW}โ„น๏ธ No changes in logs to commit.${RESET}" + fi + + if [[ "$auto_push" == "true" ]]; then + git push && echo "${GREEN}โœ… Changes pushed to remote.${RESET}" + fi + + echo "\n${GREEN}๐ŸŽ‰ Nyx rebuild completed successfully!${RESET}" + finish_nyx_rebuild + #return $exit_code + +} diff --git a/other/zsh/nyx-tool.zsh b/other/zsh/nyx-tool.zsh new file mode 100644 index 0000000..577dae0 --- /dev/null +++ b/other/zsh/nyx-tool.zsh @@ -0,0 +1,92 @@ +#!/usr/bin/env zsh + +# nyx-tool: reusable metadata banner printer with Base16 theme +function nyx-tool() { + 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 (using tput for portability or ANSI codes) + local RESET="\033[0m" + local BOLD="\033[1m" + local HEADER="\033[38;5;33m" # Approx base0D (blue) + local LABEL="\033[38;5;70m" # Approx base0B (green) + local VALUE="\033[38;5;250m" # Approx base05 (gray) + local EMPHASIS="\033[38;5;196m" # Approx base08 (red) + + local line + line=$(printf '=%.0s' {1..35}) + + echo "" + echo -e "${HEADER}${line}${RESET}" + echo -e "${HEADER}=====[ ${BOLD}Peritia System Tools${RESET}${HEADER} ]=====${RESET}" + echo -e " + ${VALUE}${BOLD} + +$(figlet -f banner3 "${logo}" | sed 's/#/โ–ˆ/g') ${RESET}${HEADER}by Peritia-System${RESET} + + ${RESET}" + + #cat ../Logo-68px.txt + + 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-show_spinner() { + local pid=$1 + local spinner_delay=0.1 + local spinstr='|/-\' + local start_time=$(date +%s%3N) + + echo -ne "${CYAN}โณ Starting rebuild...${RESET} " + + ( + while kill -0 "$pid" 2>/dev/null; do + local now=$(date +%s%3N) + local elapsed=$((now - start_time)) + local seconds=$((elapsed / 1000)) + local milliseconds=$((elapsed % 1000)) + local clock_time=$(date +%T) # format: HH:MM:SS + + 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 for the main process + wait "$pid" + local exit_status=$? + + # Kill spinner and wait + kill "$spinner_pid" 2>/dev/null + wait "$spinner_pid" 2>/dev/null + + local end_time=$(date +%s%3N) + local total_elapsed=$((end_time - start_time)) + local total_sec=$((total_elapsed / 1000)) + local total_ms=$((total_elapsed % 1000)) + local end_clock_time=$(date +%T) + + echo -e "\r${GREEN}โœ… Completed at ${end_clock_time}, total: ${total_sec}.${total_ms}s${RESET} " + + return $exit_status +}