initial commit
This commit is contained in:
438
modules/home/scripts/saugcli.nix
Normal file
438
modules/home/scripts/saugcli.nix
Normal file
@@ -0,0 +1,438 @@
|
||||
{ pkgs
|
||||
, profile
|
||||
, backupFiles ? [ ".config/mimeapps.list.backup" ]
|
||||
, ...
|
||||
}:
|
||||
let
|
||||
backupFilesString = pkgs.lib.strings.concatStringsSep " " backupFiles;
|
||||
in
|
||||
|
||||
pkgs.writeShellScriptBin "saugcli" ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# --- Configuration ---
|
||||
PROJECT="zaneyos/SaugOS"
|
||||
PROFILE="${profile}"
|
||||
BACKUP_FILES_STR="${backupFilesString}"
|
||||
VERSION="1.0.0"
|
||||
FLAKE_NIX_PATH="$HOME/$PROJECT/flake.nix"
|
||||
|
||||
read -r -a BACKUP_FILES <<< "$BACKUP_FILES_STR"
|
||||
|
||||
# --- Helper Functions ---
|
||||
verify_hostname() {
|
||||
local current_hostname
|
||||
local flake_hostname
|
||||
|
||||
current_hostname="$(hostname)"
|
||||
|
||||
if [ -f "$FLAKE_NIX_PATH" ]; then
|
||||
flake_hostname=$(${pkgs.gnugrep}/bin/grep -E '^[[:space:]]*host[[:space:]]*=' "$FLAKE_NIX_PATH" | ${pkgs.gnused}/bin/sed 's/.*=[[:space:]]*"\([^"]*\)".*/\1/')
|
||||
|
||||
if [ -z "$flake_hostname" ]; then
|
||||
echo "Error: Could not find 'host' variable in $FLAKE_NIX_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$current_hostname" != "$flake_hostname" ]; then
|
||||
echo "Error: Hostname mismatch!" >&2
|
||||
echo " Current hostname: '$current_hostname'" >&2
|
||||
echo " Flake.nix host: '$flake_hostname'" >&2
|
||||
echo "" >&2
|
||||
echo "Hint: Run 'saugcli update-host' to automatically update flake.nix" >&2
|
||||
echo " or manually edit $FLAKE_NIX_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "Error: Flake.nix not found at $FLAKE_NIX_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local folder="$HOME/$PROJECT/hosts/$current_hostname"
|
||||
if [ ! -d "$folder" ]; then
|
||||
echo "Error: Matching host not found in $PROJECT, Missing folder: $folder" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
print_help() {
|
||||
echo "SaugOS CLI Utility -- version $VERSION"
|
||||
echo ""
|
||||
echo "Usage: saugcli [command] [options]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " cleanup - Clean up old system generations."
|
||||
echo " diag - Create a system diagnostic report (~diag.txt)."
|
||||
echo " list-gens - List user and system generations."
|
||||
echo " rebuild - Rebuild the NixOS system configuration."
|
||||
echo " rebuild-boot - Rebuild and set as boot default (activates on next restart)."
|
||||
echo " trim - Trim filesystems to improve SSD performance."
|
||||
echo " update - Update the flake and rebuild the system."
|
||||
echo " update-host - Auto set host and profile in flake.nix."
|
||||
echo " (Opt: saugcli update-host [hostname] [profile])"
|
||||
echo " add-host - Add a new host configuration."
|
||||
echo " del-host - Delete a host configuration."
|
||||
echo ""
|
||||
echo "Options for rebuild, rebuild-boot, and update commands:"
|
||||
echo " --dry, -n - Show what would be done without doing it"
|
||||
echo " --ask, -a - Ask for confirmation before proceeding"
|
||||
echo " --cores N - Limit build to N cores (useful for low-resource machines)"
|
||||
echo " --verbose, -v - Show verbose output"
|
||||
echo " --no-nom - Don't use nix-output-monitor"
|
||||
echo ""
|
||||
echo " help - Show this help message."
|
||||
}
|
||||
|
||||
handle_backups() {
|
||||
if [ ''${#BACKUP_FILES[@]} -eq 0 ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
for file_path in "''${BACKUP_FILES[@]}"; do
|
||||
full_path="$HOME/$file_path"
|
||||
if [ -f "$full_path" ]; then
|
||||
echo "Removing stale backup file: $full_path"
|
||||
rm "$full_path"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
detect_gpu_profile() {
|
||||
local detected_profile=""
|
||||
local has_intel=false
|
||||
local has_amd=false
|
||||
local has_vm=false
|
||||
|
||||
if ${pkgs.pciutils}/bin/lspci &> /dev/null; then
|
||||
if ${pkgs.pciutils}/bin/lspci | ${pkgs.gnugrep}/bin/grep -qi 'vga\|3d'; then
|
||||
while read -r line; do
|
||||
if echo "$line" | ${pkgs.gnugrep}/bin/grep -qi 'amd'; then
|
||||
has_amd=true
|
||||
elif echo "$line" | ${pkgs.gnugrep}/bin/grep -qi 'intel'; then
|
||||
has_intel=true
|
||||
elif echo "$line" | ${pkgs.gnugrep}/bin/grep -qi 'virtio\|vmware'; then
|
||||
has_vm=true
|
||||
fi
|
||||
done < <(${pkgs.pciutils}/bin/lspci | ${pkgs.gnugrep}/bin/grep -i 'vga\|3d')
|
||||
|
||||
if "$has_vm"; then
|
||||
detected_profile="vm"
|
||||
elif "$has_amd"; then
|
||||
detected_profile="amd"
|
||||
elif "$has_intel"; then
|
||||
detected_profile="intel"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "Warning: lspci command not found. Cannot auto-detect GPU profile." >&2
|
||||
fi
|
||||
echo "$detected_profile"
|
||||
}
|
||||
|
||||
parse_nh_args() {
|
||||
local args_string=""
|
||||
local options_selected=()
|
||||
shift
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--dry|-n)
|
||||
args_string="$args_string --dry"
|
||||
options_selected+=("dry run mode (showing what would be done)")
|
||||
shift
|
||||
;;
|
||||
--ask|-a)
|
||||
args_string="$args_string --ask"
|
||||
options_selected+=("confirmation prompts enabled")
|
||||
shift
|
||||
;;
|
||||
--cores)
|
||||
if [[ -n $2 && $2 =~ ^[0-9]+$ ]]; then
|
||||
args_string="$args_string -- --cores $2"
|
||||
options_selected+=("limited to $2 CPU cores")
|
||||
shift 2
|
||||
else
|
||||
echo "Error: --cores requires a numeric argument" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--verbose|-v)
|
||||
args_string="$args_string --verbose"
|
||||
options_selected+=("verbose output enabled")
|
||||
shift
|
||||
;;
|
||||
--no-nom)
|
||||
args_string="$args_string --no-nom"
|
||||
options_selected+=("nix-output-monitor disabled")
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
args_string="$args_string -- $*"
|
||||
options_selected+=("additional arguments: $*")
|
||||
break
|
||||
;;
|
||||
-*)
|
||||
echo "Warning: Unknown flag '$1' - passing through to nh" >&2
|
||||
args_string="$args_string $1"
|
||||
options_selected+=("unknown flag '$1' passed through")
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "Error: Unexpected argument '$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ''${#options_selected[@]} -gt 0 ]]; then
|
||||
echo "Options selected:" >&2
|
||||
for option in "''${options_selected[@]}"; do
|
||||
echo " ✓ $option" >&2
|
||||
done
|
||||
echo >&2
|
||||
fi
|
||||
|
||||
echo "$args_string"
|
||||
}
|
||||
|
||||
# --- Main Logic ---
|
||||
if [ "$#" -eq 0 ]; then
|
||||
echo "Error: No command provided." >&2
|
||||
print_help
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
cleanup)
|
||||
echo "Warning! This will remove old generations of your system."
|
||||
read -p "How many generations to keep (default: all)? " keep_count
|
||||
|
||||
if [ -z "$keep_count" ]; then
|
||||
read -p "This will remove all but the current generation. Continue (y/N)? " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
${pkgs.nh}/bin/nh clean all -v
|
||||
else
|
||||
echo "Cleanup cancelled."
|
||||
fi
|
||||
else
|
||||
read -p "This will keep the last $keep_count generations. Continue (y/N)? " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
${pkgs.nh}/bin/nh clean all -k "$keep_count" -v
|
||||
else
|
||||
echo "Cleanup cancelled."
|
||||
fi
|
||||
fi
|
||||
|
||||
LOG_DIR="$HOME/saugcli-cleanup-logs"
|
||||
mkdir -p "$LOG_DIR"
|
||||
LOG_FILE="$LOG_DIR/saugcli-cleanup-$(${pkgs.coreutils}/bin/date +%Y-%m-%d_%H-%M-%S).log"
|
||||
echo "Cleaning up old log files..." >> "$LOG_FILE"
|
||||
${pkgs.findutils}/bin/find "$LOG_DIR" -type f -mtime +3 -name "*.log" -delete >> "$LOG_FILE" 2>&1
|
||||
echo "Cleanup process logged to $LOG_FILE"
|
||||
;;
|
||||
diag)
|
||||
echo "Generating system diagnostic report..."
|
||||
${pkgs.inxi}/bin/inxi --full > "$HOME/diag.txt"
|
||||
echo "Diagnostic report saved to $HOME/diag.txt"
|
||||
;;
|
||||
help)
|
||||
print_help
|
||||
;;
|
||||
list-gens)
|
||||
echo "--- User Generations ---"
|
||||
${pkgs.nix}/bin/nix-env --list-generations | ${pkgs.coreutils}/bin/cat || echo "Could not list user generations."
|
||||
echo ""
|
||||
echo "--- System Generations ---"
|
||||
${pkgs.nix}/bin/nix profile history --profile /nix/var/nix/profiles/system | ${pkgs.coreutils}/bin/cat || echo "Could not list system generations."
|
||||
;;
|
||||
rebuild)
|
||||
verify_hostname
|
||||
handle_backups
|
||||
|
||||
extra_args=$(parse_nh_args "$@")
|
||||
|
||||
echo "Starting NixOS rebuild for host: $(${pkgs.nettools}/bin/hostname)"
|
||||
if eval "${pkgs.nh}/bin/nh os switch --hostname '$PROFILE' $extra_args"; then
|
||||
echo "Rebuild finished successfully"
|
||||
else
|
||||
echo "Rebuild Failed" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
rebuild-boot)
|
||||
verify_hostname
|
||||
handle_backups
|
||||
|
||||
extra_args=$(parse_nh_args "$@")
|
||||
|
||||
echo "Starting NixOS rebuild (boot) for host: $(${pkgs.nettools}/bin/hostname)"
|
||||
echo "Note: Configuration will be activated on next reboot"
|
||||
if eval "${pkgs.nh}/bin/nh os boot --hostname '$PROFILE' $extra_args"; then
|
||||
echo "Rebuild-boot finished successfully"
|
||||
echo "New configuration set as boot default - restart to activate"
|
||||
else
|
||||
echo "Rebuild-boot Failed" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
trim)
|
||||
echo "Running 'sudo fstrim -v /' may take a few minutes and impact system performance."
|
||||
read -p "Enter (y/Y) to run now or enter to exit (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Running fstrim..."
|
||||
sudo ${pkgs.util-linux}/bin/fstrim -v /
|
||||
echo "fstrim complete."
|
||||
else
|
||||
echo "Trim operation cancelled."
|
||||
fi
|
||||
;;
|
||||
update)
|
||||
verify_hostname
|
||||
handle_backups
|
||||
|
||||
extra_args=$(parse_nh_args "$@")
|
||||
|
||||
echo "Updating flake and rebuilding system for host: $(${pkgs.nettools}/bin/hostname)"
|
||||
if eval "${pkgs.nh}/bin/nh os switch --hostname '$PROFILE' --update $extra_args"; then
|
||||
echo "Update and rebuild finished successfully"
|
||||
else
|
||||
echo "Update and rebuild Failed" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
update-host)
|
||||
target_hostname=""
|
||||
target_profile=""
|
||||
|
||||
if [ "$#" -eq 3 ]; then
|
||||
target_hostname="$2"
|
||||
target_profile="$3"
|
||||
elif [ "$#" -eq 1 ]; then
|
||||
echo "Attempting to auto-detect hostname and GPU profile..."
|
||||
target_hostname=$(${pkgs.nettools}/bin/hostname)
|
||||
target_profile=$(detect_gpu_profile)
|
||||
|
||||
if [ -z "$target_profile" ]; then
|
||||
echo "Error: Could not auto-detect a specific GPU profile. Please provide it manually." >&2
|
||||
echo "Usage: saugcli update-host [hostname] [profile]" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Auto-detected Hostname: $target_hostname"
|
||||
echo "Auto-detected Profile: $target_profile"
|
||||
else
|
||||
echo "Error: Invalid number of arguments for 'update-host'." >&2
|
||||
echo "Usage: saugcli update-host [hostname] [profile]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Updating $FLAKE_NIX_PATH..."
|
||||
|
||||
if ${pkgs.gnused}/bin/sed -i "s/^[[:space:]]*host[[:space:]]*=[[:space:]]*\".*\"/ host = \"$target_hostname\"/" "$FLAKE_NIX_PATH"; then
|
||||
echo "Successfully updated host to: $target_hostname"
|
||||
else
|
||||
echo "Error: Failed to update host in $FLAKE_NIX_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ${pkgs.gnused}/bin/sed -i "s/^[[:space:]]*profile[[:space:]]*=[[:space:]]*\".*\"/ profile = \"$target_profile\"/" "$FLAKE_NIX_PATH"; then
|
||||
echo "Successfully updated profile to: $target_profile"
|
||||
else
|
||||
echo "Error: Failed to update profile in $FLAKE_NIX_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Flake.nix updated successfully!"
|
||||
;;
|
||||
add-host)
|
||||
hostname=""
|
||||
profile_arg=""
|
||||
|
||||
if [ "$#" -ge 2 ]; then
|
||||
hostname="$2"
|
||||
fi
|
||||
if [ "$#" -eq 3 ]; then
|
||||
profile_arg="$3"
|
||||
fi
|
||||
|
||||
if [ -z "$hostname" ]; then
|
||||
read -p "Enter the new hostname: " hostname
|
||||
fi
|
||||
|
||||
if [ -d "$HOME/$PROJECT/hosts/$hostname" ]; then
|
||||
echo "Error: Host '$hostname' already exists." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Copying default host configuration..."
|
||||
${pkgs.coreutils}/bin/cp -r "$HOME/$PROJECT/hosts/default" "$HOME/$PROJECT/hosts/$hostname"
|
||||
|
||||
detected_profile=""
|
||||
if [[ -n "$profile_arg" && "$profile_arg" =~ ^(intel|amd|vm)$ ]]; then
|
||||
detected_profile="$profile_arg"
|
||||
else
|
||||
echo "Detecting GPU profile..."
|
||||
detected_profile=$(detect_gpu_profile)
|
||||
echo "Detected GPU profile: $detected_profile"
|
||||
read -p "Is this correct? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
||||
read -p "Enter the correct profile (intel, amd, vm): " new_profile
|
||||
while [[ ! "$new_profile" =~ ^(intel|amd|vm)$ ]]; do
|
||||
echo "Invalid profile. Please enter one of the following: intel, amd, vm"
|
||||
read -p "Enter the correct profile: " new_profile
|
||||
done
|
||||
detected_profile=$new_profile
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Setting profile to '$detected_profile'..."
|
||||
${pkgs.gnused}/bin/sed -i "s/profile = .*/profile = \"$detected_profile\";/" "$HOME/$PROJECT/hosts/$hostname/default.nix"
|
||||
|
||||
read -p "Generate new hardware.nix? (y/n) " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Generating hardware.nix..."
|
||||
sudo nixos-generate-config --show-hardware-config > "$HOME/$PROJECT/hosts/$hostname/hardware.nix"
|
||||
echo "hardware.nix generated."
|
||||
fi
|
||||
|
||||
echo "Adding new host to git..."
|
||||
${pkgs.git}/bin/git -C "$HOME/$PROJECT" add .
|
||||
echo "hostname: $hostname added"
|
||||
;;
|
||||
del-host)
|
||||
hostname=""
|
||||
if [ "$#" -eq 2 ]; then
|
||||
hostname="$2"
|
||||
else
|
||||
read -p "Enter the hostname to delete: " hostname
|
||||
fi
|
||||
|
||||
if [ ! -d "$HOME/$PROJECT/hosts/$hostname" ]; then
|
||||
echo "Error: Host '$hostname' does not exist." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
read -p "Are you sure you want to delete the host '$hostname'? (y/N) " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Deleting host '$hostname'..."
|
||||
${pkgs.coreutils}/bin/rm -rf "$HOME/$PROJECT/hosts/$hostname"
|
||||
${pkgs.git}/bin/git -C "$HOME/$PROJECT" add .
|
||||
echo "hostname: $hostname removed"
|
||||
else
|
||||
echo "Deletion cancelled."
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Error: Invalid command '$1'" >&2
|
||||
print_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
''
|
||||
Reference in New Issue
Block a user