dev: automated commit - 2025-06-08 23:28:55
This commit is contained in:
parent
33106ea4a6
commit
0ab9f62ace
13 changed files with 1255 additions and 715 deletions
252
common.sh
Normal file
252
common.sh
Normal file
|
@ -0,0 +1,252 @@
|
|||
#!/usr/bin/env bash
|
||||
# Script Standards and Common Functions
|
||||
# Source this file in your scripts for consistent behavior
|
||||
|
||||
# ==============================================================================
|
||||
# STANDARD SCRIPT HEADER
|
||||
# ==============================================================================
|
||||
# All scripts should start with:
|
||||
# #!/usr/bin/env bash
|
||||
# # NAME: Brief description of what the script does
|
||||
# # REQUIRES: sudo interactive (if needed)
|
||||
#
|
||||
# set -euo pipefail
|
||||
#
|
||||
# # Source common functions (adjust path as needed)
|
||||
# source "$(dirname "$0")/common.sh" 2>/dev/null || true
|
||||
|
||||
# ==============================================================================
|
||||
# CONFIGURATION
|
||||
# ==============================================================================
|
||||
readonly SCRIPT_NAME="${0##*/}"
|
||||
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Colors for output (only if terminal supports it)
|
||||
if [[ -t 1 ]] && command -v tput >/dev/null 2>&1; then
|
||||
readonly RED=$(tput setaf 1)
|
||||
readonly GREEN=$(tput setaf 2)
|
||||
readonly YELLOW=$(tput setaf 3)
|
||||
readonly BLUE=$(tput setaf 4)
|
||||
readonly PURPLE=$(tput setaf 5)
|
||||
readonly CYAN=$(tput setaf 6)
|
||||
readonly WHITE=$(tput setaf 7)
|
||||
readonly BOLD=$(tput bold)
|
||||
readonly RESET=$(tput sgr0)
|
||||
else
|
||||
readonly RED="" GREEN="" YELLOW="" BLUE="" PURPLE="" CYAN="" WHITE="" BOLD="" RESET=""
|
||||
fi
|
||||
|
||||
# ==============================================================================
|
||||
# LOGGING FUNCTIONS
|
||||
# ==============================================================================
|
||||
log_info() {
|
||||
printf "${GREEN}[INFO]${RESET} %s\n" "$*"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
printf "${YELLOW}[WARN]${RESET} %s\n" "$*" >&2
|
||||
}
|
||||
|
||||
log_error() {
|
||||
printf "${RED}[ERROR]${RESET} %s\n" "$*" >&2
|
||||
}
|
||||
|
||||
log_success() {
|
||||
printf "${GREEN}[SUCCESS]${RESET} %s\n" "$*"
|
||||
}
|
||||
|
||||
log_debug() {
|
||||
if [[ "${DEBUG:-0}" == "1" ]]; then
|
||||
printf "${CYAN}[DEBUG]${RESET} %s\n" "$*" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
log_sudo() {
|
||||
printf "${PURPLE}[SUDO]${RESET} %s\n" "$*"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# UTILITY FUNCTIONS
|
||||
# ==============================================================================
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
is_root() {
|
||||
[[ $EUID -eq 0 ]]
|
||||
}
|
||||
|
||||
require_root() {
|
||||
if ! is_root; then
|
||||
log_error "This script requires root privileges"
|
||||
log_info "Run with: sudo $0 $*"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if running in interactive terminal
|
||||
is_interactive() {
|
||||
[[ -t 0 && -t 1 ]]
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# CONFIRMATION FUNCTIONS
|
||||
# ==============================================================================
|
||||
confirm() {
|
||||
local prompt="${1:-Continue?}"
|
||||
local default="${2:-n}"
|
||||
local response
|
||||
|
||||
if ! is_interactive; then
|
||||
log_warn "Non-interactive mode, using default: $default"
|
||||
[[ "$default" == "y" ]]
|
||||
return $?
|
||||
fi
|
||||
|
||||
while true; do
|
||||
if [[ "$default" == "y" ]]; then
|
||||
printf "%s [Y/n]: " "$prompt"
|
||||
else
|
||||
printf "%s [y/N]: " "$prompt"
|
||||
fi
|
||||
|
||||
read -r response
|
||||
response=${response,,} # Convert to lowercase
|
||||
|
||||
case "$response" in
|
||||
"")
|
||||
[[ "$default" == "y" ]]
|
||||
return $?
|
||||
;;
|
||||
y | yes)
|
||||
return 0
|
||||
;;
|
||||
n | no)
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
log_warn "Please answer 'y' or 'n'"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Show changes and confirm
|
||||
confirm_change() {
|
||||
local file="$1"
|
||||
local description="$2"
|
||||
local temp_file="$3"
|
||||
|
||||
log_info "Proposed changes for $description:"
|
||||
log_info "File: $file"
|
||||
echo
|
||||
|
||||
if command_exists colordiff; then
|
||||
colordiff -u "$file" "$temp_file" 2>/dev/null || diff -u "$file" "$temp_file" 2>/dev/null || true
|
||||
else
|
||||
diff -u "$file" "$temp_file" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo
|
||||
confirm "Apply these changes?"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# FILE OPERATIONS
|
||||
# ==============================================================================
|
||||
backup_file() {
|
||||
local file="$1"
|
||||
local backup_suffix="${2:-$(date +%Y%m%d_%H%M%S)}"
|
||||
local backup_file="${file}.backup.${backup_suffix}"
|
||||
|
||||
if [[ -f "$file" ]]; then
|
||||
cp "$file" "$backup_file"
|
||||
log_info "Created backup: $backup_file"
|
||||
echo "$backup_file"
|
||||
fi
|
||||
}
|
||||
|
||||
create_temp_file() {
|
||||
local template="${1:-tmp.XXXXXX}"
|
||||
mktemp "/tmp/${template}"
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# PACKAGE MANAGEMENT
|
||||
# ==============================================================================
|
||||
install_packages() {
|
||||
local packages=("$@")
|
||||
|
||||
if [[ ${#packages[@]} -eq 0 ]]; then
|
||||
log_warn "No packages specified"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Installing packages: ${packages[*]}"
|
||||
|
||||
if command_exists paru; then
|
||||
paru -S --needed --noconfirm "${packages[@]}"
|
||||
elif command_exists pacman; then
|
||||
sudo pacman -S --needed --noconfirm "${packages[@]}"
|
||||
else
|
||||
log_error "No supported package manager found"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# SERVICE MANAGEMENT
|
||||
# ==============================================================================
|
||||
enable_service() {
|
||||
local service="$1"
|
||||
local user_service="${2:-false}"
|
||||
|
||||
if [[ "$user_service" == "true" ]]; then
|
||||
log_info "Enabling user service: $service"
|
||||
systemctl --user enable --now "$service"
|
||||
else
|
||||
log_info "Enabling system service: $service"
|
||||
sudo systemctl enable --now "$service"
|
||||
fi
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# ERROR HANDLING
|
||||
# ==============================================================================
|
||||
cleanup() {
|
||||
local exit_code=$?
|
||||
# Add any cleanup operations here
|
||||
exit $exit_code
|
||||
}
|
||||
|
||||
# Set up trap for cleanup
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# ==============================================================================
|
||||
# SCRIPT INITIALIZATION
|
||||
# ==============================================================================
|
||||
init_script() {
|
||||
log_info "Starting $SCRIPT_NAME"
|
||||
|
||||
# Set DEBUG mode if requested
|
||||
if [[ "${1:-}" == "--debug" ]]; then
|
||||
export DEBUG=1
|
||||
log_debug "Debug mode enabled"
|
||||
shift
|
||||
fi
|
||||
}
|
||||
|
||||
# ==============================================================================
|
||||
# SCRIPT COMPLETION
|
||||
# ==============================================================================
|
||||
finish_script() {
|
||||
local exit_code="${1:-0}"
|
||||
|
||||
if [[ "$exit_code" -eq 0 ]]; then
|
||||
log_success "$SCRIPT_NAME completed successfully"
|
||||
else
|
||||
log_error "$SCRIPT_NAME failed with exit code $exit_code"
|
||||
fi
|
||||
|
||||
exit "$exit_code"
|
||||
}
|
102
main.go
102
main.go
|
@ -32,11 +32,12 @@ type Config struct {
|
|||
}
|
||||
|
||||
type Script struct {
|
||||
Path string // Full filesystem path
|
||||
Name string // Just filename (e.g. "install.sh")
|
||||
RelPath string // Relative path from runs/ (e.g. "tools/install.sh")
|
||||
Desc string // Description from script comment
|
||||
RequiresSudo bool // Whether script needs elevated privileges
|
||||
Path string // Full filesystem path
|
||||
Name string // Just filename (e.g. "install.sh")
|
||||
RelPath string // Relative path from runs/ (e.g. "tools/install.sh")
|
||||
Desc string // Description from script comment
|
||||
RequiresSudo bool // Whether script needs elevated privileges
|
||||
RequiresInteractive bool // Whether script needs interactive input
|
||||
}
|
||||
|
||||
var config Config
|
||||
|
@ -213,15 +214,20 @@ func handlePush() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func getScriptMetadata(scriptPath string) (string, bool) {
|
||||
type ScriptMetadata struct {
|
||||
RequiresSudo bool
|
||||
RequiresInteractive bool
|
||||
}
|
||||
|
||||
func getScriptMetadata(scriptPath string) (string, ScriptMetadata) {
|
||||
file, err := os.Open(scriptPath)
|
||||
if err != nil {
|
||||
return "No description", false
|
||||
return "No description", ScriptMetadata{}
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var desc string
|
||||
var requiresSudo bool
|
||||
scriptMetadata := ScriptMetadata{}
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
|
@ -231,13 +237,9 @@ func getScriptMetadata(scriptPath string) (string, bool) {
|
|||
desc = strings.TrimSpace(strings.TrimPrefix(line, "# NAME:"))
|
||||
}
|
||||
|
||||
if strings.HasPrefix(line, "# REQUIRES: sudo") ||
|
||||
strings.HasPrefix(line, "# REQUIRES:sudo") ||
|
||||
strings.HasPrefix(line, "# ELEVATED: true") ||
|
||||
strings.HasPrefix(line, "# ELEVATED:true") ||
|
||||
strings.HasPrefix(line, "# SUDO: true") ||
|
||||
strings.HasPrefix(line, "# SUDO:true") {
|
||||
requiresSudo = true
|
||||
if strings.HasPrefix(line, "# REQUIRES:") {
|
||||
scriptMetadata.RequiresSudo = strings.Contains(line, "sudo")
|
||||
scriptMetadata.RequiresInteractive = strings.Contains(line, "interactive")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -245,7 +247,7 @@ func getScriptMetadata(scriptPath string) (string, bool) {
|
|||
desc = "No description"
|
||||
}
|
||||
|
||||
return desc, requiresSudo
|
||||
return desc, scriptMetadata
|
||||
}
|
||||
|
||||
func findScripts(filters []string) ([]Script, error) {
|
||||
|
@ -271,14 +273,15 @@ func findScripts(filters []string) ([]Script, error) {
|
|||
scriptName := filepath.Base(path)
|
||||
|
||||
if len(filters) == 0 || matchesFilters(relPath, scriptName, filters) {
|
||||
desc, requiresSudo := getScriptMetadata(path)
|
||||
desc, metaData := getScriptMetadata(path)
|
||||
|
||||
scripts = append(scripts, Script{
|
||||
Path: path,
|
||||
Name: scriptName,
|
||||
RelPath: relPath,
|
||||
Desc: desc,
|
||||
RequiresSudo: requiresSudo,
|
||||
Path: path,
|
||||
Name: scriptName,
|
||||
RelPath: relPath,
|
||||
Desc: desc,
|
||||
RequiresSudo: metaData.RequiresSudo,
|
||||
RequiresInteractive: metaData.RequiresInteractive,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -331,14 +334,15 @@ func executeScript(script Script, args []string, verbose bool) error {
|
|||
errorLog("sudo command not found - cannot run elevated script")
|
||||
return fmt.Errorf("sudo not available")
|
||||
}
|
||||
fullArgs := append([]string{script.Path}, args...)
|
||||
// Use -S to read password from stdin, and preserve environment
|
||||
fullArgs := append([]string{"-S", "-E", script.Path}, args...)
|
||||
cmd = exec.Command("sudo", fullArgs...)
|
||||
sudoLog("Running with sudo: %s", strings.Join(append([]string{script.Path}, args...), " "))
|
||||
} else {
|
||||
cmd = exec.Command(script.Path, args...)
|
||||
}
|
||||
|
||||
if config.Interactive {
|
||||
if config.Interactive || script.RequiresInteractive {
|
||||
cmd.Stdin = os.Stdin
|
||||
}
|
||||
|
||||
|
@ -348,7 +352,7 @@ func executeScript(script Script, args []string, verbose bool) error {
|
|||
}
|
||||
defer logFileHandle.Close()
|
||||
|
||||
showOutput := verbose || config.Interactive
|
||||
showOutput := verbose || config.Interactive || script.RequiresInteractive
|
||||
if showOutput {
|
||||
cmd.Stdout = io.MultiWriter(os.Stdout, logFileHandle)
|
||||
cmd.Stderr = io.MultiWriter(os.Stderr, logFileHandle)
|
||||
|
@ -371,6 +375,7 @@ func createNewScript(scriptName string) error {
|
|||
|
||||
if !strings.HasSuffix(scriptName, ".sh") {
|
||||
scriptName += ".sh"
|
||||
scriptPath = filepath.Join(config.RunsDir, scriptName)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(scriptPath); err == nil {
|
||||
|
@ -378,15 +383,52 @@ func createNewScript(scriptName string) error {
|
|||
}
|
||||
|
||||
template := fmt.Sprintf(`#!/usr/bin/env bash
|
||||
# NAME: %s script
|
||||
# REQUIRES: sudo
|
||||
# NAME: %s
|
||||
# REQUIRES: sudo interactive
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "Running %s script..."
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "✅ %s completed successfully"
|
||||
`, strings.TrimSuffix(scriptName, ".sh"), scriptName, strings.TrimSuffix(scriptName, ".sh"))
|
||||
check_requirements() {
|
||||
# Check required commands
|
||||
local required_commands=()
|
||||
# Add your required commands here
|
||||
# required_commands=(git curl wget)
|
||||
|
||||
for cmd in "${required_commands[@]}"; do
|
||||
if ! command_exists "$cmd"; then
|
||||
log_error "Required command not found: $cmd"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
main() {
|
||||
init_script
|
||||
|
||||
check_requirements
|
||||
|
||||
# Your main script logic goes here
|
||||
|
||||
|
||||
# Example operations:
|
||||
# if ! confirm "Proceed with operation?"; then
|
||||
# log_info "Operation cancelled"
|
||||
# finish_script 0
|
||||
# fi
|
||||
|
||||
# Add your implementation here
|
||||
|
||||
finish_script 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
`, strings.TrimSuffix(filepath.Base(scriptName), ".sh"))
|
||||
|
||||
err := os.WriteFile(scriptPath, []byte(template), 0o755)
|
||||
if err != nil {
|
||||
|
|
84
runs/aur
84
runs/aur
|
@ -1,34 +1,62 @@
|
|||
#!/usr/bin/env bash
|
||||
# NAME: aur script
|
||||
# NAME: Install AUR packages
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "Running aur.sh script..."
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
paru -S --needed --noconfirm adwaita-dark \
|
||||
aws-session-manager-plugin \
|
||||
bottles \
|
||||
bruno-bin \
|
||||
davmail \
|
||||
dmg2img \
|
||||
ebgaramond-otf \
|
||||
insomnia-bin \
|
||||
kubefwd-bin \
|
||||
mpvpaper \
|
||||
ngrok \
|
||||
openvpn3-git \
|
||||
otf-font-awesome-5 \
|
||||
postman-bin \
|
||||
rofi-lbonn-wayland-git \
|
||||
rose-pine-gtk-theme \
|
||||
slack-desktop \
|
||||
soapui \
|
||||
sublime-merge \
|
||||
swayfx-git \
|
||||
teams-for-linux-bin \
|
||||
ttf-font-awesome-5 \
|
||||
ttf-ms-win11-auto \
|
||||
watchman-bin \
|
||||
yubico-authenticator-bin
|
||||
check_requirements() {
|
||||
if ! command_exists paru; then
|
||||
log_error "paru not found. Install it first"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo "✅ aur completed successfully"
|
||||
install_aur_packages() {
|
||||
local packages=(
|
||||
adwaita-dark
|
||||
aws-session-manager-plugin
|
||||
bottles
|
||||
bruno-bin
|
||||
davmail
|
||||
dmg2img
|
||||
ebgaramond-otf
|
||||
insomnia-bin
|
||||
kubefwd-bin
|
||||
mpvpaper
|
||||
ngrok
|
||||
openvpn3-git
|
||||
otf-font-awesome-5
|
||||
postman-bin
|
||||
rofi-lbonn-wayland-git
|
||||
rose-pine-gtk-theme
|
||||
slack-desktop
|
||||
soapui
|
||||
sublime-merge
|
||||
swayfx-git
|
||||
teams-for-linux-bin
|
||||
ttf-font-awesome-5
|
||||
ttf-ms-win11-auto
|
||||
watchman-bin
|
||||
yubico-authenticator-bin
|
||||
betterbird-bin
|
||||
)
|
||||
|
||||
log_info "Installing AUR packages"
|
||||
paru -S --needed --noconfirm "${packages[@]}"
|
||||
}
|
||||
|
||||
main() {
|
||||
init_script
|
||||
|
||||
check_requirements
|
||||
install_aur_packages
|
||||
|
||||
finish_script 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
378
runs/base
378
runs/base
|
@ -1,199 +1,237 @@
|
|||
#!/usr/bin/env bash
|
||||
# NAME: Install base system packages
|
||||
# NAME: Install base system packages with hardware detection
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
AUR_HELPER="paru"
|
||||
|
||||
if ! command -v $AUR_HELPER &>/dev/null; then
|
||||
echo "[ERROR] $AUR_HELPER not found. Install it first."
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo "Installing organized system packages..."
|
||||
check_requirements() {
|
||||
if ! command_exists paru; then
|
||||
log_error "paru not found. Install it first"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔧 DETECT HARDWARE
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
CPU_VENDOR=$(lscpu | grep "Vendor ID" | awk '{print $3}')
|
||||
GPU_INFO=$(lspci | grep -i vga)
|
||||
detect_hardware() {
|
||||
local cpu_vendor gpu_info microcode gpu_packages
|
||||
|
||||
echo "Detected CPU: $CPU_VENDOR"
|
||||
echo "Detected GPU: $GPU_INFO"
|
||||
cpu_vendor=$(lscpu | grep "Vendor ID" | awk '{print $3}')
|
||||
gpu_info=$(lspci | grep -i vga)
|
||||
|
||||
# Determine microcode package
|
||||
if [[ "$CPU_VENDOR" == "GenuineIntel" ]]; then
|
||||
MICROCODE="intel-ucode"
|
||||
echo "→ Using Intel microcode"
|
||||
elif [[ "$CPU_VENDOR" == "AuthenticAMD" ]]; then
|
||||
MICROCODE="amd-ucode"
|
||||
echo "→ Using AMD microcode"
|
||||
else
|
||||
MICROCODE=""
|
||||
echo "→ Unknown CPU vendor, skipping microcode"
|
||||
fi
|
||||
log_info "Detected CPU: $cpu_vendor"
|
||||
log_info "Detected GPU: $gpu_info"
|
||||
|
||||
# Determine GPU drivers
|
||||
GPU_PACKAGES=""
|
||||
if echo "$GPU_INFO" | grep -qi "amd\|radeon"; then
|
||||
GPU_PACKAGES="xf86-video-amdgpu vulkan-radeon lib32-vulkan-radeon opencl-mesa lib32-opencl-mesa"
|
||||
echo "→ Using AMD GPU drivers"
|
||||
elif echo "$GPU_INFO" | grep -qi "intel"; then
|
||||
GPU_PACKAGES="xf86-video-intel vulkan-intel lib32-vulkan-intel intel-media-driver"
|
||||
echo "→ Using Intel GPU drivers"
|
||||
elif echo "$GPU_INFO" | grep -qi "nvidia"; then
|
||||
GPU_PACKAGES="nvidia nvidia-utils lib32-nvidia-utils nvidia-settings"
|
||||
echo "→ Using NVIDIA drivers (you may want to review this)"
|
||||
else
|
||||
echo "→ Unknown GPU, using generic drivers"
|
||||
fi
|
||||
# Determine microcode package
|
||||
case "$cpu_vendor" in
|
||||
"GenuineIntel")
|
||||
microcode="intel-ucode"
|
||||
log_info "Using Intel microcode"
|
||||
;;
|
||||
"AuthenticAMD")
|
||||
microcode="amd-ucode"
|
||||
log_info "Using AMD microcode"
|
||||
;;
|
||||
*)
|
||||
microcode=""
|
||||
log_warn "Unknown CPU vendor, skipping microcode"
|
||||
;;
|
||||
esac
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔧 SYSTEM BASE
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing system base..."
|
||||
BASE_PACKAGES="base base-devel sudo stow linux-cachyos linux-cachyos-headers linux-firmware efibootmgr efitools mkinitcpio grub systemd-boot-manager"
|
||||
# Determine GPU drivers
|
||||
gpu_packages=""
|
||||
if echo "$gpu_info" | grep -qi "amd\|radeon"; then
|
||||
gpu_packages="xf86-video-amdgpu vulkan-radeon lib32-vulkan-radeon opencl-mesa lib32-opencl-mesa"
|
||||
log_info "Using AMD GPU drivers"
|
||||
elif echo "$gpu_info" | grep -qi "intel"; then
|
||||
gpu_packages="xf86-video-intel vulkan-intel lib32-vulkan-intel intel-media-driver"
|
||||
log_info "Using Intel GPU drivers"
|
||||
elif echo "$gpu_info" | grep -qi "nvidia"; then
|
||||
gpu_packages="nvidia nvidia-utils lib32-nvidia-utils nvidia-settings"
|
||||
log_info "Using NVIDIA drivers"
|
||||
else
|
||||
log_warn "Unknown GPU, using generic drivers"
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ -n "$MICROCODE" ]]; then
|
||||
BASE_PACKAGES="$BASE_PACKAGES $MICROCODE"
|
||||
fi
|
||||
install_base_system() {
|
||||
log_info "Installing system base packages"
|
||||
|
||||
$AUR_HELPER -S --noconfirm --needed $BASE_PACKAGES
|
||||
local base_packages="base base-devel sudo stow linux-cachyos linux-cachyos-headers linux-firmware efibootmgr efitools mkinitcpio grub systemd-boot-manager"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🌐 NETWORKING & BLUETOOTH
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing networking..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
networkmanager networkmanager-openvpn network-manager-applet \
|
||||
dhclient dnsmasq iptables-nft iwd wpa_supplicant wireless-regdb \
|
||||
bluez-libs blueman openssh
|
||||
if [[ -n "$microcode" ]]; then
|
||||
base_packages="$base_packages $microcode"
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔊 AUDIO & VIDEO
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing audio/video..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
pipewire pipewire-alsa pipewire-pulse wireplumber \
|
||||
pavucontrol alsa-firmware alsa-plugins alsa-utils \
|
||||
gst-libav gst-plugin-pipewire gst-plugins-bad gst-plugins-ugly \
|
||||
mpv ffmpegthumbnailer
|
||||
paru -S --needed --overwrite="*" $base_packages
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🎨 FONTS & THEMES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing fonts and themes..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
adobe-source-han-sans-cn-fonts adobe-source-han-sans-jp-fonts \
|
||||
adobe-source-han-sans-kr-fonts adobe-source-serif-fonts \
|
||||
awesome-terminal-fonts inter-font noto-fonts noto-fonts-cjk noto-fonts-emoji \
|
||||
ttf-bitstream-vera ttf-dejavu ttf-fantasque-nerd ttf-fira-code ttf-fira-mono \
|
||||
ttf-fira-sans ttf-font-awesome-5 ttf-liberation ttf-linux-libertine \
|
||||
ttf-meslo-nerd ttf-ms-win11-auto ttf-opensans otf-font-awesome-5 otf-libertinus \
|
||||
papirus-icon-theme rose-pine-gtk-theme
|
||||
install_networking() {
|
||||
log_info "Installing networking packages"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 💻 DEVELOPMENT TOOLS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing development tools..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
git git-lfs git-crypt github-cli lazygit \
|
||||
go go-task python python-defusedxml python-packaging \
|
||||
python-protobuf python-pynvim python-pywlroots lua luarocks \
|
||||
ccls cmake ninja neovim-nightly-bin
|
||||
paru -S --needed \
|
||||
networkmanager networkmanager-openvpn network-manager-applet \
|
||||
dhclient dnsmasq iptables-nft iwd wpa_supplicant wireless-regdb \
|
||||
bluez-libs blueman openssh
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🛠️ CLI UTILITIES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing CLI utilities..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
bat btop duf dysk dust eza fd fzf glances glow httpie ncdu \
|
||||
plocate ripgrep tealdeer the_silver_searcher tmux wget \
|
||||
xdg-user-dirs zoxide zellij yazi yq zsh
|
||||
install_audio_video() {
|
||||
log_info "Installing audio and video packages"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🪟 WINDOW MANAGERS & DESKTOP
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing window managers..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
swaybg swayfx-git swayidle swaylock-effects waybar \
|
||||
wlogout wdisplays wl-clipboard rofi-lbonn-wayland-git
|
||||
paru -S --needed \
|
||||
pipewire pipewire-alsa pipewire-pulse wireplumber \
|
||||
pavucontrol alsa-firmware alsa-plugins alsa-utils \
|
||||
gst-libav gst-plugin-pipewire gst-plugins-bad gst-plugins-ugly \
|
||||
mpv ffmpegthumbnailer
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🌍 GUI APPLICATIONS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing GUI applications..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
chromium zen-browser-bin \
|
||||
legcord-bin slack-desktop teams-for-linux-bin \
|
||||
obs-studio obsidian sublime-merge dbeaver \
|
||||
libreoffice-fresh kitty nemo nemo-fileroller
|
||||
install_fonts_themes() {
|
||||
log_info "Installing fonts and themes"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 📁 SYSTEM UTILITIES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing system utilities..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
brightnessctl cronie cups cups-pdf gamemode gvfs gvfs-afc gvfs-google \
|
||||
gvfs-gphoto2 gvfs-mtp gvfs-nfs gvfs-smb haveged hdparm less lvm2 \
|
||||
man-db man-pages meld modemmanager mtools mupdf netctl nss-mdns \
|
||||
ntfs-3g ntp nvme-cli opencl-mesa pacman-contrib pass pika-backup \
|
||||
pkgfile power-profiles-daemon pv reflector remmina rsync rtkit \
|
||||
samba seahorse sg3_utils smartmontools snapper solaar steam \
|
||||
steam-native-runtime syncthing system-config-printer timeshift \
|
||||
transmission-qt ufw unrar unzip upower usb_modeswitch usbutils \
|
||||
vi vorta w3m which xdg-desktop-portal xdg-desktop-portal-gnome \
|
||||
xdg-desktop-portal-gtk xdg-desktop-portal-wlr yad zenity
|
||||
paru -S --needed \
|
||||
adobe-source-han-sans-cn-fonts adobe-source-han-sans-jp-fonts \
|
||||
adobe-source-han-sans-kr-fonts adobe-source-serif-fonts \
|
||||
awesome-terminal-fonts inter-font noto-fonts noto-fonts-cjk noto-fonts-emoji \
|
||||
ttf-bitstream-vera ttf-dejavu ttf-fantasque-nerd ttf-fira-code ttf-fira-mono \
|
||||
ttf-fira-sans ttf-font-awesome-5 ttf-liberation ttf-linux-libertine \
|
||||
ttf-meslo-nerd ttf-ms-win11-auto ttf-opensans otf-font-awesome-5 otf-libertinus \
|
||||
papirus-icon-theme rose-pine-gtk-theme
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🎮 GAMING & GRAPHICS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing gaming and graphics..."
|
||||
GAMING_BASE="lib32-alsa-lib lib32-alsa-plugins lib32-gamemode lib32-libpulse lib32-mesa lib32-openal lib32-vkd3d lib32-vulkan-mesa-layers vkd3d vulkan-mesa-layers vulkan-tools vulkan-validation-layers wine protonup-qt"
|
||||
install_development() {
|
||||
log_info "Installing development tools"
|
||||
|
||||
if [[ -n "$GPU_PACKAGES" ]]; then
|
||||
$AUR_HELPER -S --noconfirm --needed $GAMING_BASE $GPU_PACKAGES
|
||||
else
|
||||
$AUR_HELPER -S --noconfirm --needed $GAMING_BASE
|
||||
fi
|
||||
paru -S --needed \
|
||||
git git-lfs git-crypt github-cli lazygit \
|
||||
go go-task python python-defusedxml python-packaging \
|
||||
python-protobuf python-pynvim python-pywlroots lua luarocks \
|
||||
ccls cmake ninja neovim-nightly-bin
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 📱 MOBILE & HARDWARE
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing hardware support..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
sof-firmware xf86-input-libinput xfsprogs \
|
||||
xorg-server xorg-xdpyinfo xorg-xhost xorg-xinit xorg-xinput \
|
||||
xorg-xkill xorg-xrandr xorg-xwayland
|
||||
install_cli_utilities() {
|
||||
log_info "Installing CLI utilities"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# ☁️ CLOUD & DEVOPS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing cloud and DevOps tools..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
aws-cli aws-session-manager-plugin insomnia-bin \
|
||||
kubectl kubectx kubefwd-bin ngrok postgresql
|
||||
paru -S --needed \
|
||||
bat btop duf dysk dust eza fd fzf glances glow httpie ncdu \
|
||||
plocate ripgrep tealdeer the_silver_searcher tmux wget \
|
||||
xdg-user-dirs zoxide yazi yq zsh
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 📚 DOCUMENT & PRODUCTIVITY
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing document tools..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
pandoc-cli texinfo wkhtmltopdf-bin zathura zathura-pdf-mupdf \
|
||||
swappy wf-recorder
|
||||
install_window_managers() {
|
||||
log_info "Installing window managers and desktop environment"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔐 SECURITY & ENCRYPTION
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing security tools..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
yubico-authenticator-bin yubikey-manager-qt
|
||||
paru -S --needed \
|
||||
swaybg swayfx-git swayidle swaylock-effects waybar \
|
||||
wlogout wdisplays wl-clipboard rofi-lbonn-wayland-git
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 📦 PACKAGE MANAGERS & MISC
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Installing package managers and misc..."
|
||||
$AUR_HELPER -S --noconfirm --needed \
|
||||
pyenv watchman-bin wimlib
|
||||
install_gui_applications() {
|
||||
log_info "Installing GUI applications"
|
||||
|
||||
tldr --update
|
||||
paru -S --needed \
|
||||
chromium zen-browser-bin \
|
||||
legcord-bin slack-desktop teams-for-linux-bin \
|
||||
obs-studio obsidian sublime-merge dbeaver \
|
||||
libreoffice-fresh kitty nemo nemo-fileroller
|
||||
}
|
||||
|
||||
install_system_utilities() {
|
||||
log_info "Installing system utilities"
|
||||
|
||||
paru -S --needed \
|
||||
brightnessctl cronie cups cups-pdf gamemode gvfs gvfs-afc gvfs-google \
|
||||
gvfs-gphoto2 gvfs-mtp gvfs-nfs gvfs-smb haveged hdparm less lvm2 \
|
||||
man-db man-pages meld modemmanager mtools mupdf netctl nss-mdns \
|
||||
ntfs-3g ntp nvme-cli opencl-mesa pacman-contrib pass pika-backup \
|
||||
pkgfile power-profiles-daemon pv reflector remmina rsync rtkit \
|
||||
samba seahorse sg3_utils smartmontools snapper solaar steam \
|
||||
steam-native-runtime syncthing system-config-printer \
|
||||
transmission-qt ufw unrar unzip upower usb_modeswitch usbutils \
|
||||
vi vorta w3m which xdg-desktop-portal xdg-desktop-portal-gnome \
|
||||
xdg-desktop-portal-gtk xdg-desktop-portal-wlr yad zenity
|
||||
}
|
||||
|
||||
install_gaming_graphics() {
|
||||
log_info "Installing gaming and graphics packages"
|
||||
|
||||
local gaming_base="lib32-alsa-lib lib32-alsa-plugins lib32-gamemode lib32-libpulse lib32-mesa lib32-openal lib32-vkd3d lib32-vulkan-mesa-layers vkd3d vulkan-mesa-layers vulkan-tools vulkan-validation-layers wine protonup-qt"
|
||||
|
||||
if [[ -n "$gpu_packages" ]]; then
|
||||
paru -S --needed $gaming_base $gpu_packages
|
||||
else
|
||||
paru -S --needed $gaming_base
|
||||
fi
|
||||
}
|
||||
|
||||
install_hardware_support() {
|
||||
log_info "Installing hardware support"
|
||||
|
||||
paru -S --needed \
|
||||
sof-firmware xf86-input-libinput xfsprogs \
|
||||
xorg-server xorg-xdpyinfo xorg-xhost xorg-xinit xorg-xinput \
|
||||
xorg-xkill xorg-xrandr xorg-xwayland
|
||||
}
|
||||
|
||||
install_cloud_devops() {
|
||||
log_info "Installing cloud and DevOps tools"
|
||||
|
||||
paru -S --needed \
|
||||
aws-cli aws-session-manager-plugin insomnia-bin \
|
||||
kubectl kubectx kubefwd-bin ngrok postgresql
|
||||
}
|
||||
|
||||
install_document_tools() {
|
||||
log_info "Installing document and productivity tools"
|
||||
|
||||
paru -S --needed \
|
||||
pandoc-cli texinfo wkhtmltopdf-bin zathura zathura-pdf-mupdf \
|
||||
swappy wf-recorder
|
||||
}
|
||||
|
||||
install_security_tools() {
|
||||
log_info "Installing security tools"
|
||||
|
||||
paru -S --needed \
|
||||
yubico-authenticator-bin yubikey-manager-qt
|
||||
}
|
||||
|
||||
install_misc_packages() {
|
||||
log_info "Installing miscellaneous packages"
|
||||
|
||||
paru -S --needed \
|
||||
pyenv watchman-bin wimlib \
|
||||
slurp grim swaync gum nwg-look lxsession colordiff
|
||||
|
||||
log_info "Updating tldr database"
|
||||
tldr --update
|
||||
}
|
||||
|
||||
main() {
|
||||
init_script
|
||||
|
||||
check_requirements
|
||||
detect_hardware
|
||||
|
||||
install_base_system
|
||||
install_networking
|
||||
install_audio_video
|
||||
install_fonts_themes
|
||||
install_development
|
||||
install_cli_utilities
|
||||
install_window_managers
|
||||
install_gui_applications
|
||||
install_system_utilities
|
||||
install_gaming_graphics
|
||||
install_hardware_support
|
||||
install_cloud_devops
|
||||
install_document_tools
|
||||
install_security_tools
|
||||
install_misc_packages
|
||||
|
||||
finish_script 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
70
runs/boot
70
runs/boot
|
@ -1,37 +1,40 @@
|
|||
#!/usr/bin/env bash
|
||||
# NAME: Configure systemd-boot manager settings
|
||||
# REQUIRES: sudo
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SDBOOT_CONFIG="/etc/sdboot-manage.conf"
|
||||
|
||||
echo "Configuring systemd-boot manager..."
|
||||
|
||||
# Check if sdboot-manage is installed
|
||||
if ! command -v sdboot-manage &>/dev/null; then
|
||||
echo "⚠️ sdboot-manage not found. Install systemd-boot-manager first."
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Backup existing config if it exists
|
||||
if [[ -f "$SDBOOT_CONFIG" ]]; then
|
||||
sudo cp "$SDBOOT_CONFIG" "$SDBOOT_CONFIG.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
echo "→ Backed up existing config"
|
||||
fi
|
||||
readonly SDBOOT_CONFIG="/etc/sdboot-manage.conf"
|
||||
|
||||
# Create the configuration
|
||||
sudo tee "$SDBOOT_CONFIG" >/dev/null <<'EOF'
|
||||
check_requirements() {
|
||||
if ! command_exists sdboot-manage; then
|
||||
log_error "sdboot-manage not found. Install systemd-boot-manager first"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
configure_systemd_boot() {
|
||||
log_info "Configuring systemd-boot manager"
|
||||
|
||||
if [[ -f "$SDBOOT_CONFIG" ]]; then
|
||||
backup_file "$SDBOOT_CONFIG"
|
||||
fi
|
||||
|
||||
log_info "Creating systemd-boot configuration"
|
||||
tee "$SDBOOT_CONFIG" >/dev/null <<'EOF'
|
||||
# Config file for sdboot-manage
|
||||
# Kernel options to be appended to the "options" line
|
||||
LINUX_OPTIONS="zswap.enabled=0 nowatchdog ipv6.disable=1 audit=0 loglevel=3 rd.systemd.show_status=auto rd.udev.log_level=3"
|
||||
#LINUX_FALLBACK_OPTIONS=""
|
||||
|
||||
# When DISABLE_FALLBACK is set to "yes", it will stop creating fallback entries for each kernel.
|
||||
DISABLE_FALLBACK="no"
|
||||
|
||||
# Use this pattern to match kernels which should be considered native OS kernels
|
||||
#KERNEL_PATTERN="vmlinuz-"
|
||||
|
||||
# Setting REMOVE_EXISTING to "yes" will remove all your existing systemd-boot entries before building new entries
|
||||
REMOVE_EXISTING="yes"
|
||||
|
||||
|
@ -41,19 +44,18 @@ OVERWRITE_EXISTING="yes"
|
|||
|
||||
# When REMOVE_OBSOLETE is set to "yes" entries for kernels no longer available on the system will be removed
|
||||
REMOVE_OBSOLETE="yes"
|
||||
|
||||
# If PRESERVE_FOREIGN is set to "yes", do not delete entries starting with $ENTRY_ROOT
|
||||
#PRESERVE_FOREIGN="no"
|
||||
|
||||
# Setting NO_AUTOUPDATE to "yes" will stop the updates to systemd-boot when systemd is updated - not recommended unless you are seperately updating systemd-boot
|
||||
#NO_AUTOUPDATE="no"
|
||||
|
||||
# Setting NO_AUTOGEN to "yes" will stop the automatic creation of entries when kernels are installed or updated
|
||||
#NO_AUTOGEN="no"
|
||||
|
||||
# Use this to change the default initramfs prefix (e.g. when using booster)
|
||||
#INITRD_PREFIX="initramfs"
|
||||
|
||||
# Additional entities to initrd can be added here, such as microcode if your initramfs does not include it.
|
||||
#INITRD_ENTRIES=()
|
||||
EOF
|
||||
|
||||
log_info "systemd-boot configuration updated"
|
||||
}
|
||||
|
||||
main() {
|
||||
init_script
|
||||
|
||||
check_requirements
|
||||
configure_systemd_boot
|
||||
|
||||
finish_script 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
47
runs/docker
47
runs/docker
|
@ -1,24 +1,41 @@
|
|||
#!/usr/bin/env bash
|
||||
# NAME: Install and configure Docker on Arch Linux
|
||||
# NAME: Install and configure Docker
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "Installing Docker..."
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Install Docker packages
|
||||
sudo pacman -S --needed --noconfirm docker docker-compose docker-buildx
|
||||
install_docker() {
|
||||
log_info "Installing Docker packages"
|
||||
sudo pacman -S --needed --noconfirm docker docker-compose docker-buildx
|
||||
}
|
||||
|
||||
# Add current user to docker group
|
||||
sudo usermod -aG docker "$USER"
|
||||
configure_docker() {
|
||||
log_info "Adding current user to docker group"
|
||||
sudo usermod -aG docker "$USER"
|
||||
|
||||
# Enable and start Docker service
|
||||
sudo systemctl enable docker.service
|
||||
sudo systemctl start docker.service
|
||||
log_info "Enabling Docker services"
|
||||
sudo systemctl enable docker.service
|
||||
sudo systemctl start docker.service
|
||||
sudo systemctl enable containerd.service
|
||||
sudo systemctl start containerd.service
|
||||
}
|
||||
|
||||
# Enable containerd service (dependency)
|
||||
sudo systemctl enable containerd.service
|
||||
sudo systemctl start containerd.service
|
||||
main() {
|
||||
init_script
|
||||
|
||||
echo "✅ Docker installed successfully!"
|
||||
echo "⚠️ You need to log out and back in (or reboot) for group changes to take effect"
|
||||
echo "🐳 Test with: docker run hello-world"
|
||||
install_docker
|
||||
configure_docker
|
||||
|
||||
log_info "Docker installed successfully"
|
||||
log_warn "You need to log out and back in (or reboot) for group changes to take effect"
|
||||
log_info "Test with: docker run hello-world"
|
||||
|
||||
finish_script 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
229
runs/dotfiles
229
runs/dotfiles
|
@ -1,151 +1,118 @@
|
|||
#!/usr/bin/env bash
|
||||
# NAME: Setup dotfiles and Neovim configuration
|
||||
# NAME: Setup dotfiles and configuration
|
||||
# REQUIRES: interactive
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DOTFILES_REPO="https://git.mz.uy/marianozunino/dotfiles.git"
|
||||
NVIM_REPO="https://github.com/marianozunino/nvim.git"
|
||||
DOTFILES_DIR="$HOME/dotfiles"
|
||||
NVIM_CONFIG_DIR="$HOME/.config/nvim"
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "🏠 Setting up Forbi's development environment..."
|
||||
readonly DOTFILES_REPO="https://git.mz.uy/marianozunino/dotfiles.git"
|
||||
readonly DOTFILES_DIR="$HOME/dotfiles"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 📁 CLONE DOTFILES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "📦 Cloning dotfiles repository..."
|
||||
check_requirements() {
|
||||
local required_commands=(git git-crypt stow)
|
||||
|
||||
if [[ -d "$DOTFILES_DIR" ]]; then
|
||||
echo "→ Dotfiles directory already exists, updating..."
|
||||
cd "$DOTFILES_DIR"
|
||||
git pull origin main || git pull origin master
|
||||
else
|
||||
echo "→ Cloning dotfiles to $DOTFILES_DIR"
|
||||
git clone "$DOTFILES_REPO" "$DOTFILES_DIR"
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔐 HANDLE GIT-CRYPT
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "🔐 Checking for git-crypt..."
|
||||
|
||||
cd "$DOTFILES_DIR"
|
||||
|
||||
# Check if repo uses git-crypt
|
||||
if [[ -f ".git-crypt/.gitattributes" ]] || git-crypt status &>/dev/null; then
|
||||
echo "→ git-crypt repository detected"
|
||||
|
||||
# Check if already unlocked
|
||||
if git-crypt status | grep -q "unlocked"; then
|
||||
echo "→ Repository already unlocked"
|
||||
else
|
||||
echo "→ Repository is encrypted, attempting to unlock..."
|
||||
|
||||
# Check if YubiKey/GPG setup is available
|
||||
if command -v gpg &>/dev/null; then
|
||||
echo "→ GPG found, checking for available keys..."
|
||||
|
||||
# List secret keys to see if YubiKey is connected
|
||||
if gpg --list-secret-keys &>/dev/null; then
|
||||
echo "→ GPG keys detected, attempting git-crypt unlock..."
|
||||
|
||||
# Attempt to unlock with GPG (YubiKey)
|
||||
if git-crypt unlock 2>/dev/null; then
|
||||
echo "✅ Repository unlocked successfully with GPG/YubiKey!"
|
||||
else
|
||||
echo "❌ Failed to unlock with GPG"
|
||||
echo
|
||||
echo "🔑 Manual unlock required:"
|
||||
echo " 1. Make sure your YubiKey is connected"
|
||||
echo " 2. Test GPG: gpg --card-status"
|
||||
echo " 3. Try: cd $DOTFILES_DIR && git-crypt unlock"
|
||||
echo " 4. Or unlock with key file: git-crypt unlock /path/to/key"
|
||||
echo " 5. Then re-run: ./run forbi"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "❌ No GPG secret keys found"
|
||||
echo
|
||||
echo "🔑 YubiKey/GPG setup needed:"
|
||||
echo " 1. Connect your YubiKey"
|
||||
echo " 2. Import your GPG key: gpg --card-status"
|
||||
echo " 3. Set trust level: gpg --edit-key <your-key-id> trust"
|
||||
echo " 4. Then re-run: ./run forbi"
|
||||
echo
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "❌ GPG not available"
|
||||
echo
|
||||
echo "🔑 To unlock your dotfiles:"
|
||||
echo " 1. Install GPG and connect YubiKey, or"
|
||||
echo " 2. Use key file: cd $DOTFILES_DIR && git-crypt unlock /path/to/key"
|
||||
echo " 3. Then re-run: ./run forbi"
|
||||
echo
|
||||
for cmd in "${required_commands[@]}"; do
|
||||
if ! command_exists "$cmd"; then
|
||||
log_error "Required command not found: $cmd"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
clone_dotfiles() {
|
||||
log_info "Setting up dotfiles repository"
|
||||
|
||||
if [[ -d "$DOTFILES_DIR" ]]; then
|
||||
log_info "Dotfiles directory already exists, updating"
|
||||
cd "$DOTFILES_DIR"
|
||||
git pull origin main || git pull origin master
|
||||
else
|
||||
log_info "Cloning dotfiles to $DOTFILES_DIR"
|
||||
git clone "$DOTFILES_REPO" "$DOTFILES_DIR"
|
||||
fi
|
||||
else
|
||||
echo "→ No git-crypt encryption detected"
|
||||
fi
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# ⚙️ CLONE NEOVIM CONFIG
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "📝 Setting up Neovim configuration..."
|
||||
handle_git_crypt() {
|
||||
log_info "Checking git-crypt status"
|
||||
cd "$DOTFILES_DIR"
|
||||
|
||||
# Backup existing Neovim config if it exists
|
||||
if [[ -d "$NVIM_CONFIG_DIR" ]]; then
|
||||
BACKUP_DIR="$NVIM_CONFIG_DIR.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
echo "→ Backing up existing Neovim config to $BACKUP_DIR"
|
||||
mv "$NVIM_CONFIG_DIR" "$BACKUP_DIR"
|
||||
fi
|
||||
if git-crypt status | grep -q "unlocked"; then
|
||||
log_info "Repository already unlocked"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Clone Neovim configuration
|
||||
echo "→ Cloning Neovim config to $NVIM_CONFIG_DIR"
|
||||
git clone "$NVIM_REPO" "$NVIM_CONFIG_DIR"
|
||||
log_info "Repository is encrypted, attempting to unlock"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔧 CONFIGURE GIT HOOKS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "🎣 Setting up Git hooks for Neovim config..."
|
||||
if gpg --card-status &>/dev/null; then
|
||||
log_info "YubiKey detected, fetching public key"
|
||||
|
||||
cd "$NVIM_CONFIG_DIR"
|
||||
if [[ -d ".githooks" ]]; then
|
||||
git config core.hooksPath .githooks
|
||||
echo "→ Git hooks configured"
|
||||
else
|
||||
echo "→ No .githooks directory found, skipping"
|
||||
fi
|
||||
local key_id
|
||||
key_id=$(gpg --card-status 2>/dev/null | grep "General key info" -A 1 | tail -1 | awk '{print $1}' | sed 's/.*\///')
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 📂 CREATE NECESSARY DIRECTORIES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "📂 Creating necessary directories..."
|
||||
if [[ -n "$key_id" ]] && ! gpg --list-keys "$key_id" &>/dev/null; then
|
||||
gpg --card-edit --batch --command-fd 0 <<<"fetch" &>/dev/null ||
|
||||
gpg --keyserver hkps://keys.openpgp.org --recv-keys "$key_id" &>/dev/null || true
|
||||
fi
|
||||
else
|
||||
log_error "YubiKey not detected"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create .config directory if it doesn't exist
|
||||
mkdir -p "$HOME/.config"
|
||||
if git-crypt unlock 2>/dev/null; then
|
||||
log_info "Repository unlocked successfully"
|
||||
else
|
||||
log_error "Failed to unlock repository"
|
||||
log_info "Manual unlock required: cd $DOTFILES_DIR && git-crypt unlock"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Create common development directories
|
||||
mkdir -p "$HOME/Dev"
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
create_directories() {
|
||||
log_info "Creating necessary directories"
|
||||
mkdir -p "$HOME/.config" "$HOME/Dev" "$HOME/.local/bin"
|
||||
}
|
||||
|
||||
echo
|
||||
echo "# Install everything"
|
||||
echo "stow */"
|
||||
echo
|
||||
echo "# Or install individual modules"
|
||||
echo "stow zsh"
|
||||
echo "stow nvim"
|
||||
echo "stow sway"
|
||||
echo
|
||||
echo "Run these commands in: $DOTFILES_DIR"
|
||||
stow_packages() {
|
||||
cd "$DOTFILES_DIR"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 📋 SUMMARY & NEXT STEPS
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo
|
||||
echo "📁 Locations:"
|
||||
echo " • Dotfiles: $DOTFILES_DIR"
|
||||
echo " • Neovim config: $NVIM_CONFIG_DIR"
|
||||
log_info "Available stow packages:"
|
||||
for dir in */; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
log_info " ${dir%/}"
|
||||
fi
|
||||
done
|
||||
|
||||
if confirm "Stow all packages?" "y"; then
|
||||
log_info "Stowing all packages"
|
||||
if stow */; then
|
||||
log_info "All packages stowed successfully"
|
||||
else
|
||||
log_error "Some packages failed to stow. Check for conflicts"
|
||||
fi
|
||||
else
|
||||
log_info "Skipping automatic stow. Run manually:"
|
||||
log_info " cd $DOTFILES_DIR"
|
||||
log_info " stow <package_name>"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
init_script
|
||||
|
||||
check_requirements
|
||||
clone_dotfiles
|
||||
handle_git_crypt
|
||||
create_directories
|
||||
stow_packages
|
||||
|
||||
log_info "Dotfiles location: $DOTFILES_DIR"
|
||||
|
||||
finish_script 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
211
runs/limine
211
runs/limine
|
@ -1,211 +0,0 @@
|
|||
#!/bin/bash
|
||||
# NAME: Script to transition from systemd-boot to Limine bootloader
|
||||
# REQUIRES: sudo
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "do you confirm this transition?"
|
||||
|
||||
read -r -p "Are you sure? [y/N] " response
|
||||
|
||||
if [[ "$response" != "y" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
print_status() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
|
||||
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
|
||||
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
print_error "This script must be run as root (use sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v pacman &>/dev/null; then
|
||||
print_error "This script is designed for Arch Linux / CachyOS systems"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_status "Starting transition from systemd-boot to Limine..."
|
||||
|
||||
ESP_PATH=""
|
||||
if command -v bootctl &>/dev/null; then
|
||||
ESP_PATH=$(bootctl --print-esp-path 2>/dev/null || echo "")
|
||||
fi
|
||||
|
||||
if [[ -z "$ESP_PATH" ]]; then
|
||||
if [[ -d "/boot/EFI" ]]; then
|
||||
ESP_PATH="/boot"
|
||||
elif [[ -d "/efi/EFI" ]]; then
|
||||
ESP_PATH="/efi"
|
||||
else
|
||||
print_error "Could not detect ESP path"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
print_success "ESP detected at: $ESP_PATH"
|
||||
|
||||
BACKUP_DIR="/root/bootloader-backup-$(date +%Y%m%d-%H%M%S)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
[[ -d "$ESP_PATH/loader" ]] && cp -r "$ESP_PATH/loader" "$BACKUP_DIR/" 2>/dev/null || true
|
||||
[[ -d "$ESP_PATH/EFI/systemd" ]] && cp -r "$ESP_PATH/EFI/systemd" "$BACKUP_DIR/" 2>/dev/null || true
|
||||
efibootmgr -v >"$BACKUP_DIR/efibootmgr-backup.txt" 2>/dev/null || true
|
||||
|
||||
print_success "Backup created at: $BACKUP_DIR"
|
||||
|
||||
CURRENT_CMDLINE=""
|
||||
if [[ -f "/etc/kernel/cmdline" ]]; then
|
||||
CURRENT_CMDLINE=$(cat /etc/kernel/cmdline)
|
||||
print_status "Found existing /etc/kernel/cmdline: $CURRENT_CMDLINE"
|
||||
else
|
||||
CURRENT_CMDLINE=$(cat /proc/cmdline | sed 's/BOOT_IMAGE=[^ ]* //')
|
||||
print_status "Using current /proc/cmdline: $CURRENT_CMDLINE"
|
||||
fi
|
||||
|
||||
print_status "Installing Limine and related packages..."
|
||||
pacman -S --needed --noconfirm limine limine-snapper-sync limine-mkinitcpio-hook
|
||||
print_success "Limine packages installed"
|
||||
|
||||
print_status "Installing Limine bootloader to ESP..."
|
||||
mkdir -p "$ESP_PATH/EFI/Limine"
|
||||
|
||||
if [[ -f "/usr/share/limine/limine_x64.efi" ]]; then
|
||||
cp /usr/share/limine/limine_x64.efi "$ESP_PATH/EFI/Limine/"
|
||||
elif [[ -f "/usr/share/limine/BOOTX64.EFI" ]]; then
|
||||
cp /usr/share/limine/BOOTX64.EFI "$ESP_PATH/EFI/Limine/limine_x64.efi"
|
||||
else
|
||||
print_error "Could not find Limine EFI files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_success "Limine files installed to ESP"
|
||||
|
||||
print_status "Creating UEFI boot entry for Limine..."
|
||||
ESP_DEVICE=$(df "$ESP_PATH" | tail -1 | awk '{print $1}')
|
||||
ESP_DISK=$(echo "$ESP_DEVICE" | sed 's/[0-9]*$//')
|
||||
ESP_PART_NUM=$(echo "$ESP_DEVICE" | sed 's/.*[^0-9]//')
|
||||
|
||||
efibootmgr -c -d "$ESP_DISK" -p "$ESP_PART_NUM" -L "Limine" -l "\\EFI\\Limine\\limine_x64.efi" || {
|
||||
print_warning "Could not create UEFI boot entry automatically"
|
||||
}
|
||||
|
||||
print_success "Limine UEFI boot entry created"
|
||||
|
||||
print_status "Configuring kernel command line..."
|
||||
echo "$CURRENT_CMDLINE" >/etc/kernel/cmdline
|
||||
print_success "Kernel command line configured: $CURRENT_CMDLINE"
|
||||
|
||||
print_status "Configuring Limine..."
|
||||
[[ ! -f "/etc/default/limine" ]] && cat >/etc/default/limine <<EOF
|
||||
SPACE_NUMBER=2
|
||||
ENABLE_VERIFICATION=yes
|
||||
BACKUP_THRESHOLD=8
|
||||
BOOT_ORDER="*, *fallback, Snapshots"
|
||||
ENABLE_SORT=no
|
||||
ENABLE_LIMINE_FALLBACK=no
|
||||
FIND_BOOTLOADERS=yes
|
||||
ROOT_SNAPSHOTS_PATH="/@snapshots"
|
||||
EOF
|
||||
|
||||
print_status "Creating custom Limine configuration..."
|
||||
cat >"$ESP_PATH/limine.conf" <<'EOF'
|
||||
### Read more at config document: https://github.com/limine-bootloader/limine/blob/trunk/CONFIG.md
|
||||
timeout: 1
|
||||
### Note: For "default_entry" to select a sub-entry within an OS menu, modify "/OS name" to "/+OS name" to keep its submenus visible.
|
||||
default_entry: 2
|
||||
#interface_branding_color: 3
|
||||
interface_branding:
|
||||
hash_mismatch_panic: no
|
||||
term_palette: 1e1e2e;f38ba8;a6e3a1;f9e2af;89b4fa;f5c2e7;94e2d5;cdd6f4
|
||||
term_palette_bright: 585b70;f38ba8;a6e3a1;f9e2af;89b4fa;f5c2e7;94e2d5;cdd6f4
|
||||
term_background: 1e1e2e
|
||||
term_foreground: cdd6f4
|
||||
term_background_bright: 585b70
|
||||
term_foreground_bright: cdd6f4
|
||||
|
||||
EOF
|
||||
|
||||
print_status "Generating Limine boot entries..."
|
||||
limine-update
|
||||
print_success "Limine configuration created"
|
||||
|
||||
print_status "Setting Limine as default boot option..."
|
||||
LIMINE_ENTRY=$(efibootmgr | grep "Limine" | head -1 | cut -c5-8)
|
||||
|
||||
if [[ -n "$LIMINE_ENTRY" ]]; then
|
||||
CURRENT_ORDER=$(efibootmgr | grep "BootOrder" | cut -d' ' -f2)
|
||||
NEW_ORDER=$(echo "$CURRENT_ORDER" | sed "s/$LIMINE_ENTRY,//g" | sed "s/,$LIMINE_ENTRY//g" | sed "s/^$LIMINE_ENTRY$//g")
|
||||
|
||||
if [[ -n "$NEW_ORDER" ]]; then
|
||||
efibootmgr -o "$LIMINE_ENTRY,$NEW_ORDER"
|
||||
else
|
||||
efibootmgr -o "$LIMINE_ENTRY"
|
||||
fi
|
||||
|
||||
print_success "Limine set as default boot option"
|
||||
else
|
||||
print_warning "Could not find Limine boot entry to set as default"
|
||||
fi
|
||||
|
||||
print_status "Removing systemd-boot components..."
|
||||
|
||||
# Remove systemd-boot UEFI entries
|
||||
SYSTEMD_ENTRIES=$(efibootmgr | grep -i "Linux Boot Manager\|systemd" | cut -c5-8 || true)
|
||||
if [[ -n "$SYSTEMD_ENTRIES" ]]; then
|
||||
for entry in $SYSTEMD_ENTRIES; do
|
||||
print_status "Removing UEFI boot entry: Boot$entry"
|
||||
efibootmgr -b "$entry" -B || print_warning "Failed to remove boot entry $entry"
|
||||
done
|
||||
fi
|
||||
|
||||
# Remove systemd-boot files from ESP
|
||||
if [[ -d "$ESP_PATH/EFI/systemd" ]]; then
|
||||
print_status "Removing systemd-boot EFI files..."
|
||||
rm -rf "$ESP_PATH/EFI/systemd"
|
||||
print_success "systemd-boot EFI files removed"
|
||||
fi
|
||||
|
||||
if [[ -d "$ESP_PATH/loader" ]]; then
|
||||
print_status "Removing systemd-boot configuration..."
|
||||
rm -rf "$ESP_PATH/loader"
|
||||
print_success "systemd-boot configuration removed"
|
||||
fi
|
||||
|
||||
if [[ -f "$ESP_PATH/limine.conf" ]]; then
|
||||
print_success "Limine configuration file exists"
|
||||
else
|
||||
print_error "Limine configuration file missing!"
|
||||
fi
|
||||
|
||||
if [[ -f "$ESP_PATH/EFI/Limine/limine_x64.efi" ]]; then
|
||||
print_success "Limine EFI bootloader exists"
|
||||
else
|
||||
print_error "Limine EFI bootloader missing!"
|
||||
fi
|
||||
|
||||
sudo pacman -S snap-pac
|
||||
sudo systemctl enable --now limine-snapper-sync.service
|
||||
|
||||
echo
|
||||
print_success "TRANSITION COMPLETED SUCCESSFULLY!"
|
||||
echo
|
||||
print_status "Summary:"
|
||||
echo " • Limine bootloader installed to: $ESP_PATH/EFI/Limine/"
|
||||
echo " • Configuration file: $ESP_PATH/limine.conf"
|
||||
echo " • Kernel command line: /etc/kernel/cmdline"
|
||||
echo " • Backup created at: $BACKUP_DIR"
|
||||
echo " • Boot order updated"
|
||||
echo " • systemd-boot completely removed"
|
||||
echo
|
||||
print_warning "IMPORTANT: Reboot to test the new Limine setup!"
|
||||
print_warning "systemd-boot has been completely removed - ensure Limine works before removing backup!"
|
||||
print_success "Script completed. Please reboot when ready."
|
279
runs/limine_hibernate
Executable file
279
runs/limine_hibernate
Executable file
|
@ -0,0 +1,279 @@
|
|||
#!/usr/bin/env bash
|
||||
# NAME: Configure hibernation for CachyOS with Limine bootloader
|
||||
# REQUIRES: sudo interactive
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
readonly LIMINE_CONFIG="/etc/default/limine"
|
||||
readonly MKINITCPIO_CONFIG="/etc/mkinitcpio.conf"
|
||||
|
||||
check_requirements() {
|
||||
local swap_uuid
|
||||
swap_uuid=$(blkid -t TYPE=swap -o value -s UUID | head -n1)
|
||||
|
||||
if [[ -z "$swap_uuid" ]]; then
|
||||
log_error "No swap partition found"
|
||||
log_info "Please create a swap partition or swapfile before running this script"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Found swap partition UUID: $swap_uuid"
|
||||
readonly SWAP_UUID="$swap_uuid"
|
||||
}
|
||||
|
||||
escape_for_sed() {
|
||||
printf '%s\n' "$1" | sed 's/[[\.*^$()+?{|]/\\&/g'
|
||||
}
|
||||
|
||||
show_diff_and_confirm() {
|
||||
local file="$1"
|
||||
local description="$2"
|
||||
local temp_file="$3"
|
||||
|
||||
log_info "Proposed changes for $description"
|
||||
log_info "File: $file"
|
||||
echo
|
||||
|
||||
if command_exists colordiff; then
|
||||
colordiff -u "$file" "$temp_file" || true
|
||||
else
|
||||
diff -u "$file" "$temp_file" || true
|
||||
fi
|
||||
|
||||
echo
|
||||
confirm "Apply these changes?"
|
||||
}
|
||||
|
||||
update_limine_config() {
|
||||
log_info "Updating Limine configuration"
|
||||
|
||||
backup_file "$LIMINE_CONFIG"
|
||||
|
||||
local current_cmdline new_cmdline changes_made=false
|
||||
current_cmdline=$(grep 'KERNEL_CMDLINE\[default\]' "$LIMINE_CONFIG" | cut -d'"' -f2)
|
||||
log_info "Current kernel cmdline: $current_cmdline"
|
||||
|
||||
new_cmdline="$current_cmdline"
|
||||
|
||||
if [[ ! "$new_cmdline" =~ resume= ]]; then
|
||||
new_cmdline="$new_cmdline resume=UUID=$SWAP_UUID"
|
||||
log_info "Adding resume parameter"
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
if [[ ! "$new_cmdline" =~ ipv6.disable= ]]; then
|
||||
new_cmdline="$new_cmdline ipv6.disable=1"
|
||||
log_info "Adding ipv6.disable parameter"
|
||||
changes_made=true
|
||||
fi
|
||||
|
||||
new_cmdline=$(echo "$new_cmdline" | sed 's/ */ /g' | sed 's/^ *//' | sed 's/ *$//')
|
||||
|
||||
if [[ "$changes_made" == "true" ]]; then
|
||||
log_info "New kernel cmdline: $new_cmdline"
|
||||
|
||||
local new_cmdline_escaped temp_file
|
||||
new_cmdline_escaped=$(escape_for_sed "$new_cmdline")
|
||||
temp_file=$(mktemp)
|
||||
|
||||
sed "s|KERNEL_CMDLINE\[default\]=\".*\"|KERNEL_CMDLINE[default]=\"$new_cmdline_escaped\"|" "$LIMINE_CONFIG" >"$temp_file"
|
||||
|
||||
if show_diff_and_confirm "$LIMINE_CONFIG" "LIMINE CONFIGURATION" "$temp_file"; then
|
||||
cp "$temp_file" "$LIMINE_CONFIG"
|
||||
log_info "Limine configuration updated successfully"
|
||||
rm "$temp_file"
|
||||
return 0
|
||||
else
|
||||
log_info "Skipping Limine configuration update"
|
||||
log_info "You can manually add: resume=UUID=$SWAP_UUID to your kernel cmdline"
|
||||
rm "$temp_file"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_info "Limine configuration already contains required parameters"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
update_mkinitcpio_config() {
|
||||
log_info "Updating mkinitcpio configuration"
|
||||
|
||||
backup_file "$MKINITCPIO_CONFIG"
|
||||
|
||||
if grep -q '^HOOKS=.*resume' "$MKINITCPIO_CONFIG"; then
|
||||
log_info "Resume hook already present in mkinitcpio.conf"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Adding resume hook to mkinitcpio.conf"
|
||||
|
||||
local current_hooks new_hooks temp_file
|
||||
current_hooks=$(grep '^HOOKS=' "$MKINITCPIO_CONFIG")
|
||||
log_info "Current HOOKS: $current_hooks"
|
||||
|
||||
new_hooks=$(echo "$current_hooks" | sed 's/filesystems/filesystems resume/' | sed 's/resume resume/resume/')
|
||||
|
||||
if [[ ! "$new_hooks" =~ resume ]]; then
|
||||
new_hooks=$(echo "$current_hooks" | sed 's/)/ resume)/')
|
||||
fi
|
||||
|
||||
log_info "New HOOKS: $new_hooks"
|
||||
|
||||
local new_hooks_escaped
|
||||
new_hooks_escaped=$(escape_for_sed "$new_hooks")
|
||||
temp_file=$(mktemp)
|
||||
|
||||
sed "s|^HOOKS=.*|$new_hooks_escaped|" "$MKINITCPIO_CONFIG" >"$temp_file"
|
||||
|
||||
if show_diff_and_confirm "$MKINITCPIO_CONFIG" "MKINITCPIO CONFIGURATION" "$temp_file"; then
|
||||
cp "$temp_file" "$MKINITCPIO_CONFIG"
|
||||
log_info "mkinitcpio.conf updated successfully"
|
||||
rm "$temp_file"
|
||||
return 0
|
||||
else
|
||||
log_info "Skipping mkinitcpio.conf update"
|
||||
log_info "You can manually add 'resume' to your HOOKS array"
|
||||
rm "$temp_file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
apply_system_changes() {
|
||||
local limine_updated="$1"
|
||||
local mkinitcpio_updated="$2"
|
||||
local operations_needed=()
|
||||
|
||||
log_info "System updates required"
|
||||
|
||||
if [[ "$mkinitcpio_updated" == "true" ]]; then
|
||||
operations_needed+=("Regenerate initramfs (mkinitcpio -P)")
|
||||
fi
|
||||
|
||||
if [[ "$limine_updated" == "true" ]]; then
|
||||
operations_needed+=("Update Limine bootloader (limine-update)")
|
||||
fi
|
||||
|
||||
if [[ ${#operations_needed[@]} -eq 0 ]]; then
|
||||
log_info "No system updates needed - configuration is already up to date"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "The following operations need to be performed:"
|
||||
for i in "${!operations_needed[@]}"; do
|
||||
log_info " $((i + 1)). ${operations_needed[$i]}"
|
||||
done
|
||||
|
||||
if ! confirm "Apply all pending system changes?" "y"; then
|
||||
log_warn "Skipping system updates"
|
||||
log_warn "Configuration files have been updated but system changes were not applied"
|
||||
log_info "You will need to manually run:"
|
||||
|
||||
if [[ "$mkinitcpio_updated" == "true" ]]; then
|
||||
log_info " mkinitcpio -P"
|
||||
fi
|
||||
|
||||
if [[ "$limine_updated" == "true" ]]; then
|
||||
log_info " limine-update"
|
||||
fi
|
||||
|
||||
log_warn "Hibernation will not work until these commands are executed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Applying system changes"
|
||||
|
||||
if [[ "$mkinitcpio_updated" == "true" ]]; then
|
||||
log_info "Regenerating initramfs"
|
||||
if ! mkinitcpio -P; then
|
||||
log_error "Failed to regenerate initramfs"
|
||||
log_info "Please check the configuration and run 'mkinitcpio -P' manually"
|
||||
exit 1
|
||||
fi
|
||||
log_info "Initramfs regenerated successfully"
|
||||
fi
|
||||
|
||||
if [[ "$limine_updated" == "true" ]]; then
|
||||
log_info "Updating Limine configuration"
|
||||
if ! limine-update; then
|
||||
log_error "Failed to update Limine bootloader"
|
||||
log_info "Please run 'limine-update' manually"
|
||||
exit 1
|
||||
fi
|
||||
log_info "Limine bootloader updated successfully"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
show_completion_summary() {
|
||||
local limine_updated="$1"
|
||||
local mkinitcpio_updated="$2"
|
||||
|
||||
log_info "Hibernation configuration completed successfully"
|
||||
echo
|
||||
log_info "Configuration details:"
|
||||
log_info " - Swap UUID: $SWAP_UUID"
|
||||
|
||||
if [[ "$limine_updated" == "true" ]]; then
|
||||
log_info " - Resume parameter added to kernel cmdline"
|
||||
log_info " - IPv6 disabled (optional optimization)"
|
||||
else
|
||||
log_info " - Kernel cmdline already configured"
|
||||
fi
|
||||
|
||||
if [[ "$mkinitcpio_updated" == "true" ]]; then
|
||||
log_info " - Resume hook added to initramfs"
|
||||
else
|
||||
log_info " - Resume hook already present in initramfs"
|
||||
fi
|
||||
|
||||
echo
|
||||
log_info "Backups created:"
|
||||
log_info " - $LIMINE_CONFIG.backup.*"
|
||||
log_info " - $MKINITCPIO_CONFIG.backup.*"
|
||||
echo
|
||||
log_info "Next steps:"
|
||||
log_info " 1. Reboot your system"
|
||||
log_info " 2. Test hibernation with: systemctl hibernate"
|
||||
log_info " 3. Wake up and verify everything works correctly"
|
||||
echo
|
||||
log_info "If you encounter issues, restore backups with:"
|
||||
log_info " cp $LIMINE_CONFIG.backup.* $LIMINE_CONFIG"
|
||||
log_info " cp $MKINITCPIO_CONFIG.backup.* $MKINITCPIO_CONFIG"
|
||||
log_info " mkinitcpio -P && limine-update"
|
||||
}
|
||||
|
||||
main() {
|
||||
init_script
|
||||
|
||||
check_requirements
|
||||
|
||||
local limine_updated mkinitcpio_updated
|
||||
|
||||
if update_limine_config; then
|
||||
limine_updated="true"
|
||||
else
|
||||
limine_updated="false"
|
||||
fi
|
||||
|
||||
if update_mkinitcpio_config; then
|
||||
mkinitcpio_updated="true"
|
||||
else
|
||||
mkinitcpio_updated="false"
|
||||
fi
|
||||
|
||||
if apply_system_changes "$limine_updated" "$mkinitcpio_updated"; then
|
||||
show_completion_summary "$limine_updated" "$mkinitcpio_updated"
|
||||
finish_script 0
|
||||
else
|
||||
finish_script 1
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
55
runs/nvim
Executable file
55
runs/nvim
Executable file
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env bash
|
||||
# NAME: Setup Neovim configuration
|
||||
# REQUIRES: interactive
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
readonly NVIM_REPO="https://github.com/marianozunino/nvim.git"
|
||||
readonly NVIM_CONFIG_DIR="$HOME/.config/nvim"
|
||||
|
||||
check_requirements() {
|
||||
if ! command_exists git; then
|
||||
log_error "git is required but not installed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
setup_neovim_config() {
|
||||
log_info "Setting up Neovim configuration"
|
||||
|
||||
if [[ -d "$NVIM_CONFIG_DIR" ]]; then
|
||||
local backup_dir="$NVIM_CONFIG_DIR.backup.$(date +%Y%m%d_%H%M%S)"
|
||||
log_info "Backing up existing Neovim config to $backup_dir"
|
||||
mv "$NVIM_CONFIG_DIR" "$backup_dir"
|
||||
fi
|
||||
|
||||
log_info "Cloning Neovim config to $NVIM_CONFIG_DIR"
|
||||
git clone "$NVIM_REPO" "$NVIM_CONFIG_DIR"
|
||||
|
||||
cd "$NVIM_CONFIG_DIR"
|
||||
|
||||
if [[ -d ".githooks" ]]; then
|
||||
git config core.hooksPath .githooks
|
||||
chmod +x .githooks/* 2>/dev/null || true
|
||||
log_info "Git hooks configured"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
init_script
|
||||
|
||||
check_requirements
|
||||
setup_neovim_config
|
||||
|
||||
log_info "Neovim configuration: $NVIM_CONFIG_DIR"
|
||||
|
||||
finish_script 0
|
||||
}
|
||||
|
||||
main "$@"
|
69
runs/paru
69
runs/paru
|
@ -1,26 +1,59 @@
|
|||
#!/usr/bin/env bash
|
||||
# NAME: Installs paru
|
||||
# NAME: Install paru AUR helper
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if command -v paru &>/dev/null; then
|
||||
echo "paru ya está instalado."
|
||||
exit 0
|
||||
fi
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Instalando dependencias necesarias..."
|
||||
sudo pacman -S --needed --noconfirm base-devel git
|
||||
check_requirements() {
|
||||
local required_commands=(git makepkg)
|
||||
|
||||
tmpdir=$(mktemp -d)
|
||||
echo "Temp dir: $tmpdir"
|
||||
cd "$tmpdir"
|
||||
for cmd in "${required_commands[@]}"; do
|
||||
if ! command_exists "$cmd"; then
|
||||
log_error "Required command not found: $cmd"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
echo "Cloning paru..."
|
||||
git clone https://aur.archlinux.org/paru.git
|
||||
cd paru
|
||||
install_paru() {
|
||||
if command_exists paru; then
|
||||
log_info "paru is already installed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "Compiling paru..."
|
||||
makepkg -si --noconfirm
|
||||
log_info "Installing build dependencies"
|
||||
sudo pacman -S --needed --noconfirm base-devel git
|
||||
|
||||
echo "Cleaning up..."
|
||||
cd ..
|
||||
rm -rf "$tmpdir"
|
||||
local tmpdir
|
||||
tmpdir=$(mktemp -d)
|
||||
log_info "Using temporary directory: $tmpdir"
|
||||
|
||||
cd "$tmpdir"
|
||||
|
||||
log_info "Cloning paru repository"
|
||||
git clone https://aur.archlinux.org/paru.git
|
||||
cd paru
|
||||
|
||||
log_info "Building and installing paru"
|
||||
makepkg -si --noconfirm
|
||||
|
||||
log_info "Cleaning up temporary files"
|
||||
cd /
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
|
||||
main() {
|
||||
init_script
|
||||
|
||||
check_requirements
|
||||
install_paru
|
||||
|
||||
finish_script 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
|
152
runs/services
152
runs/services
|
@ -3,103 +3,99 @@
|
|||
|
||||
set -euo pipefail
|
||||
|
||||
echo "Enabling and configuring system services..."
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🌐 NETWORKING SERVICES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Enabling networking services..."
|
||||
enable_networking_services() {
|
||||
log_info "Enabling networking services"
|
||||
|
||||
# NetworkManager (main network management)
|
||||
sudo systemctl enable --now NetworkManager.service
|
||||
sudo systemctl enable --now NetworkManager.service
|
||||
sudo systemctl enable --now bluetooth.service
|
||||
sudo systemctl enable --now sshd.service
|
||||
}
|
||||
|
||||
# Bluetooth
|
||||
sudo systemctl enable --now bluetooth.service
|
||||
enable_audio_services() {
|
||||
log_info "Enabling audio services"
|
||||
|
||||
# SSH daemon
|
||||
sudo systemctl enable --now sshd.service
|
||||
systemctl --user enable --now pipewire.service
|
||||
systemctl --user enable --now pipewire-pulse.service
|
||||
systemctl --user enable --now wireplumber.service
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔊 AUDIO SERVICES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Enabling audio services..."
|
||||
enable_printing_services() {
|
||||
log_info "Enabling printing services"
|
||||
|
||||
# PipeWire audio (replaces PulseAudio)
|
||||
systemctl --user enable --now pipewire.service
|
||||
systemctl --user enable --now pipewire-pulse.service
|
||||
systemctl --user enable --now wireplumber.service
|
||||
sudo systemctl enable --now cups.service
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🖨️ PRINTING SERVICES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Enabling printing services..."
|
||||
configure_time_locale() {
|
||||
log_info "Configuring time and locale services"
|
||||
|
||||
# CUPS printing system
|
||||
sudo systemctl enable --now cups.service
|
||||
if ! grep -q "en_US.UTF-8 UTF-8" /etc/locale.gen; then
|
||||
echo "en_US.UTF-8 UTF-8" | sudo tee -a /etc/locale.gen
|
||||
sudo locale-gen
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# ⏰ TIME & SCHEDULING SERVICES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Configuring time and scheduling services..."
|
||||
echo "LANG=en_US.UTF-8" | sudo tee /etc/locale.conf
|
||||
log_info "System locale set to en_US.UTF-8"
|
||||
|
||||
echo "en_US.UTF-8 UTF-8" | sudo tee -a /etc/locale.gen
|
||||
sudo locale-gen
|
||||
sudo timedatectl set-timezone America/Montevideo
|
||||
sudo timedatectl set-ntp true
|
||||
sudo systemctl enable --now systemd-timesyncd.service
|
||||
sudo systemctl enable --now cronie.service
|
||||
}
|
||||
|
||||
# Set system locale
|
||||
echo "LANG=en_US.UTF-8" | sudo tee /etc/locale.conf
|
||||
echo "→ System locale set to en_US.UTF-8"
|
||||
enable_security_services() {
|
||||
log_info "Enabling security services"
|
||||
|
||||
sudo timedatectl set-timezone America/Montevideo
|
||||
sudo systemctl enable --now ufw.service
|
||||
sudo ufw --force enable
|
||||
sudo ufw default deny incoming
|
||||
sudo ufw default allow outgoing
|
||||
}
|
||||
|
||||
# Enable NTP time synchronization
|
||||
sudo timedatectl set-ntp true
|
||||
sudo systemctl enable --now systemd-timesyncd.service
|
||||
enable_backup_services() {
|
||||
log_info "Enabling backup services"
|
||||
|
||||
# Cron daemon for scheduled tasks
|
||||
sudo systemctl enable --now cronie.service
|
||||
if findmnt / -t btrfs &>/dev/null; then
|
||||
sudo systemctl enable --now snapper-timeline.timer
|
||||
sudo systemctl enable --now snapper-cleanup.timer
|
||||
log_info "Snapper enabled (BTRFS detected)"
|
||||
else
|
||||
log_info "Skipping Snapper (no BTRFS detected)"
|
||||
fi
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔒 SECURITY & FIREWALL SERVICES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Enabling security services..."
|
||||
enable_power_management() {
|
||||
log_info "Enabling power management"
|
||||
|
||||
# UFW firewall
|
||||
sudo systemctl enable --now ufw.service
|
||||
sudo systemctl enable --now power-profiles-daemon.service
|
||||
}
|
||||
|
||||
# Enable basic firewall rules
|
||||
sudo ufw --force enable
|
||||
sudo ufw default deny incoming
|
||||
sudo ufw default allow outgoing
|
||||
enable_system_optimization() {
|
||||
log_info "Enabling system optimization"
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 💾 BACKUP & SYNC SERVICES
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Enabling backup services..."
|
||||
sudo systemctl enable --now haveged.service
|
||||
sudo systemctl enable --now plocate-updatedb.timer
|
||||
sudo systemctl enable --now syncthing@forbi.service
|
||||
}
|
||||
|
||||
# Snapper for BTRFS snapshots (if using BTRFS)
|
||||
if findmnt / -t btrfs &>/dev/null; then
|
||||
sudo systemctl enable --now snapper-timeline.timer
|
||||
sudo systemctl enable --now snapper-cleanup.timer
|
||||
echo "→ Snapper enabled (BTRFS detected)"
|
||||
else
|
||||
echo "→ Skipping Snapper (no BTRFS detected)"
|
||||
fi
|
||||
main() {
|
||||
init_script
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# ⚡ POWER MANAGEMENT
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Enabling power management..."
|
||||
enable_networking_services
|
||||
enable_audio_services
|
||||
enable_printing_services
|
||||
configure_time_locale
|
||||
enable_security_services
|
||||
enable_backup_services
|
||||
enable_power_management
|
||||
enable_system_optimization
|
||||
|
||||
# Power profiles daemon
|
||||
sudo systemctl enable --now power-profiles-daemon.service
|
||||
finish_script 0
|
||||
}
|
||||
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
# 🔧 SYSTEM OPTIMIZATION
|
||||
# ═══════════════════════════════════════════════════════════
|
||||
echo "Enabling system optimization..."
|
||||
|
||||
# Haveged entropy daemon
|
||||
sudo systemctl enable --now haveged.service
|
||||
|
||||
# Locate database updates
|
||||
sudo systemctl enable --now plocate-updatedb.timer
|
||||
main "$@"
|
||||
|
|
42
runs/sudo
Executable file
42
runs/sudo
Executable file
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env bash
|
||||
# NAME: Configure passwordless sudo for wheel group
|
||||
# REQUIRES: sudo
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source common functions
|
||||
source "$(dirname "$0")/../common.sh" || {
|
||||
echo "[ERROR] Could not source common.sh" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
check_requirements() {
|
||||
if ! is_root; then
|
||||
log_error "This script requires root privileges"
|
||||
log_info "Run with: sudo $0"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
configure_sudo() {
|
||||
local sudoers_file="/etc/sudoers.d/wheel"
|
||||
local config_line="%wheel ALL=(ALL:ALL) NOPASSWD: ALL"
|
||||
|
||||
log_sudo "Configuring wheel group for passwordless sudo"
|
||||
|
||||
echo "$config_line" >"$sudoers_file"
|
||||
chmod 440 "$sudoers_file"
|
||||
|
||||
log_info "Wheel group configured for passwordless sudo"
|
||||
log_info "Users in wheel group can now use sudo without password"
|
||||
}
|
||||
|
||||
main() {
|
||||
init_script
|
||||
|
||||
check_requirements
|
||||
configure_sudo
|
||||
|
||||
finish_script 0
|
||||
}
|
||||
main "$@"
|
Loading…
Add table
Add a link
Reference in a new issue