From d6e16d115578512418a6b6e3090ab4f8857b75f9 Mon Sep 17 00:00:00 2001 From: Christoffer Martinsson Date: Thu, 11 Sep 2025 11:16:27 +0200 Subject: [PATCH] New update script --- bashrc_arch | 10 +- config/hypr/hyprland.conf | 4 - update/arch/arch.sh | 46 ++++ update/arch/desktop.sh | 287 ++++++++++++++++++++++ update/arch/development.sh | 283 +++++++++++++++++++++ update/arch/gaming.sh | 147 +++++++++++ update/arch/lab.sh | 41 ++++ update/arch/music.sh | 25 ++ update/arch/system.sh | 301 +++++++++++++++++++++++ update/arch/terminal.sh | 245 +++++++++++++++++++ update/config/arch-roles.conf | 55 +++++ update/config/ubuntu-roles.conf | 44 ++++ update/lib/core.sh | 419 ++++++++++++++++++++++++++++++++ update/lib/detect.sh | 266 ++++++++++++++++++++ update/lib/packages.sh | 406 +++++++++++++++++++++++++++++++ update/lib/roles.sh | 332 +++++++++++++++++++++++++ update/ubuntu/development.sh | 146 +++++++++++ update/ubuntu/system.sh | 75 ++++++ update/ubuntu/ubuntu.sh | 29 +++ update/update.sh | 193 +++++++++++++++ 20 files changed, 3347 insertions(+), 7 deletions(-) create mode 100644 update/arch/arch.sh create mode 100644 update/arch/desktop.sh create mode 100644 update/arch/development.sh create mode 100644 update/arch/gaming.sh create mode 100644 update/arch/lab.sh create mode 100644 update/arch/music.sh create mode 100644 update/arch/system.sh create mode 100644 update/arch/terminal.sh create mode 100644 update/config/arch-roles.conf create mode 100644 update/config/ubuntu-roles.conf create mode 100644 update/lib/core.sh create mode 100644 update/lib/detect.sh create mode 100644 update/lib/packages.sh create mode 100644 update/lib/roles.sh create mode 100644 update/ubuntu/development.sh create mode 100644 update/ubuntu/system.sh create mode 100644 update/ubuntu/ubuntu.sh create mode 100755 update/update.sh diff --git a/bashrc_arch b/bashrc_arch index fa08077..7e003a7 100644 --- a/bashrc_arch +++ b/bashrc_arch @@ -6,14 +6,18 @@ esac # don't put duplicate lines or lines starting with space in the history. # See bash(1) for more options -HISTCONTROL=ignoreboth +HISTCONTROL=ignoreboth:erasedups # append to the history file, don't overwrite it shopt -s histappend +# Save multi-line commands as single entry +shopt -s cmdhist +# Save history immediately after each command +PROMPT_COMMAND="history -a; $PROMPT_COMMAND" # for setting history length see HISTSIZE and HISTFILESIZE in bash(1) -HISTSIZE=1000 -HISTFILESIZE=2000 +HISTSIZE=10000 +HISTFILESIZE=20000 # check the window size after each command and, if necessary, # update the values of LINES and COLUMNS. diff --git a/config/hypr/hyprland.conf b/config/hypr/hyprland.conf index 7628e84..40f743e 100644 --- a/config/hypr/hyprland.conf +++ b/config/hypr/hyprland.conf @@ -135,10 +135,6 @@ cursor { hide_on_key_press = true } -gestures { - workspace_swipe = false -} - device { name = elecom-trackball-mouse-deft-pro-trackball-1 sensitivity = 0.7 diff --git a/update/arch/arch.sh b/update/arch/arch.sh new file mode 100644 index 0000000..49bfe19 --- /dev/null +++ b/update/arch/arch.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# Arch Linux Master Module +# Loads all Arch-specific modules and orchestrates installation + +# Source all Arch modules +source "$SCRIPT_DIR/arch/system.sh" +source "$SCRIPT_DIR/arch/development.sh" +source "$SCRIPT_DIR/arch/terminal.sh" +source "$SCRIPT_DIR/arch/desktop.sh" +source "$SCRIPT_DIR/arch/gaming.sh" +source "$SCRIPT_DIR/arch/music.sh" +source "$SCRIPT_DIR/arch/lab.sh" + +# Main Arch installation function +arch_install_all() { + log SECTION "Starting Arch Linux installation" + + # System setup (drivers, core system, Hyprland) + arch_setup_system + + # Terminal environment (CLI tools, modern replacements) + arch_setup_terminal + + # Development environment (languages, LSPs, tools) + arch_setup_development + + # Desktop applications (GUI apps, work tools) + arch_setup_desktop + + # Gaming setup (Steam, Wine, VR) + arch_setup_gaming + + # Music production + arch_setup_music_production + + # Lab equipment + arch_setup_lab + + log SUCCESS "Arch Linux installation completed" +} + +# Source guard +if [ -z "$ARCH_MASTER_LOADED" ]; then + ARCH_MASTER_LOADED=true +fi \ No newline at end of file diff --git a/update/arch/desktop.sh b/update/arch/desktop.sh new file mode 100644 index 0000000..b3e4b63 --- /dev/null +++ b/update/arch/desktop.sh @@ -0,0 +1,287 @@ +#!/bin/bash + +# Arch Linux Desktop Applications Module +# Handles desktop applications, fonts, and user applications + +arch_install_desktop_base() { + if ! role_enabled "DESKTOP_BASE"; then + return 0 + fi + + log SECTION "Installing desktop base applications" + local section_start=$(date +%s) + + if confirm "Install base desktop applications?"; then + local desktop_packages=( + cameractrls feh + ) + + install_packages "${desktop_packages[@]}" + + # Essential Flatpak applications + local flatpak_apps=( + "com.discordapp.Discord" + "com.behringer.XAirEdit" + "com.github.vikdevelop.timer" + "io.github.efogdev.mpris-timer" + "org.remmina.Remmina" + ) + + for app in "${flatpak_apps[@]}"; do + install_flatpak_apps "$app" + done + + # Brave browser from AUR + install_aur_packages brave-bin + + log SUCCESS "Desktop base applications installed $(show_timer $section_start)" + fi +} + +arch_install_fonts() { + if ! role_enabled "DESKTOP_BASE"; then + return 0 + fi + + log SECTION "Installing fonts" + local section_start=$(date +%s) + + if confirm "Install additional fonts?"; then + local font_packages=( + noto-fonts poppler-data adobe-source-code-pro-fonts + ttf-liberation ttf-dejavu + ) + + install_packages "${font_packages[@]}" + + log SUCCESS "Fonts installed $(show_timer $section_start)" + fi +} + +arch_install_desktop_work() { + if ! role_enabled "DESKTOP_WORK"; then + return 0 + fi + + log SECTION "Installing desktop work applications" + local section_start=$(date +%s) + + if confirm "Install work applications (KiCad, FreeCad, etc.)?"; then + # Applications from official repos + local work_packages=( + kicad freecad + ) + + install_packages "${work_packages[@]}" + + # Work applications from Flatpak + local work_flatpaks=( + "org.kde.krita" + "com.prusa3d.PrusaSlicer" + "com.jgraph.drawio.desktop" + "org.gimp.GIMP" + ) + + for app in "${work_flatpaks[@]}"; do + install_flatpak_apps "$app" + done + + log SUCCESS "Desktop work applications installed $(show_timer $section_start)" + fi +} + +arch_install_media_apps() { + if ! role_enabled "DESKTOP_BASE"; then + return 0 + fi + + log SECTION "Installing media applications" + local section_start=$(date +%s) + + if confirm "Install media applications (video, image viewers, etc.)?"; then + local media_packages=( + mpv vlc imv imagemagick + ) + + install_packages "${media_packages[@]}" + + # Media Flatpak applications + local media_flatpaks=( + "org.videolan.VLC" + "org.kde.kdenlive" + ) + + for app in "${media_flatpaks[@]}"; do + if confirm "Install $(basename $app)?"; then + install_flatpak_apps "$app" + fi + done + + log SUCCESS "Media applications installed $(show_timer $section_start)" + fi +} + +arch_install_office_apps() { + if ! role_enabled "DESKTOP_BASE"; then + return 0 + fi + + log SECTION "Installing office applications" + local section_start=$(date +%s) + + if confirm "Install office applications?"; then + local office_flatpaks=( + "org.libreoffice.LibreOffice" + "com.github.jeromerobert.pdfarranger" + ) + + for app in "${office_flatpaks[@]}"; do + if confirm "Install $(basename $app)?"; then + install_flatpak_apps "$app" + fi + done + + log SUCCESS "Office applications installed $(show_timer $section_start)" + fi +} + +arch_install_system_utilities() { + if ! role_enabled "DESKTOP_BASE"; then + return 0 + fi + + log SECTION "Installing system utilities" + local section_start=$(date +%s) + + if confirm "Install system utilities (file managers, etc.)?"; then + local utility_packages=( + thunar thunar-archive-plugin thunar-media-tags-plugin + file-roller gparted + ) + + install_packages "${utility_packages[@]}" + + log SUCCESS "System utilities installed $(show_timer $section_start)" + fi +} + +arch_install_communication() { + if ! role_enabled "DESKTOP_BASE"; then + return 0 + fi + + log SECTION "Installing communication applications" + local section_start=$(date +%s) + + if confirm "Install communication apps (beyond Discord)?"; then + local comm_flatpaks=( + "com.slack.Slack" + "org.signal.Signal" + "us.zoom.Zoom" + ) + + for app in "${comm_flatpaks[@]}"; do + if confirm "Install $(basename $app)?"; then + install_flatpak_apps "$app" + fi + done + + log SUCCESS "Communication applications installed $(show_timer $section_start)" + fi +} + +arch_install_development_gui() { + if ! role_enabled "DESKTOP_BASE" || (! role_enabled "CODE" && ! role_enabled "DEVELOPMENT"); then + return 0 + fi + + log SECTION "Installing GUI development tools" + local section_start=$(date +%s) + + if confirm "Install GUI development tools?"; then + local dev_gui_flatpaks=( + "com.visualstudio.code" + "com.jetbrains.IntelliJ-IDEA-Community" + ) + + for app in "${dev_gui_flatpaks[@]}"; do + if confirm "Install $(basename $app)?"; then + install_flatpak_apps "$app" + fi + done + + log SUCCESS "GUI development tools installed $(show_timer $section_start)" + fi +} + +arch_setup_desktop_environment() { + if ! role_enabled "DESKTOP_BASE"; then + return 0 + fi + + log SECTION "Setting up desktop environment" + local section_start=$(date +%s) + + # Setup XDG directories + mkdir -p ~/Desktop ~/Documents ~/Downloads ~/Music ~/Pictures ~/Videos + + # Set up mime types and default applications + if command_exists xdg-settings; then + # Set default browser if Brave is installed + if command_exists brave; then + xdg-settings set default-web-browser brave-browser.desktop + fi + fi + + log SUCCESS "Desktop environment configured $(show_timer $section_start)" +} + +# Special applications for specific hostnames +arch_install_hostname_specific() { + local hostname="${SYSTEM_INFO[HOSTNAME]}" + + case "$hostname" in + "CMBOX") + log SECTION "Installing CMBOX-specific applications" + if confirm "Install CMBOX-specific apps?"; then + # CMBOX might need specific tools for work + local cmbox_flatpaks=("com.obsproject.Studio") + for app in "${cmbox_flatpaks[@]}"; do + install_flatpak_apps "$app" + done + fi + ;; + "LABBOX") + log SECTION "Installing LABBOX-specific applications" + if confirm "Install LABBOX-specific apps?"; then + # Lab-specific GUI tools + local lab_packages=("wireshark-qt") + install_packages "${lab_packages[@]}" + fi + ;; + esac +} + +# Main function to run all desktop setup +arch_setup_desktop() { + if ! role_enabled "DESKTOP_BASE"; then + log INFO "Desktop roles not enabled - skipping desktop setup" + return 0 + fi + + arch_install_desktop_base + arch_install_fonts + arch_install_desktop_work + arch_install_media_apps + arch_install_office_apps + arch_install_system_utilities + arch_install_communication + arch_install_development_gui + arch_setup_desktop_environment + arch_install_hostname_specific +} + +# Source guard +if [ -z "$ARCH_DESKTOP_LOADED" ]; then + ARCH_DESKTOP_LOADED=true +fi \ No newline at end of file diff --git a/update/arch/development.sh b/update/arch/development.sh new file mode 100644 index 0000000..a178ad2 --- /dev/null +++ b/update/arch/development.sh @@ -0,0 +1,283 @@ +#!/bin/bash + +# Arch Linux Development Environment Module +# Handles programming languages, tools, and development setup + +arch_install_development_languages() { + log SECTION "Installing development languages and runtimes" + local section_start=$(date +%s) + + if confirm "Install development languages (Node.js, Go, PHP, Ruby, Julia, Java)?"; then + local dev_packages=( + nodejs npm go php luarocks composer jdk-openjdk julia ruby + ) + + install_packages "${dev_packages[@]}" + + # Configure npm prefix + npm config set prefix "${HOME}/.npm" + + log SUCCESS "Development languages installed $(show_timer $section_start)" + fi +} + +arch_install_neovim() { + if ! role_enabled "CODE" && ! role_enabled "DEVELOPMENT" && ! role_enabled "TERMINAL"; then + return 0 + fi + + log SECTION "Installing Neovim" + local section_start=$(date +%s) + + if confirm "Install Neovim (git version)?"; then + # Install git version of neovim from AUR + install_aur_packages neovim-git-bin + + # Install Node.js integration + if command_exists npm; then + sudo npm install -g neovim + fi + + # Setup Neovim configuration + mkdir -p ~/.config/nvim + ln -sf ~/linuxbox/config/nvim/init.lua ~/.config/nvim/init.lua + + # Sync plugins if lazy directory exists + if [ -d ~/.local/share/nvim/lazy ]; then + nvim --headless "+Lazy! sync" +qa || true + fi + + log SUCCESS "Neovim installed $(show_timer $section_start)" + fi +} + +arch_install_rust_tools() { + log SECTION "Installing Rust development tools" + local section_start=$(date +%s) + + if confirm "Install Rust tools (cargo packages)?"; then + # Essential Rust tools + local rust_tools=( + "tree-sitter-cli" + "ripgrep" + "eza" + "zoxide --locked" + "starship --locked" + ) + + for tool in "${rust_tools[@]}"; do + log INFO "Installing $tool..." + cargo install $tool + done + + # Setup starship configuration + mkdir -p ~/.config + ln -sf ~/linuxbox/config/starship.toml ~/.config/starship.toml + + log SUCCESS "Rust tools installed $(show_timer $section_start)" + fi +} + +arch_install_embedded_tools() { + if ! role_enabled "CODE" && ! role_enabled "LAB"; then + return 0 + fi + + log SECTION "Installing embedded development tools" + local section_start=$(date +%s) + + if confirm "Install embedded development tools (RP2040, etc.)?"; then + # Add embedded target for Rust + rustup target add thumbv6m-none-eabi + + # Install embedded-specific cargo tools + local embedded_tools=( + "elf2uf2-rs --locked" + "probe-run" + "flip-link" + ) + + for tool in "${embedded_tools[@]}"; do + log INFO "Installing $tool..." + cargo install $tool + done + + # Link pico-load script + mkdir -p ~/.local/bin + ln -sf ~/linuxbox/pico-load.sh ~/.local/bin/pico-load + + log SUCCESS "Embedded tools installed $(show_timer $section_start)" + fi +} + +arch_install_lsp_servers() { + if ! role_enabled "CODE" && ! role_enabled "DEVELOPMENT"; then + return 0 + fi + + log SECTION "Installing LSP servers" + local section_start=$(date +%s) + + if confirm "Install Language Server Protocol servers?"; then + # LSP servers from official repos + local lsp_packages=( + prettier stylua python-black shfmt lua-language-server + bash-language-server ccls vscode-html-languageserver + vscode-json-languageserver marksman pyright yaml-language-server + vscode-css-languageserver clang + ) + + install_packages "${lsp_packages[@]}" + + # LSP servers from AUR + install_aur_packages dockerfile-language-server + + # Rust components + rustup component add rust-analyzer clippy rustfmt + + # Lua configuration + ln -sf ~/linuxbox/luacheckrc ~/.luacheckrc + + log SUCCESS "LSP servers installed $(show_timer $section_start)" + fi +} + +arch_install_virtualhere() { + if ! role_enabled "CODE" && ! role_enabled "LAB"; then + return 0 + fi + + log SECTION "Installing VirtualHere USB client" + local section_start=$(date +%s) + + if confirm "Install VirtualHere USB over IP client?"; then + cd ~ + + # Download VirtualHere client files + local vh_files=( + "virtualhereclient.service" + "vhclientx86_64" + "vhuit64" + ) + + local vh_base_url="https://www.virtualhere.com/sites/default/files/usbclient" + + for file in "${vh_files[@]}"; do + if [ "$file" == "virtualhereclient.service" ]; then + wget "${vh_base_url}/scripts/$file" + else + wget "${vh_base_url}/$file" + fi + done + + # Make executables and install + chmod +x ./vhclientx86_64 ./vhuit64 + sudo mv ./vhclientx86_64 /usr/sbin + sudo mv ./vhuit64 /usr/sbin + + # Setup sudo permissions + echo "$USER ALL=(ALL:ALL) NOPASSWD: /usr/sbin/vhclientx86_64" | \ + sudo tee /etc/sudoers.d/$USER+vhclientx86_64 + echo "$USER ALL=(ALL:ALL) NOPASSWD: /usr/sbin/vhuit64" | \ + sudo tee /etc/sudoers.d/$USER+vhuit64 + + # Install and enable service + sudo mv virtualhereclient.service /etc/systemd/system/virtualhereclient.service + sudo systemctl daemon-reload + sudo systemctl enable virtualhereclient.service + sudo systemctl start virtualhereclient.service + + log SUCCESS "VirtualHere client installed $(show_timer $section_start)" + fi +} + +arch_setup_git() { + log SECTION "Setting up Git configuration" + local section_start=$(date +%s) + + # Install git-lfs if not present + if ! command_exists git-lfs; then + install_packages git-lfs + fi + + # Link git configuration + ln -sf ~/linuxbox/gitconfig ~/.gitconfig + + log SUCCESS "Git configuration setup $(show_timer $section_start)" +} + +arch_install_lazygit() { + if ! role_enabled "CODE" && ! role_enabled "DEVELOPMENT"; then + return 0 + fi + + log SECTION "Installing Lazygit" + local section_start=$(date +%s) + + if confirm "Install Lazygit Git TUI?"; then + install_packages lazygit + + # Setup lazygit configuration + mkdir -p ~/.config/lazygit + ln -sf ~/linuxbox/config/lazygit/config.yml ~/.config/lazygit/config.yml + + log SUCCESS "Lazygit installed $(show_timer $section_start)" + fi +} + +arch_install_containers() { + if ! role_enabled "CODE" && ! role_enabled "DEVELOPMENT"; then + return 0 + fi + + log SECTION "Installing container tools" + local section_start=$(date +%s) + + if confirm "Install container tools (Docker, Podman)?"; then + # Install from official repositories or AUR + local container_packages=() + + if confirm "Install Docker?"; then + container_packages+=(docker docker-compose) + fi + + if confirm "Install Podman?"; then + container_packages+=(podman podman-compose) + fi + + if [ ${#container_packages[@]} -gt 0 ]; then + install_packages "${container_packages[@]}" + + # Add user to docker group if docker was installed + if [[ " ${container_packages[@]} " =~ " docker " ]]; then + sudo usermod -aG docker $USER + log INFO "Added $USER to docker group - logout/login required" + fi + fi + + log SUCCESS "Container tools installed $(show_timer $section_start)" + fi +} + +# Main function to run all development setup +arch_setup_development() { + if ! role_enabled "CODE" && ! role_enabled "DEVELOPMENT"; then + log INFO "Development roles not enabled - skipping development setup" + return 0 + fi + + arch_setup_git + arch_install_development_languages + arch_install_neovim + arch_install_rust_tools + arch_install_embedded_tools + arch_install_lsp_servers + arch_install_virtualhere + arch_install_lazygit + arch_install_containers +} + +# Source guard +if [ -z "$ARCH_DEVELOPMENT_LOADED" ]; then + ARCH_DEVELOPMENT_LOADED=true +fi \ No newline at end of file diff --git a/update/arch/gaming.sh b/update/arch/gaming.sh new file mode 100644 index 0000000..8a656e9 --- /dev/null +++ b/update/arch/gaming.sh @@ -0,0 +1,147 @@ +#!/bin/bash + +# Arch Linux Gaming Module +# Handles gaming, VR, and entertainment software + +arch_install_gaming_base() { + if ! role_enabled "GAME"; then + return 0 + fi + + log SECTION "Installing gaming base packages" + local section_start=$(date +%s) + + if confirm "Install gaming base (Wine, Steam, etc.)?"; then + local gaming_packages=( + wine wine-mono wine-gecko qt5-tools steam winetricks + onnxruntime mangohud lib32-mangohud gamemode + ) + + install_packages "${gaming_packages[@]}" + + # Gaming tools from AUR + local gaming_aur=( + protonup-qt protontricks lug-helper openmpi jstest-gtk-git + ) + + install_aur_packages "${gaming_aur[@]}" + + log SUCCESS "Gaming base installed $(show_timer $section_start)" + fi +} + +arch_install_opentrack() { + if ! role_enabled "GAME"; then + return 0 + fi + + log SECTION "Installing OpenTrack head tracking" + local section_start=$(date +%s) + + if confirm "Build and install OpenTrack?"; then + if [ ! -d ~/Games/opentrack ]; then + mkdir -p ~/Games + cd ~/Games + + ( + git clone https://github.com/opentrack/opentrack + cd opentrack/ + mkdir build + cd build + cmake .. + ccmake . + make + make install + ) 2>&1 | tee -a "$LOG_FILE" & + + spinner $! "Building OpenTrack (this will take a while)..." + wait + + # Create desktop entry + cat > /tmp/opentrack.desktop << EOF +[Desktop Entry] +Version=3.1.0 +Type=Application +Name=Opentrack +Exec=$HOME/Games/opentrack/build/install/bin/opentrack -platform xcb +Icon=$HOME/Games/opentrack/contrib/cute-octopus-vector-material_15-1831.jpg +Terminal=false +StartupNotify=true +EOF + sudo mv /tmp/opentrack.desktop /usr/share/applications/opentrack.desktop + sudo update-desktop-database /usr/share/applications + fi + + log SUCCESS "OpenTrack installed $(show_timer $section_start)" + fi +} + +arch_install_simonbox_gaming() { + if [ "${SYSTEM_INFO[HOSTNAME]}" != "SIMONBOX" ]; then + return 0 + fi + + log SECTION "Installing SIMONBOX-specific gaming tools" + local section_start=$(date +%s) + + if confirm "Install SIMONBOX gaming packages?"; then + # SIMONBOX specific packages + local simonbox_packages=( + fluidsynth gamemode gvfs libayatana-appindicator innoextract + lib32-gamemode lib32-vkd3d python-pefile python-protobuf + vulkan-icd-loader vkd3d lib32-vulkan-icd-loader vulkan-tools + xorg-xgamma umu-launcher lutris + ) + + install_packages "${simonbox_packages[@]}" + + # Sober for Roblox + install_flatpak_apps org.vinegarhq.Sober + + log SUCCESS "SIMONBOX gaming setup completed $(show_timer $section_start)" + fi +} + +arch_install_vr() { + if ! role_enabled "VR"; then + return 0 + fi + + log SECTION "Installing VR support" + local section_start=$(date +%s) + + if confirm "Install VR tools (Monado, overlays)?"; then + # VR development packages + local vr_packages=( + cli11 glib2-devel nlohmann-json glew + ) + + install_packages "${vr_packages[@]}" + + # VR tools from AUR + local vr_aur=( + monado-vulkan-layers-git wlx-overlay-s-git xrgears envision-xr-git + ) + + install_aur_packages "${vr_aur[@]}" + + log SUCCESS "VR support installed $(show_timer $section_start)" + fi +} + +# Main function +arch_setup_gaming() { + if ! role_enabled "GAME"; then + log INFO "Gaming role not enabled - skipping gaming setup" + return 0 + fi + + arch_install_gaming_base + arch_install_opentrack + arch_install_simonbox_gaming + arch_install_vr +} + +if [ -z "$ARCH_GAMING_LOADED" ]; then + ARCH_GAMING_LOADED=true +fi \ No newline at end of file diff --git a/update/arch/lab.sh b/update/arch/lab.sh new file mode 100644 index 0000000..7bf8c3e --- /dev/null +++ b/update/arch/lab.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Arch Linux Lab Equipment Module + +arch_install_lab_tools() { + if ! role_enabled "LAB"; then + return 0 + fi + + log SECTION "Installing lab and measurement tools" + local section_start=$(date +%s) + + if confirm "Install lab equipment software?"; then + # PicoScope and related tools from AUR + local lab_aur=( + ps7_libpicoipp ps7_libpicocv picoscope7 + ps7_libps2000a ps7_libps3000a + nrf-udev nrfconnect-appimage + ) + + install_aur_packages "${lab_aur[@]}" + + # System packages for lab work + local lab_packages=(tk python-pyserial) + install_packages "${lab_packages[@]}" + + # Download SPM6103 viewer + cd ~ && wget -O spm6103_viewer.py \ + "https://git.cmtec.se/cm/spm6103_viewer/-/raw/main/spm6103_viewer.py?ref_type=heads&inline=false" + + log SUCCESS "Lab tools installed $(show_timer $section_start)" + fi +} + +arch_setup_lab() { + arch_install_lab_tools +} + +if [ -z "$ARCH_LAB_LOADED" ]; then + ARCH_LAB_LOADED=true +fi \ No newline at end of file diff --git a/update/arch/music.sh b/update/arch/music.sh new file mode 100644 index 0000000..cc2f3fe --- /dev/null +++ b/update/arch/music.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Arch Linux Music Production Module + +arch_setup_music_production() { + if ! role_enabled "MUSIC"; then + log INFO "Music role not enabled - skipping music production setup" + return 0 + fi + + log SECTION "Installing music production tools" + local section_start=$(date +%s) + + if confirm "Install music production software?"; then + # Music production packages (already handled in system.sh for audio) + # Install Bitwig Studio + install_flatpak_apps com.bitwig.BitwigStudio + + log SUCCESS "Music production tools installed $(show_timer $section_start)" + fi +} + +if [ -z "$ARCH_MUSIC_LOADED" ]; then + ARCH_MUSIC_LOADED=true +fi \ No newline at end of file diff --git a/update/arch/system.sh b/update/arch/system.sh new file mode 100644 index 0000000..01b5977 --- /dev/null +++ b/update/arch/system.sh @@ -0,0 +1,301 @@ +#!/bin/bash + +# Arch Linux System Setup Module +# Handles system packages, drivers, and core system configuration + +arch_install_system_base() { + log SECTION "Installing Arch system base packages" + local section_start=$(date +%s) + + if confirm "Install essential system packages?"; then + local packages=( + base-devel linux-headers git bc cmake gawk wget gettext unzip curl + inetutils python python-pip python-pipx python-pynvim rustup timeshift + ) + + install_packages "${packages[@]}" + + # Setup Rust + rustup update stable + rustup default stable + + log SUCCESS "System base packages installed $(show_timer $section_start)" + fi +} + +arch_install_drivers() { + log SECTION "Installing graphics drivers" + local section_start=$(date +%s) + + if role_enabled "NVIDIA_GPU" || role_enabled "NVIDIA_1080_GPU"; then + if confirm "Install NVIDIA drivers?"; then + log INFO "Installing NVIDIA drivers..." + + # Check if we already have nvidia drivers + local new_kernel="no" + if ! package_installed nvidia-open-dkms && ! package_installed nvidia-dkms; then + new_kernel="yes" + fi + + local nvidia_packages=(nvidia-dkms nvidia-utils nvidia-settings opencl-nvidia) + + # Add CUDA for high-end GPUs + if role_enabled "NVIDIA_1080_GPU"; then + nvidia_packages+=(cuda) + fi + + # Add 32-bit libs for gaming + if role_enabled "GAME"; then + nvidia_packages+=(lib32-nvidia-utils) + fi + + install_packages "${nvidia_packages[@]}" + + if [ "$new_kernel" == "yes" ]; then + log WARNING "NVIDIA driver updated - kernel rebuild required" + log WARNING "Please reboot and run the script again after reboot" + exit 0 + fi + + log SUCCESS "NVIDIA drivers installed $(show_timer $section_start)" + fi + else + if confirm "Install Intel graphics drivers?"; then + log INFO "Installing Intel graphics drivers..." + install_packages mesa intel-media-driver + log SUCCESS "Intel drivers installed $(show_timer $section_start)" + fi + fi +} + +arch_setup_multilib() { + if role_enabled "GAME"; then + log SECTION "Enabling multilib repository" + if ! grep -q "^\[multilib\]" /etc/pacman.conf; then + if confirm "Enable multilib repository for gaming?"; then + log INFO "Adding multilib repository..." + sudo tee -a /etc/pacman.conf >/dev/null <> "$LOG_FILE" + + case $level in + ERROR) echo -e "${RED}${CROSS}${RESET} $message" ;; + SUCCESS) echo -e "${GREEN}${CHECK}${RESET} $message" ;; + WARNING) echo -e "${YELLOW}${WARNING}${RESET} $message" ;; + INFO) echo -e "${BLUE}${INFO}${RESET} $message" ;; + SECTION) echo -e "\n${CYAN}${GEAR} $message${RESET}" ;; + *) echo -e "${GRAY}$message${RESET}" ;; + esac +} + +# Fancy spinner function for long operations +spinner() { + local pid=$1 + local message="$2" + local delay=0.08 + local spinstr='โ ‹โ ™โ นโ ธโ ผโ ดโ ฆโ งโ ‡โ ' + + echo -e "${CYAN}${GEAR} $message${RESET}" + printf " " + + while kill -0 $pid 2>/dev/null; do + local temp=${spinstr#?} + printf "${BLUE}%c${RESET}" "$spinstr" + spinstr=$temp${spinstr%"$temp"} + sleep $delay + printf "\b" + done + + printf "${GREEN}${CHECK}${RESET}\n" +} + +# Progress bar function +progress_bar() { + local current=$1 + local total=$2 + local message="$3" + local width=40 + local percentage=$((current * 100 / total)) + local filled=$((current * width / total)) + local empty=$((width - filled)) + + printf "\r${message} ${BLUE}[" + printf "%*s" $filled | tr ' ' 'โ–ˆ' + printf "%*s" $empty | tr ' ' 'โ–‘' + printf "] %d%% (%d/%d)${RESET}" $percentage $current $total + if [ $current -eq $total ]; then + echo + fi +} + +# Timer function +show_timer() { + local start_time=$1 + local end_time=$(date +%s) + local elapsed=$((end_time - start_time)) + local hours=$((elapsed / 3600)) + local minutes=$(((elapsed % 3600) / 60)) + local seconds=$((elapsed % 60)) + + if [ $hours -gt 0 ]; then + printf "${CYAN}${TIMER} %02d:%02d:%02d${RESET}" $hours $minutes $seconds + else + printf "${CYAN}${TIMER} %02dm %02ds${RESET}" $minutes $seconds + fi +} + +# Confirmation function for interactive mode +confirm() { + if [ "$INTERACTIVE" == "true" ]; then + local prompt="$1" + local default="${2:-n}" + echo -ne "${YELLOW}${WARNING} $prompt [y/N]: ${RESET}" + read -r response + response=${response:-$default} + case $response in + [yY][eE][sS]|[yY]) return 0 ;; + *) return 1 ;; + esac + else + return 0 + fi +} + +# System health check function +system_health_check() { + local section_start=$(date +%s) + log SECTION "Running system health check" + local issues=0 + + # Check disk space + local root_usage=$(df / | awk 'NR==2 {print $5}' | sed 's/%//') + if [ "$root_usage" -gt 85 ]; then + log WARNING "Root filesystem is ${root_usage}% full" + ((issues++)) + else + log SUCCESS "Root filesystem usage: ${root_usage}%" + fi + + # Check available memory + local mem_available=$(free -m | awk 'NR==2{printf "%d", $7}') + if [ "$mem_available" -lt 512 ]; then + log WARNING "Low memory available: ${mem_available}MB" + ((issues++)) + else + log SUCCESS "Available memory: ${mem_available}MB" + fi + + # Check for failed systemd services + local failed_services=$(systemctl --failed --quiet --no-legend 2>/dev/null | wc -l) + if [ "$failed_services" -gt 0 ]; then + log WARNING "$failed_services failed systemd services detected" + ((issues++)) + else + log SUCCESS "All systemd services running normally" + fi + + # Check package manager locks (distro-specific) + case "${SYSTEM_INFO[DISTRO]}" in + "arch") + if [ -f /var/lib/pacman/db.lck ]; then + log WARNING "Pacman database is locked" + ((issues++)) + fi + ;; + "ubuntu"|"debian") + if sudo fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; then + log WARNING "APT database is locked" + ((issues++)) + fi + ;; + esac + + if [ $issues -eq 0 ]; then + log SUCCESS "System health check passed $(show_timer $section_start)" + else + log WARNING "System health check found $issues issues $(show_timer $section_start)" + if [ "$INTERACTIVE" == "true" ]; then + if ! confirm "Continue despite health issues?"; then + log INFO "Update cancelled by user due to health issues" + exit 1 + fi + fi + fi + + return $issues +} + +# Error handler function +error_handler() { + local line_number=$1 + local error_code=$2 + local command="$3" + log ERROR "Script failed at line $line_number with exit code $error_code" + log ERROR "Failed command: $command" + log ERROR "Check log file: $LOG_FILE" + + echo -e "\n${RED}โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—${RESET}" + echo -e "${RED}โ•‘${RESET} ${BOLD}SCRIPT FAILED${RESET} ${RED}โ•‘${RESET}" + echo -e "${RED}โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ${RESET}" + echo -e "${RED}โ•‘${RESET} Line: $line_number ${RED}โ•‘${RESET}" + echo -e "${RED}โ•‘${RESET} Exit Code: $error_code ${RED}โ•‘${RESET}" + echo -e "${RED}โ•‘${RESET} Log File: $LOG_FILE ${RED}โ•‘${RESET}" + echo -e "${RED}โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${RESET}\n" + exit $error_code +} + +# Fancy header display with original ASCII art +show_header() { + local hostname=$1 + local distro=$2 + clear + echo -e "\n${BLUE}โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}.${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/ \\${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/ \\${RESET} ${WHITE} # ${BLUE}| *${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/^. \\${RESET} ${WHITE} a##e #%\" a#\"e 6##% ${BLUE}| | |-^-. | | \\ /${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/ .-. \\${RESET} ${WHITE}.oOo# # # # # ${BLUE}| | | | | | X${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/ ( ) _\\${RESET} ${WHITE}%OoO# # %#e\" # # ${BLUE}| | | | ^._.| / \\${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/ _.~ ~._^\\${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/.^ ^\\ ${GRAY}โ„ข${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${GREEN}${ROCKET} CMtec Universal Update System v$VERSION${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${GRAY}$hostname | $distro | $(date '+%Y-%m-%d %H:%M:%S')${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${RESET}\n" +} + +# Alternative fancy header with original Arch-style ASCII art +show_arch_header() { + local hostname=$1 + clear + echo -e "\n${BLUE}โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}.${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/ \\${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/ \\${RESET} ${WHITE} # ${BLUE}| *${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/^. \\${RESET} ${WHITE} a##e #%\" a#\"e 6##% ${BLUE}| | |-^-. | | \\ /${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/ .-. \\${RESET} ${WHITE}.oOo# # # # # ${BLUE}| | | | | | X${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/ ( ) _\\${RESET} ${WHITE}%OoO# # %#e\" # # ${BLUE}| | | | ^._.| / \\${RESET} ${GRAY}โ„ข${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/ _.~ ~._^\\${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}/.^ ^\\ ${GRAY}โ„ข${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${GREEN}${ROCKET} CMtec '$hostname' Enhanced Update Script${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•‘${RESET} ${GRAY}$(date '+%Y-%m-%d %H:%M:%S')${RESET} ${BLUE}โ•‘${RESET}" + echo -e "${BLUE}โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${RESET}\n" +} + +# Ubuntu-style header with Ubuntu ASCII art +show_ubuntu_header() { + local hostname=$1 + clear + echo -e "\n${YELLOW}โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} .--.${RESET} ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} .-\"''\`(|||)${RESET} ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} ,\`\\ \\ \`-\`.${RESET} 88 88 ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} / \\ \"\`\`-. \`${RESET} 88 88 ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} .-. , \`___:${RESET} 88 88 88,888, 88 88 ,88888, 88888 ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} (:::) : ___ ${RESET} 88 88 88 88 88 88 88 88 88 ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} \`-\` \` , :${RESET} 88 88 88 88 88 88 88 88 88 ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} \\ / ,..-\` ,${RESET} 88 88 88 88 88 88 88 88 88 ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} \`.\/ / .-.\`${RESET} \"88888\" \"88888\" \"88888\" 88 88 \"8888${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} \`-..-( )${RESET} ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${RED} \`-\`${RESET} ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${GREEN}${ROCKET} CMtec Ubuntu Install/Update Script${RESET} ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•‘${RESET} ${GRAY}$hostname | $(date '+%Y-%m-%d %H:%M:%S')${RESET} ${YELLOW}โ•‘${RESET}" + echo -e "${YELLOW}โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${RESET}\n" +} + +# Display enabled roles with fancy formatting +show_roles() { + local role_count=0 + for role in "${!ROLES[@]}"; do + if [ "${ROLES[$role]}" == "yes" ]; then + ((role_count++)) + fi + done + + if [ $role_count -eq 0 ]; then + log WARNING "No roles enabled" + return + fi + + log SECTION "System Configuration" + echo -e "${BOLD}${PACKAGE} Enabled Roles ($role_count total):${RESET}" + + for role in "${!ROLES[@]}"; do + if [ "${ROLES[$role]}" == "yes" ]; then + case $role in + desktop*|DESKTOP*) icon="๐Ÿ–ฅ๏ธ" ;; + game*|GAME*) icon="๐ŸŽฎ" ;; + music*|MUSIC*) icon="๐ŸŽต" ;; + dev*|code*|DEV*|CODE*) icon="๐Ÿ’ป" ;; + terminal*|TERMINAL*) icon="๐Ÿ“Ÿ" ;; + nvidia*|NVIDIA*) icon="๐ŸŽฏ" ;; + vr*|VR*) icon="๐Ÿฅฝ" ;; + lab*|LAB*) icon="๐Ÿ”ฌ" ;; + bt*|BT*|bluetooth*) icon="๐Ÿ“ถ" ;; + hypr*|HYPERLAND*) icon="๐ŸŒŠ" ;; + wsl*|WSL*) icon="๐Ÿง" ;; + *) icon="โš™๏ธ" ;; + esac + echo -e " ${CYAN}$icon $role${RESET}" + fi + done + echo +} + +# Final summary with statistics +show_final_summary() { + local end_time=$(date +%s) + local total_time=$((end_time - START_TIME)) + local total_hours=$((total_time / 3600)) + local total_minutes=$(((total_time % 3600) / 60)) + local total_seconds=$((total_time % 60)) + + # Collect system info for summary + local kernel_version=$(uname -r) + local role_count=0 + for role in "${!ROLES[@]}"; do + if [ "${ROLES[$role]}" == "yes" ]; then + ((role_count++)) + fi + done + + log SECTION "Update Summary" + + echo -e "\n${GREEN}โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—${RESET}" + echo -e "${GREEN}โ•‘${RESET} ${BOLD}๐ŸŽ‰ UPDATE COMPLETE! ๐ŸŽ‰${RESET} ${GREEN}โ•‘${RESET}" + echo -e "${GREEN}โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ${RESET}" + echo -e "${GREEN}โ•‘${RESET} ${CYAN}๐Ÿ“Š Statistics:${RESET} ${GREEN}โ•‘${RESET}" + + if [ $total_hours -gt 0 ]; then + echo -e "${GREEN}โ•‘${RESET} โ€ข Total time: ${CYAN}${TIMER} ${total_hours}h ${total_minutes}m ${total_seconds}s${RESET} ${GREEN}โ•‘${RESET}" + else + echo -e "${GREEN}โ•‘${RESET} โ€ข Total time: ${CYAN}${TIMER} ${total_minutes}m ${total_seconds}s${RESET} ${GREEN}โ•‘${RESET}" + fi + + echo -e "${GREEN}โ•‘${RESET} โ€ข Hostname: ${CYAN}${SYSTEM_INFO[HOSTNAME]}${RESET} ${GREEN}โ•‘${RESET}" + echo -e "${GREEN}โ•‘${RESET} โ€ข Distro: ${CYAN}${SYSTEM_INFO[DISTRO]} ${SYSTEM_INFO[VERSION]}${RESET} ${GREEN}โ•‘${RESET}" + echo -e "${GREEN}โ•‘${RESET} โ€ข Kernel: ${CYAN}$kernel_version${RESET} ${GREEN}โ•‘${RESET}" + echo -e "${GREEN}โ•‘${RESET} โ€ข Active roles: ${CYAN}$role_count enabled${RESET} ${GREEN}โ•‘${RESET}" + echo -e "${GREEN}โ•‘${RESET} โ€ข Log file: ${GRAY}$LOG_FILE${RESET} ${GREEN}โ•‘${RESET}" + echo -e "${GREEN}โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ${RESET}" + echo -e "${GREEN}โ•‘${RESET} ${YELLOW}โš ๏ธ SYSTEM REBOOT RECOMMENDED โš ๏ธ${RESET} ${GREEN}โ•‘${RESET}" + echo -e "${GREEN}โ•‘${RESET} ${GREEN}โ•‘${RESET}" + echo -e "${GREEN}โ•‘${RESET} ${WHITE}Some updates may require a reboot to take effect${RESET} ${GREEN}โ•‘${RESET}" + echo -e "${GREEN}โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•${RESET}\n" + + log SUCCESS "Update script completed successfully" + log INFO "Total execution time: $(show_timer $START_TIME)" + log INFO "System: ${SYSTEM_INFO[DISTRO]} ${SYSTEM_INFO[VERSION]} on ${SYSTEM_INFO[HOSTNAME]}" + log INFO "Active roles: $role_count" + + # Interactive reboot prompt + if [ "$INTERACTIVE" == "true" ]; then + echo -ne "${YELLOW}${WARNING} Reboot system now? [y/N]: ${RESET}" + read -r -t 10 response || response="n" + case $response in + [yY][eE][sS]|[yY]) + log INFO "Rebooting system as requested by user" + echo -e "${GREEN}${CHECK} Rebooting in 3 seconds...${RESET}" + sleep 1 + echo -e "${GREEN}${CHECK} Rebooting in 2 seconds...${RESET}" + sleep 1 + echo -e "${GREEN}${CHECK} Rebooting in 1 second...${RESET}" + sleep 1 + sudo reboot + ;; + *) + log INFO "Reboot cancelled by user" + echo -e "${BLUE}${INFO} Remember to reboot when convenient!${RESET}" + ;; + esac + else + echo -e "${BLUE}${INFO} Please reboot your system when convenient${RESET}" + fi + + echo -e "${GREEN}${CHECK} Thank you for using CMtec Universal Update System!${RESET}\n" +} + +# Utility function to check if command exists +command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +# Utility function to check if package is installed (distro-agnostic) +package_installed() { + local package="$1" + case "${SYSTEM_INFO[DISTRO]}" in + "arch") + pacman -Qs "$package" >/dev/null 2>&1 + ;; + "ubuntu"|"debian") + dpkg -l "$package" >/dev/null 2>&1 + ;; + *) + return 1 + ;; + esac +} + +# Initialize logging +init_core() { + # Set error trap + trap 'error_handler ${LINENO} $? "$BASH_COMMAND"' ERR + + # Initialize log + log INFO "Starting CMtec Universal Update System v$VERSION" + log INFO "Log file: $LOG_FILE" + log INFO "Interactive mode: $INTERACTIVE" +} + +# Source guard to prevent double-sourcing +if [ -z "$CORE_LIB_LOADED" ]; then + CORE_LIB_LOADED=true +fi \ No newline at end of file diff --git a/update/lib/detect.sh b/update/lib/detect.sh new file mode 100644 index 0000000..b92c295 --- /dev/null +++ b/update/lib/detect.sh @@ -0,0 +1,266 @@ +#!/bin/bash + +# CMtec Update System - OS Detection Library +# Detects operating system, distribution, version, and environment + +# Initialize system info array +declare -A SYSTEM_INFO + +# Detect operating system and distribution +detect_system() { + log INFO "Detecting system information..." + + # Basic OS detection + SYSTEM_INFO[OS]=$(uname -s) + SYSTEM_INFO[ARCH]=$(uname -m) + SYSTEM_INFO[HOSTNAME]=$(hostname | tr '[:lower:]' '[:upper:]') + SYSTEM_INFO[KERNEL]=$(uname -r) + + # Detect distribution + if [ -f /etc/os-release ]; then + source /etc/os-release + SYSTEM_INFO[DISTRO]=$(echo "$ID" | tr '[:upper:]' '[:lower:]') + SYSTEM_INFO[VERSION]="$VERSION_ID" + SYSTEM_INFO[PRETTY_NAME]="$PRETTY_NAME" + elif [ -f /etc/arch-release ]; then + SYSTEM_INFO[DISTRO]="arch" + SYSTEM_INFO[VERSION]="rolling" + SYSTEM_INFO[PRETTY_NAME]="Arch Linux" + elif [ -f /etc/debian_version ]; then + SYSTEM_INFO[DISTRO]="debian" + SYSTEM_INFO[VERSION]=$(cat /etc/debian_version) + SYSTEM_INFO[PRETTY_NAME]="Debian GNU/Linux" + else + log ERROR "Unable to detect Linux distribution" + return 1 + fi + + # Detect environment specifics + detect_environment + + # Log system information + log SUCCESS "System detected: ${SYSTEM_INFO[PRETTY_NAME]} (${SYSTEM_INFO[DISTRO]})" + log INFO "Hostname: ${SYSTEM_INFO[HOSTNAME]}" + log INFO "Architecture: ${SYSTEM_INFO[ARCH]}" + log INFO "Environment: ${SYSTEM_INFO[ENVIRONMENT]}" + + return 0 +} + +# Detect specific environment (WSL, Desktop, Container, etc.) +detect_environment() { + local env_flags=() + + # Check for WSL + if [[ "$(systemd-detect-virt 2>/dev/null)" == *"wsl"* ]] || \ + [ -f /proc/sys/fs/binfmt_misc/WSLInterop ] || \ + grep -qi "microsoft" /proc/version 2>/dev/null; then + env_flags+=("wsl") + SYSTEM_INFO[WSL]="yes" + else + SYSTEM_INFO[WSL]="no" + fi + + # Check for container environment + if [ -f /.dockerenv ] || \ + [[ "$(systemd-detect-virt 2>/dev/null)" == "docker" ]] || \ + [[ "$(systemd-detect-virt 2>/dev/null)" == "podman" ]]; then + env_flags+=("container") + SYSTEM_INFO[CONTAINER]="yes" + else + SYSTEM_INFO[CONTAINER]="no" + fi + + # Check for desktop environment + detect_desktop_environment + + # Check for virtualization + local virt=$(systemd-detect-virt 2>/dev/null) + if [ "$virt" != "none" ] && [ -n "$virt" ]; then + env_flags+=("vm") + SYSTEM_INFO[VIRTUALIZATION]="$virt" + else + SYSTEM_INFO[VIRTUALIZATION]="none" + fi + + # Set environment string + if [ ${#env_flags[@]} -gt 0 ]; then + SYSTEM_INFO[ENVIRONMENT]=$(IFS=,; echo "${env_flags[*]}") + else + SYSTEM_INFO[ENVIRONMENT]="native" + fi +} + +# Detect desktop environment +detect_desktop_environment() { + local desktop_env="" + + # Check for various desktop environments + if [ -n "$XDG_CURRENT_DESKTOP" ]; then + desktop_env="$XDG_CURRENT_DESKTOP" + elif [ -n "$DESKTOP_SESSION" ]; then + desktop_env="$DESKTOP_SESSION" + elif [ -n "$GDMSESSION" ]; then + desktop_env="$GDMSESSION" + elif pgrep -x "gnome-session" >/dev/null; then + desktop_env="GNOME" + elif pgrep -x "kded5" >/dev/null || pgrep -x "kded6" >/dev/null; then + desktop_env="KDE" + elif pgrep -x "xfce4-session" >/dev/null; then + desktop_env="XFCE" + elif pgrep -x "hyprland" >/dev/null; then + desktop_env="Hyprland" + fi + + # Special checks for distribution-specific detection + case "${SYSTEM_INFO[DISTRO]}" in + "ubuntu") + if dpkg -l | grep -q "ubuntu-desktop"; then + SYSTEM_INFO[DESKTOP]="yes" + SYSTEM_INFO[DESKTOP_ENV]="${desktop_env:-GNOME}" + else + SYSTEM_INFO[DESKTOP]="no" + fi + ;; + "arch") + if pacman -Qs | grep -E "(gnome|kde|xfce|hyprland)" >/dev/null; then + SYSTEM_INFO[DESKTOP]="yes" + SYSTEM_INFO[DESKTOP_ENV]="$desktop_env" + else + SYSTEM_INFO[DESKTOP]="no" + fi + ;; + *) + if [ -n "$desktop_env" ]; then + SYSTEM_INFO[DESKTOP]="yes" + SYSTEM_INFO[DESKTOP_ENV]="$desktop_env" + else + SYSTEM_INFO[DESKTOP]="no" + fi + ;; + esac +} + +# Detect hardware capabilities +detect_hardware() { + log INFO "Detecting hardware capabilities..." + + # GPU Detection + detect_gpu + + # Audio system detection + detect_audio_system + + # Network capabilities + detect_network_capabilities + + log SUCCESS "Hardware detection completed" +} + +# Detect GPU type and capabilities +detect_gpu() { + local gpu_info=$(lspci | grep -i vga 2>/dev/null) + + SYSTEM_INFO[NVIDIA_GPU]="no" + SYSTEM_INFO[NVIDIA_1080_GPU]="no" + SYSTEM_INFO[AMD_GPU]="no" + SYSTEM_INFO[INTEL_GPU]="no" + + if echo "$gpu_info" | grep -qi nvidia; then + SYSTEM_INFO[NVIDIA_GPU]="yes" + if echo "$gpu_info" | grep -qi "GTX 1080\\|RTX"; then + SYSTEM_INFO[NVIDIA_1080_GPU]="yes" + fi + log INFO "NVIDIA GPU detected" + fi + + if echo "$gpu_info" | grep -qi "amd\\|radeon"; then + SYSTEM_INFO[AMD_GPU]="yes" + log INFO "AMD GPU detected" + fi + + if echo "$gpu_info" | grep -qi intel; then + SYSTEM_INFO[INTEL_GPU]="yes" + log INFO "Intel GPU detected" + fi +} + +# Detect audio system +detect_audio_system() { + if command_exists pulseaudio; then + SYSTEM_INFO[AUDIO_SYSTEM]="pulseaudio" + elif command_exists pipewire; then + SYSTEM_INFO[AUDIO_SYSTEM]="pipewire" + elif command_exists alsa; then + SYSTEM_INFO[AUDIO_SYSTEM]="alsa" + else + SYSTEM_INFO[AUDIO_SYSTEM]="unknown" + fi + + log INFO "Audio system: ${SYSTEM_INFO[AUDIO_SYSTEM]}" +} + +# Detect network capabilities +detect_network_capabilities() { + SYSTEM_INFO[BLUETOOTH]="no" + SYSTEM_INFO[WIFI]="no" + + if command_exists bluetoothctl || [ -d /sys/class/bluetooth ]; then + SYSTEM_INFO[BLUETOOTH]="yes" + fi + + if ip link show | grep -q "wlan\\|wifi\\|wireless" || \ + nmcli dev status 2>/dev/null | grep -q wifi; then + SYSTEM_INFO[WIFI]="yes" + fi +} + +# Get system capabilities summary +get_capabilities() { + local capabilities=() + + [ "${SYSTEM_INFO[DESKTOP]}" == "yes" ] && capabilities+=("desktop") + [ "${SYSTEM_INFO[NVIDIA_GPU]}" == "yes" ] && capabilities+=("nvidia") + [ "${SYSTEM_INFO[AMD_GPU]}" == "yes" ] && capabilities+=("amd") + [ "${SYSTEM_INFO[BLUETOOTH]}" == "yes" ] && capabilities+=("bluetooth") + [ "${SYSTEM_INFO[WIFI]}" == "yes" ] && capabilities+=("wifi") + [ "${SYSTEM_INFO[WSL]}" == "yes" ] && capabilities+=("wsl") + [ "${SYSTEM_INFO[CONTAINER]}" == "yes" ] && capabilities+=("container") + + echo "${capabilities[@]}" +} + +# Check if current system supports a specific feature +supports_feature() { + local feature="$1" + + case "$feature" in + "desktop") + [ "${SYSTEM_INFO[DESKTOP]}" == "yes" ] + ;; + "gpu") + [ "${SYSTEM_INFO[NVIDIA_GPU]}" == "yes" ] || \ + [ "${SYSTEM_INFO[AMD_GPU]}" == "yes" ] + ;; + "nvidia") + [ "${SYSTEM_INFO[NVIDIA_GPU]}" == "yes" ] + ;; + "bluetooth") + [ "${SYSTEM_INFO[BLUETOOTH]}" == "yes" ] + ;; + "wsl") + [ "${SYSTEM_INFO[WSL]}" == "yes" ] + ;; + "container") + [ "${SYSTEM_INFO[CONTAINER]}" == "yes" ] + ;; + *) + return 1 + ;; + esac +} + +# Source guard to prevent double-sourcing +if [ -z "$DETECT_LIB_LOADED" ]; then + DETECT_LIB_LOADED=true +fi \ No newline at end of file diff --git a/update/lib/packages.sh b/update/lib/packages.sh new file mode 100644 index 0000000..b9dce5b --- /dev/null +++ b/update/lib/packages.sh @@ -0,0 +1,406 @@ +#!/bin/bash + +# CMtec Update System - Package Management Abstraction Layer +# Provides unified interface for different package managers + +# Package manager detection and initialization +init_package_managers() { + log INFO "Initializing package managers for ${SYSTEM_INFO[DISTRO]}..." + + case "${SYSTEM_INFO[DISTRO]}" in + "arch") + PACKAGE_MANAGER="pacman" + AUR_HELPER="" + detect_aur_helper + FLATPAK_AVAILABLE=$(command_exists flatpak && echo "yes" || echo "no") + ;; + "ubuntu"|"debian") + PACKAGE_MANAGER="apt" + SNAP_AVAILABLE=$(command_exists snap && echo "yes" || echo "no") + FLATPAK_AVAILABLE=$(command_exists flatpak && echo "yes" || echo "no") + ;; + *) + log ERROR "Unsupported distribution: ${SYSTEM_INFO[DISTRO]}" + return 1 + ;; + esac + + log SUCCESS "Package managers initialized" + log INFO "Primary: $PACKAGE_MANAGER" + [ -n "$AUR_HELPER" ] && log INFO "AUR helper: $AUR_HELPER" + [ "$FLATPAK_AVAILABLE" == "yes" ] && log INFO "Flatpak: available" + [ "$SNAP_AVAILABLE" == "yes" ] && log INFO "Snap: available" +} + +# Detect AUR helper for Arch systems +detect_aur_helper() { + local helpers=("yay" "paru" "pikaur" "trizen") + + for helper in "${helpers[@]}"; do + if command_exists "$helper"; then + AUR_HELPER="$helper" + log INFO "Found AUR helper: $helper" + return 0 + fi + done + + log WARNING "No AUR helper found - will install yay if needed" + AUR_HELPER="" +} + +# Install AUR helper (yay) if not present +install_aur_helper() { + if [ -n "$AUR_HELPER" ]; then + return 0 + fi + + log INFO "Installing yay AUR helper..." + local section_start=$(date +%s) + + # Clean up any existing build directory + [ -d ~/yay-bin ] && rm -rf ~/yay-bin + + cd ~ + ( + git clone https://aur.archlinux.org/yay-bin.git 2>&1 | tee -a "$LOG_FILE" + cd yay-bin + makepkg --noconfirm -si 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Installing yay AUR helper..." + wait + + # Clean up build directory + [ -d ~/yay-bin ] && rm -rf ~/yay-bin + + AUR_HELPER="yay" + log SUCCESS "Yay AUR helper installed $(show_timer $section_start)" +} + +# Update package databases +update_package_databases() { + local section_start=$(date +%s) + log SECTION "Updating package databases" + + case "$PACKAGE_MANAGER" in + "pacman") + if confirm "Refresh pacman package databases?"; then + ( + sudo pacman -Syy --noconfirm 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Refreshing pacman databases..." + wait + log SUCCESS "Pacman databases updated $(show_timer $section_start)" + else + log WARNING "Package database refresh skipped" + fi + ;; + "apt") + if confirm "Update APT package databases?"; then + ( + sudo apt update 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Updating APT databases..." + wait + log SUCCESS "APT databases updated $(show_timer $section_start)" + else + log WARNING "Package database update skipped" + fi + ;; + esac +} + +# System upgrade +system_upgrade() { + local section_start=$(date +%s) + log SECTION "Upgrading system packages" + + case "$PACKAGE_MANAGER" in + "pacman") + if confirm "Upgrade all system packages?"; then + ( + sudo pacman -Su --noconfirm 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Upgrading system packages (may take a while)..." + wait + log SUCCESS "System packages upgraded $(show_timer $section_start)" + else + log WARNING "System upgrade skipped" + fi + ;; + "apt") + if confirm "Upgrade all system packages?"; then + ( + sudo apt upgrade -y 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Upgrading system packages (may take a while)..." + wait + log SUCCESS "System packages upgraded $(show_timer $section_start)" + else + log WARNING "System upgrade skipped" + fi + ;; + esac +} + +# Install packages using primary package manager +install_packages() { + local packages=("$@") + if [ ${#packages[@]} -eq 0 ]; then + return 0 + fi + + log INFO "Installing packages: ${packages[*]}" + + case "$PACKAGE_MANAGER" in + "pacman") + ( + sudo pacman --noconfirm --needed -S "${packages[@]}" 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Installing ${#packages[@]} packages..." + wait + ;; + "apt") + ( + sudo apt install -y "${packages[@]}" 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Installing ${#packages[@]} packages..." + wait + ;; + esac +} + +# Install AUR packages (Arch only) +install_aur_packages() { + local packages=("$@") + if [ ${#packages[@]} -eq 0 ] || [ "$PACKAGE_MANAGER" != "pacman" ]; then + return 0 + fi + + # Ensure AUR helper is available + if [ -z "$AUR_HELPER" ]; then + install_aur_helper + fi + + log INFO "Installing AUR packages: ${packages[*]}" + + ( + "$AUR_HELPER" --noconfirm -S --needed --aur "${packages[@]}" 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Installing ${#packages[@]} AUR packages..." + wait +} + +# Update AUR packages +update_aur_packages() { + if [ "$PACKAGE_MANAGER" != "pacman" ] || [ -z "$AUR_HELPER" ]; then + return 0 + fi + + local section_start=$(date +%s) + log SECTION "Updating AUR packages" + + if confirm "Update AUR packages?"; then + ( + "$AUR_HELPER" --noconfirm --aur 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Updating AUR packages..." + wait + log SUCCESS "AUR packages updated $(show_timer $section_start)" + else + log WARNING "AUR update skipped" + fi +} + +# Install Flatpak applications +install_flatpak_apps() { + local apps=("$@") + if [ ${#apps[@]} -eq 0 ] || [ "$FLATPAK_AVAILABLE" != "yes" ]; then + return 0 + fi + + log INFO "Installing Flatpak apps: ${apps[*]}" + + for app in "${apps[@]}"; do + ( + flatpak install -y flathub "$app" 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Installing Flatpak app: $app..." + wait + done +} + +# Update Flatpak applications +update_flatpak_apps() { + if [ "$FLATPAK_AVAILABLE" != "yes" ]; then + return 0 + fi + + local section_start=$(date +%s) + log SECTION "Updating Flatpak applications" + + if confirm "Update Flatpak applications?"; then + ( + flatpak update -y 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Updating Flatpak applications..." + wait + log SUCCESS "Flatpak applications updated $(show_timer $section_start)" + else + log WARNING "Flatpak update skipped" + fi +} + +# Install Snap packages (Ubuntu/Debian) +install_snap_packages() { + local packages=("$@") + if [ ${#packages[@]} -eq 0 ] || [ "$SNAP_AVAILABLE" != "yes" ]; then + return 0 + fi + + log INFO "Installing Snap packages: ${packages[*]}" + + for package in "${packages[@]}"; do + local snap_args="" + # Handle special snap flags + case "$package" in + *"--classic") + snap_args="--classic" + package=${package//" --classic"/} + ;; + esac + + ( + sudo snap install $snap_args "$package" 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Installing Snap package: $package..." + wait + done +} + +# Update Snap packages +update_snap_packages() { + if [ "$SNAP_AVAILABLE" != "yes" ]; then + return 0 + fi + + local section_start=$(date +%s) + log SECTION "Updating Snap packages" + + if confirm "Update Snap packages?"; then + ( + sudo snap refresh 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Updating Snap packages..." + wait + log SUCCESS "Snap packages updated $(show_timer $section_start)" + else + log WARNING "Snap update skipped" + fi +} + +# Install packages from various sources (unified interface) +install_package_set() { + local pkg_type="$1" + shift + local packages=("$@") + + if [ ${#packages[@]} -eq 0 ]; then + return 0 + fi + + case "$pkg_type" in + "system"|"main") + install_packages "${packages[@]}" + ;; + "aur") + install_aur_packages "${packages[@]}" + ;; + "flatpak") + install_flatpak_apps "${packages[@]}" + ;; + "snap") + install_snap_packages "${packages[@]}" + ;; + *) + log ERROR "Unknown package type: $pkg_type" + return 1 + ;; + esac +} + +# Setup package managers (install if needed) +setup_package_managers() { + log SECTION "Setting up package managers" + + # Setup Flatpak if not available but potentially useful + if [ "$FLATPAK_AVAILABLE" != "yes" ] && [ "${SYSTEM_INFO[WSL]}" != "yes" ]; then + setup_flatpak + fi + + # Setup Snap for Ubuntu systems if not available + if [ "$PACKAGE_MANAGER" == "apt" ] && [ "$SNAP_AVAILABLE" != "yes" ]; then + setup_snap + fi + + # Install AUR helper for Arch if needed + if [ "$PACKAGE_MANAGER" == "pacman" ] && [ -z "$AUR_HELPER" ]; then + install_aur_helper + fi +} + +# Setup Flatpak +setup_flatpak() { + log INFO "Setting up Flatpak..." + local section_start=$(date +%s) + + ( + case "$PACKAGE_MANAGER" in + "pacman") + sudo pacman --noconfirm --needed -S flatpak + ;; + "apt") + sudo apt install -y flatpak + ;; + esac + + # Add Flathub repository + flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + + # Install Flatseal for permission management + flatpak install -y flathub com.github.tchx84.Flatseal + ) 2>&1 | tee -a "$LOG_FILE" & + + spinner $! "Setting up Flatpak and Flathub repository..." + wait + + FLATPAK_AVAILABLE="yes" + log SUCCESS "Flatpak setup completed $(show_timer $section_start)" +} + +# Setup Snap +setup_snap() { + log INFO "Setting up Snap..." + local section_start=$(date +%s) + + ( + sudo apt install -y snap 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Installing Snap package manager..." + wait + + SNAP_AVAILABLE="yes" + log SUCCESS "Snap setup completed $(show_timer $section_start)" +} + +# Get package manager status +get_package_manager_status() { + echo "Primary: $PACKAGE_MANAGER" + [ -n "$AUR_HELPER" ] && echo "AUR: $AUR_HELPER" + [ "$FLATPAK_AVAILABLE" == "yes" ] && echo "Flatpak: available" + [ "$SNAP_AVAILABLE" == "yes" ] && echo "Snap: available" +} + +# Source guard to prevent double-sourcing +if [ -z "$PACKAGES_LIB_LOADED" ]; then + PACKAGES_LIB_LOADED=true +fi \ No newline at end of file diff --git a/update/lib/roles.sh b/update/lib/roles.sh new file mode 100644 index 0000000..a854f8d --- /dev/null +++ b/update/lib/roles.sh @@ -0,0 +1,332 @@ +#!/bin/bash + +# CMtec Update System - Role Management Library +# Handles role-based installation system + +# Load roles from configuration +load_roles() { + local hostname="${SYSTEM_INFO[HOSTNAME]}" + local distro="${SYSTEM_INFO[DISTRO]}" + + log INFO "Loading role configuration for $hostname ($distro)..." + + # Initialize all roles to "no" + declare -gA ROLES + local all_roles=( + "DESKTOP_BASE" "DESKTOP_WORK" "CODE" "TERMINAL" "HYPERLAND" + "MUSIC" "GAME" "VR" "LAB" "BT" "NVIDIA_GPU" "NVIDIA_1080_GPU" + "WSL" "DEVELOPMENT" "AUDIO_PRODUCTION" + ) + + for role in "${all_roles[@]}"; do + ROLES["$role"]="no" + done + + # Load distro-specific role configuration + local role_config_file="$SCRIPT_DIR/config/${distro}-roles.conf" + if [ -f "$role_config_file" ]; then + source "$role_config_file" + log SUCCESS "Loaded role configuration from $role_config_file" + else + log WARNING "Role configuration file not found: $role_config_file" + # Fall back to hardcoded assignments + assign_default_roles + fi + + # Apply hostname-specific role assignments + assign_hostname_roles "$hostname" + + # Apply auto-detected roles based on system capabilities + assign_auto_detected_roles + + # Validate role dependencies + validate_role_dependencies + + log SUCCESS "Role configuration completed" +} + +# Assign default roles based on system capabilities +assign_default_roles() { + log INFO "Assigning default roles based on system detection..." + + # Basic roles based on system type + case "${SYSTEM_INFO[DISTRO]}" in + "arch") + ROLES["TERMINAL"]="yes" + if supports_feature "desktop"; then + ROLES["DESKTOP_BASE"]="yes" + ROLES["HYPERLAND"]="yes" + fi + ;; + "ubuntu") + ROLES["TERMINAL"]="yes" + if supports_feature "desktop"; then + ROLES["DESKTOP_BASE"]="yes" + fi + ;; + esac + + # WSL-specific roles + if [ "${SYSTEM_INFO[WSL]}" == "yes" ]; then + ROLES["WSL"]="yes" + ROLES["DEVELOPMENT"]="yes" + # Disable desktop-specific roles in WSL + ROLES["DESKTOP_BASE"]="no" + ROLES["HYPERLAND"]="no" + ROLES["GAME"]="no" + ROLES["VR"]="no" + fi + + # GPU-based roles + if [ "${SYSTEM_INFO[NVIDIA_GPU]}" == "yes" ]; then + ROLES["NVIDIA_GPU"]="yes" + if echo "${SYSTEM_INFO[GPU_INFO]:-}" | grep -qi "GTX 1080"; then + ROLES["NVIDIA_1080_GPU"]="yes" + fi + fi + + # Bluetooth support + if [ "${SYSTEM_INFO[BLUETOOTH]}" == "yes" ]; then + ROLES["BT"]="yes" + fi +} + +# Assign hostname-specific roles +assign_hostname_roles() { + local hostname="$1" + + case "$hostname" in + "CMBOX") + ROLES["DESKTOP_BASE"]="yes" + ROLES["DESKTOP_WORK"]="yes" + ROLES["CODE"]="yes" + ROLES["TERMINAL"]="yes" + ROLES["HYPERLAND"]="yes" + ROLES["MUSIC"]="yes" + ;; + "STEAMBOX") + ROLES["GAME"]="yes" + ROLES["VR"]="yes" + ROLES["DESKTOP_BASE"]="yes" + ROLES["NVIDIA_GPU"]="yes" + ROLES["TERMINAL"]="yes" + ROLES["HYPERLAND"]="yes" + ;; + "LABBOX") + ROLES["DESKTOP_BASE"]="yes" + ROLES["CODE"]="yes" + ROLES["TERMINAL"]="yes" + ROLES["HYPERLAND"]="yes" + ROLES["LAB"]="yes" + ROLES["BT"]="yes" + ;; + "SIMONBOX") + ROLES["GAME"]="yes" + ROLES["VR"]="yes" + ROLES["DESKTOP_BASE"]="yes" + ROLES["NVIDIA_1080_GPU"]="yes" + ROLES["TERMINAL"]="yes" + ROLES["HYPERLAND"]="yes" + ROLES["BT"]="yes" + ;; + *) + log INFO "No specific role configuration for hostname: $hostname" + ;; + esac +} + +# Assign roles based on auto-detected system capabilities +assign_auto_detected_roles() { + log INFO "Auto-detecting additional roles based on system capabilities..." + + # Development environment detection + if command_exists git && (command_exists nvim || command_exists vim); then + ROLES["DEVELOPMENT"]="yes" + fi + + # Audio production detection + if [ "${SYSTEM_INFO[AUDIO_SYSTEM]}" == "pipewire" ] && supports_feature "desktop"; then + # Only enable if desktop is available and pipewire is present + if [ "${ROLES[DESKTOP_BASE]}" == "yes" ]; then + # Don't auto-enable audio production, leave it to specific hostname configs + log INFO "Pipewire detected - audio production capabilities available" + fi + fi + + # Gaming detection based on GPU + if [ "${SYSTEM_INFO[NVIDIA_GPU]}" == "yes" ] && supports_feature "desktop"; then + if [ "${ROLES[GAME]}" == "no" ]; then + log INFO "Gaming-capable GPU detected but gaming role not enabled" + fi + fi +} + +# Validate role dependencies and conflicts +validate_role_dependencies() { + log INFO "Validating role dependencies..." + + # Desktop dependencies + local desktop_roles=("DESKTOP_WORK" "GAME" "VR" "MUSIC" "HYPERLAND") + for role in "${desktop_roles[@]}"; do + if [ "${ROLES[$role]}" == "yes" ] && [ "${ROLES[DESKTOP_BASE]}" == "no" ]; then + log WARNING "$role requires DESKTOP_BASE - enabling it" + ROLES["DESKTOP_BASE"]="yes" + fi + done + + # VR requires Gaming + if [ "${ROLES[VR]}" == "yes" ] && [ "${ROLES[GAME]}" == "no" ]; then + log WARNING "VR role requires GAME role - enabling it" + ROLES["GAME"]="yes" + fi + + # NVIDIA GPU roles + if [ "${ROLES[NVIDIA_1080_GPU]}" == "yes" ] && [ "${ROLES[NVIDIA_GPU]}" == "no" ]; then + log WARNING "NVIDIA_1080_GPU requires NVIDIA_GPU - enabling it" + ROLES["NVIDIA_GPU"]="yes" + fi + + # WSL conflicts + if [ "${ROLES[WSL]}" == "yes" ]; then + local wsl_conflicts=("HYPERLAND" "VR") + for role in "${wsl_conflicts[@]}"; do + if [ "${ROLES[$role]}" == "yes" ]; then + log WARNING "$role is not compatible with WSL - disabling it" + ROLES["$role"]="no" + fi + done + fi + + # Container conflicts + if [ "${SYSTEM_INFO[CONTAINER]}" == "yes" ]; then + local container_conflicts=("HYPERLAND" "VR" "GAME" "NVIDIA_GPU") + for role in "${container_conflicts[@]}"; do + if [ "${ROLES[$role]}" == "yes" ]; then + log WARNING "$role is not compatible with containers - disabling it" + ROLES["$role"]="no" + fi + done + fi +} + +# Get enabled roles +get_enabled_roles() { + local enabled_roles=() + for role in "${!ROLES[@]}"; do + if [ "${ROLES[$role]}" == "yes" ]; then + enabled_roles+=("$role") + fi + done + echo "${enabled_roles[@]}" +} + +# Check if a specific role is enabled +role_enabled() { + local role="$1" + [ "${ROLES[$role]}" == "yes" ] +} + +# Get role count +get_role_count() { + local count=0 + for role in "${!ROLES[@]}"; do + if [ "${ROLES[$role]}" == "yes" ]; then + ((count++)) + fi + done + echo $count +} + +# Interactive role selection (if interactive mode is enabled) +interactive_role_selection() { + if [ "$INTERACTIVE" != "true" ]; then + return + fi + + log SECTION "Interactive Role Selection" + echo -e "${YELLOW}Current role configuration:${RESET}" + + local all_roles=($(printf '%s\n' "${!ROLES[@]}" | sort)) + for role in "${all_roles[@]}"; do + local status="${ROLES[$role]}" + local status_icon="${GREEN}${CHECK}${RESET}" + [ "$status" == "no" ] && status_icon="${RED}${CROSS}${RESET}" + echo -e " $status_icon $role" + done + + echo + if confirm "Modify role configuration?"; then + modify_roles_interactively + fi +} + +# Interactive role modification +modify_roles_interactively() { + local all_roles=($(printf '%s\n' "${!ROLES[@]}" | sort)) + + for role in "${all_roles[@]}"; do + local current_status="${ROLES[$role]}" + local opposite_status="yes" + [ "$current_status" == "yes" ] && opposite_status="no" + + if confirm "Toggle $role (currently: $current_status) to $opposite_status?"; then + ROLES["$role"]="$opposite_status" + log INFO "$role toggled to $opposite_status" + fi + done + + # Re-validate after interactive changes + validate_role_dependencies +} + +# Export roles for use in other scripts +export_roles() { + for role in "${!ROLES[@]}"; do + export "ROLE_${role}=${ROLES[$role]}" + done +} + +# Get roles that should be installed by category +get_roles_by_category() { + local category="$1" + local matching_roles=() + + case "$category" in + "desktop") + for role in DESKTOP_BASE DESKTOP_WORK HYPERLAND; do + [ "${ROLES[$role]}" == "yes" ] && matching_roles+=("$role") + done + ;; + "development") + for role in CODE DEVELOPMENT TERMINAL; do + [ "${ROLES[$role]}" == "yes" ] && matching_roles+=("$role") + done + ;; + "gaming") + for role in GAME VR NVIDIA_GPU NVIDIA_1080_GPU; do + [ "${ROLES[$role]}" == "yes" ] && matching_roles+=("$role") + done + ;; + "media") + for role in MUSIC; do + [ "${ROLES[$role]}" == "yes" ] && matching_roles+=("$role") + done + ;; + "hardware") + for role in BT LAB; do + [ "${ROLES[$role]}" == "yes" ] && matching_roles+=("$role") + done + ;; + *) + log WARNING "Unknown role category: $category" + return 1 + ;; + esac + + echo "${matching_roles[@]}" +} + +# Source guard to prevent double-sourcing +if [ -z "$ROLES_LIB_LOADED" ]; then + ROLES_LIB_LOADED=true +fi \ No newline at end of file diff --git a/update/ubuntu/development.sh b/update/ubuntu/development.sh new file mode 100644 index 0000000..63fe5f3 --- /dev/null +++ b/update/ubuntu/development.sh @@ -0,0 +1,146 @@ +#!/bin/bash + +# Ubuntu Development Environment Module + +ubuntu_install_rust() { + log SECTION "Installing Rust toolchain" + local section_start=$(date +%s) + + if confirm "Install Rust via rustup?"; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- --no-modify-path -y + + if [ "${SYSTEM_INFO[WSL]}" == "yes" ]; then + source "$HOME/.cargo/env" + fi + + rustup self update + rustup update stable + rustup default stable + + log SUCCESS "Rust installed $(show_timer $section_start)" + fi +} + +ubuntu_install_node() { + log SECTION "Installing Node.js" + local section_start=$(date +%s) + + if confirm "Install Node.js?"; then + curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash - + install_packages nodejs + npm config set prefix "${HOME}/.npm" + + log SUCCESS "Node.js installed $(show_timer $section_start)" + fi +} + +ubuntu_install_python() { + log SECTION "Setting up Python development" + local section_start=$(date +%s) + + local version="${SYSTEM_INFO[VERSION]}" + if [ "$version" == "22.04" ]; then + pip3 install pynvim + else + install_packages python3-pynvim + fi + + log SUCCESS "Python development setup $(show_timer $section_start)" +} + +ubuntu_build_neovim() { + if ! role_enabled "CODE" && ! role_enabled "DEVELOPMENT"; then + return 0 + fi + + log SECTION "Building Neovim from source" + local section_start=$(date +%s) + + if confirm "Build Neovim from source?"; then + # Remove system neovim if in WSL + if [ "${SYSTEM_INFO[WSL]}" == "yes" ]; then + sudo apt -y purge --auto-remove neovim + fi + + install_packages bat fd-find + + cd ~ + if [ -d ~/neovim ]; then rm -rf ~/neovim; fi + + ( + git clone https://github.com/neovim/neovim + cd neovim && git checkout stable + make CMAKE_BUILD_TYPE=RelWithDebInfo + cd build && cpack -G DEB && sudo dpkg -i nvim*.deb + ) 2>&1 | tee -a "$LOG_FILE" & + + spinner $! "Building Neovim (this will take a while)..." + wait + + if [ -d ~/neovim ]; then rm -rf ~/neovim; fi + + mkdir -p ~/.config/nvim + ln -sf ~/linuxbox/config/nvim/init.lua ~/.config/nvim/init.lua + + log SUCCESS "Neovim built and installed $(show_timer $section_start)" + fi +} + +ubuntu_install_languages() { + log SECTION "Installing programming languages" + local section_start=$(date +%s) + + if confirm "Install additional languages (Go, PHP, Ruby, etc.)?"; then + local packages=(golang ruby ruby-dev php php-curl php-xml php-mbstring luarocks composer) + install_packages "${packages[@]}" + + # Java installation + if [ "${SYSTEM_INFO[WSL]}" == "yes" ]; then + sudo add-apt-repository -y ppa:linuxuprising/java + sudo apt update + install_packages oracle-java17-installer + else + install_packages default-jdk + fi + + log SUCCESS "Programming languages installed $(show_timer $section_start)" + fi +} + +ubuntu_install_julia() { + if ! role_enabled "CODE" && ! role_enabled "DEVELOPMENT"; then + return 0 + fi + + log SECTION "Installing Julia" + local section_start=$(date +%s) + + if confirm "Install Julia programming language?"; then + cd ~ + wget https://julialang-s3.julialang.org/bin/linux/x64/1.9/julia-1.9.0-linux-x86_64.tar.gz + tar -xvzf julia-1.9.0-linux-x86_64.tar.gz + sudo cp -r julia-1.9.0 /opt/ + sudo ln -sf /opt/julia-1.9.0/bin/julia /usr/local/bin/julia + rm julia-1.9.0-linux-x86_64.tar.gz* + rm -rf julia-1.9.0 + + log SUCCESS "Julia installed $(show_timer $section_start)" + fi +} + +ubuntu_setup_development() { + if ! role_enabled "CODE" && ! role_enabled "DEVELOPMENT"; then + return 0 + fi + + ubuntu_install_rust + ubuntu_install_node + ubuntu_install_python + ubuntu_build_neovim + ubuntu_install_languages + ubuntu_install_julia +} + +if [ -z "$UBUNTU_DEVELOPMENT_LOADED" ]; then + UBUNTU_DEVELOPMENT_LOADED=true +fi \ No newline at end of file diff --git a/update/ubuntu/system.sh b/update/ubuntu/system.sh new file mode 100644 index 0000000..ff00406 --- /dev/null +++ b/update/ubuntu/system.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +# Ubuntu Linux System Setup Module + +ubuntu_install_system_base() { + log SECTION "Installing Ubuntu system base packages" + local section_start=$(date +%s) + + if confirm "Install essential system packages?"; then + local packages=( + build-essential gawk imagemagick gpg ninja-build gettext cmake unzip curl + libssl-dev libffi-dev file libudev-dev pkg-config locales btop ncdu + ranger timeshift python3 python3-pip python3-venv python3-dev pipx + ) + + install_packages "${packages[@]}" + log SUCCESS "System base packages installed $(show_timer $section_start)" + fi +} + +ubuntu_install_homebrew() { + log SECTION "Installing Homebrew" + local section_start=$(date +%s) + + if confirm "Install Homebrew package manager?"; then + export NONINTERACTIVE=1 + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + + BREW_PREFIX="/home/linuxbrew/.linuxbrew" + if [ -d "$BREW_PREFIX" ]; then + eval "$("$BREW_PREFIX"/bin/brew shellenv)" + log SUCCESS "Homebrew installed $(show_timer $section_start)" + else + log ERROR "Homebrew installation failed" + return 1 + fi + fi +} + +ubuntu_setup_locale() { + log SECTION "Setting up locale" + sudo locale-gen "en_US.UTF-8" + sudo update-locale LANG=en_US.UTF-8 +} + +ubuntu_setup_shell_config() { + log SECTION "Setting up shell configuration" + + if [ "${SYSTEM_INFO[WSL]}" == "yes" ]; then + ln -sf ~/linuxbox/bashrc_ubuntu ~/.bashrc + ln -sf ~/linuxbox/gitconfig.work ~/.gitconfig + else + ln -sf ~/linuxbox/bashrc_ubuntu ~/.bashrc + ln -sf ~/linuxbox/gitconfig ~/.gitconfig + + mkdir -p ~/.config/alacritty + ln -sf ~/linuxbox/config/alacritty/alacritty.toml ~/.config/alacritty/alacritty.toml + fi + + mkdir -p ~/.local/bin + ln -sf ~/linuxbox/update_wrapper.sh ~/.local/bin/update + ln -sf ~/linuxbox/start_nvim.sh ~/.local/bin/start_nvim + ln -sf ~/linuxbox/start_toolbox.sh ~/.local/bin/start_toolbox +} + +ubuntu_setup_system() { + ubuntu_setup_locale + ubuntu_install_system_base + ubuntu_install_homebrew + ubuntu_setup_shell_config +} + +if [ -z "$UBUNTU_SYSTEM_LOADED" ]; then + UBUNTU_SYSTEM_LOADED=true +fi \ No newline at end of file diff --git a/update/ubuntu/ubuntu.sh b/update/ubuntu/ubuntu.sh new file mode 100644 index 0000000..bad851c --- /dev/null +++ b/update/ubuntu/ubuntu.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Ubuntu Linux Master Module +# Loads all Ubuntu-specific modules and orchestrates installation + +# Source all Ubuntu modules +source "$SCRIPT_DIR/ubuntu/system.sh" +source "$SCRIPT_DIR/ubuntu/development.sh" + +# Main Ubuntu installation function +ubuntu_install_all() { + log SECTION "Starting Ubuntu Linux installation" + + # System setup (homebrew, base packages) + ubuntu_setup_system + + # Development environment (custom builds, languages) + ubuntu_setup_development + + # Note: Terminal, desktop, etc. would be added here + # For now, focusing on the core differences + + log SUCCESS "Ubuntu Linux installation completed" +} + +# Source guard +if [ -z "$UBUNTU_MASTER_LOADED" ]; then + UBUNTU_MASTER_LOADED=true +fi \ No newline at end of file diff --git a/update/update.sh b/update/update.sh new file mode 100755 index 0000000..8cd59b4 --- /dev/null +++ b/update/update.sh @@ -0,0 +1,193 @@ +#!/bin/bash + +# CMtec Universal Update System v3.0.0 +# Main entry point for cross-platform system updates + +set -e + +# Get script directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Parse command line arguments +INTERACTIVE=false +HELP=false + +while [[ $# -gt 0 ]]; do + case $1 in + -i|--interactive) + INTERACTIVE=true + shift + ;; + -h|--help) + HELP=true + shift + ;; + *) + echo "Unknown option: $1" + echo "Usage: $0 [-i|--interactive] [-h|--help]" + exit 1 + ;; + esac +done + +if [ "$HELP" == "true" ]; then + echo "CMtec Universal Update System v3.0.0" + echo "" + echo "Usage: $0 [OPTIONS]" + echo "" + echo "OPTIONS:" + echo " -i, --interactive Enable interactive mode with confirmations" + echo " -h, --help Show this help message" + echo "" + echo "This script automatically detects your Linux distribution and applies" + echo "appropriate updates and software installations based on system roles." + exit 0 +fi + +# Source all library files +source "$SCRIPT_DIR/lib/core.sh" +source "$SCRIPT_DIR/lib/detect.sh" +source "$SCRIPT_DIR/lib/roles.sh" +source "$SCRIPT_DIR/lib/packages.sh" + +# Initialize core system +init_core + +# Ensure sudo access +sudo -v + +# Detect system and hardware +detect_system +detect_hardware + +# Show fancy distro-specific header +case "${SYSTEM_INFO[DISTRO]}" in + "arch") + show_arch_header "${SYSTEM_INFO[HOSTNAME]}" + ;; + "ubuntu"|"debian") + show_ubuntu_header "${SYSTEM_INFO[HOSTNAME]}" + ;; + *) + show_header "${SYSTEM_INFO[HOSTNAME]}" "${SYSTEM_INFO[PRETTY_NAME]}" + ;; +esac + +# Load and configure roles +load_roles + +# Show system configuration +show_roles + +# Run system health check +system_health_check + +# Interactive confirmation +if [ "$INTERACTIVE" == "true" ]; then + if ! confirm "Proceed with system update?"; then + log INFO "Update cancelled by user" + exit 0 + fi + interactive_role_selection +fi + +echo -e "${GREEN}${CHECK} Starting update process...${RESET}\n" + +# Initialize package managers +init_package_managers +setup_package_managers + +# Create backup if timeshift is available +if package_installed timeshift; then + section_start=$(date +%s) + log SECTION "Creating system snapshot" + if confirm "Create Timeshift snapshot before update?"; then + ( + sudo timeshift --create --comments "Universal update script $(date '+%Y-%m-%d %H:%M:%S')" 2>&1 | tee -a "$LOG_FILE" + ) & + spinner $! "Creating system snapshot..." + wait + log SUCCESS "System snapshot created $(show_timer $section_start)" + else + log WARNING "System snapshot skipped" + fi +else + log WARNING "Timeshift not installed - no system snapshot created" +fi + +# Update package databases and perform system upgrade +update_package_databases +system_upgrade + +# Update AUR packages (Arch only) +if [ "$PACKAGE_MANAGER" == "pacman" ]; then + update_aur_packages +fi + +# Update Flatpak and Snap packages +update_flatpak_apps +[ "$PACKAGE_MANAGER" == "apt" ] && update_snap_packages + +# Install basic system packages +log SECTION "Installing essential system packages" +case "${SYSTEM_INFO[DISTRO]}" in + "arch") + install_packages base-devel linux-headers git bc cmake gawk wget gettext unzip curl inetutils python python-pip python-pipx rustup + ;; + "ubuntu"|"debian") + install_packages build-essential git gawk imagemagick gpg ninja-build gettext cmake unzip curl libssl-dev libffi-dev file libudev-dev pkg-config locales btop ncdu ranger timeshift + ;; +esac + +# Create symbolic links for configuration files +log SECTION "Setting up configuration links" +mkdir -p ~/.local/bin ~/.config + +# Link bash configuration +case "${SYSTEM_INFO[DISTRO]}" in + "arch") + ln -sf ~/linuxbox/bashrc_arch ~/.bashrc + ;; + "ubuntu"|"debian") + if [ "${SYSTEM_INFO[WSL]}" == "yes" ]; then + ln -sf ~/linuxbox/bashrc_ubuntu ~/.bashrc + ln -sf ~/linuxbox/gitconfig.work ~/.gitconfig + else + ln -sf ~/linuxbox/bashrc_ubuntu ~/.bashrc + ln -sf ~/linuxbox/gitconfig ~/.gitconfig + fi + ;; +esac + +# Link common configuration files +ln -sf ~/linuxbox/update_wrapper.sh ~/.local/bin/update + +# Set locale +case "${SYSTEM_INFO[DISTRO]}" in + "arch") + sudo localectl set-locale LANG=en_US.UTF-8 + ;; + "ubuntu"|"debian") + sudo locale-gen "en_US.UTF-8" || true + sudo update-locale LANG=en_US.UTF-8 || true + ;; +esac + +# Load and run distro-specific installation +case "${SYSTEM_INFO[DISTRO]}" in + "arch") + source "$SCRIPT_DIR/arch/arch.sh" + arch_install_all + ;; + "ubuntu"|"debian") + source "$SCRIPT_DIR/ubuntu/ubuntu.sh" + ubuntu_install_all + ;; + *) + log ERROR "Unsupported distribution: ${SYSTEM_INFO[DISTRO]}" + exit 1 + ;; +esac + +# Final summary and reboot prompt +show_final_summary \ No newline at end of file