From a6243585ba861c80d19f5f135170204e22bfc346 Mon Sep 17 00:00:00 2001 From: srdusr Date: Tue, 30 Sep 2025 11:50:05 +0200 Subject: Various changes, fixed .zshenv initializing properly, updated install.sh/packages.yml (testing shell-git invocation/make tmp and re-exec with bash) --- common/.profile | 164 +++++++++++++++++++----------------------- common/.zshenv | 2 + common/.zshrc | 10 --- common/install.sh | 200 ++++++++++++++++++++++++++++++++++++++++++++++++---- common/packages.yml | 14 ++-- 5 files changed, 268 insertions(+), 122 deletions(-) mode change 100644 => 100755 common/.profile create mode 100644 common/.zshenv delete mode 100644 common/.zshrc diff --git a/common/.profile b/common/.profile old mode 100644 new mode 100755 index b847d6c..53703b7 --- a/common/.profile +++ b/common/.profile @@ -1,102 +1,84 @@ #!/bin/bash - -#~/.profile - -# ====================================== -# Basic environment setup -# ====================================== - -export EDITOR="$(command -v nvim || command -v vim || echo nano)" - -# Load zsh env if running zsh -if [ -n "$ZSH_VERSION" ] && [ -f "$HOME/.config/zsh/.zshenv" ]; then - . "$HOME/.config/zsh/.zshenv" -fi - -cd "$HOME" || exit 1 - # ====================================== # Session launcher # ====================================== -# Detect graphical DE session -if [ -n "$DISPLAY" ]; then - #echo "Graphical session detected ($XDG_SESSION_DESKTOP). Skipping auto TTY session launch." - return -fi - -# Only run on first virtual terminal -if [ -z "$XDG_VTNR" ] || [ "$XDG_VTNR" -ne 1 ]; then - return -fi - -# Clean environment -unset DISPLAY XAUTHORITY DBUS_SESSION_BUS_ADDRESS - -# Priority-ordered list of sessions (WM/DE) -sessions=( - "Hyprland" - "bspwm" - "sway" - "gnome-session" - "startplasma-x11" - "startxfce4" - "openbox" - "i3" -) - -# Handle saved session -if [ -f "$HOME/.session" ]; then - chosen_session=$(<"$HOME/.session") - rm -f "$HOME/.session" -fi - -# Start a session start_session() { - local s="$1" - case "$s" in - bspwm) - export XDG_SESSION_TYPE="x11" - exec startx /usr/bin/bspwm - ;; - Hyprland|sway) - #exec dbus-launch --sh-syntax --exit-with-session "$s" - exec dbus-launch --sh-syntax --exit-with-session "$s" >/dev/null 2>&1 - ;; - gnome-session|startplasma-x11|startxfce4|openbox|i3) - exec "$s" - ;; - *) - return 1 - ;; - esac -} - -# Try saved session first -if [ -n "$chosen_session" ]; then - if start_session "$chosen_session"; then - exit - else - echo "Saved session '$chosen_session' not found. Falling back..." + # Clean environment + unset DISPLAY XAUTHORITY DBUS_SESSION_BUS_ADDRESS + + # Priority-ordered list of sessions (WM/DE) + sessions=( + "Hyprland" + "bspwm" + "sway" + "gnome-session" + "startplasma-x11" + "startxfce4" + "openbox" + "i3" + ) + + # Handle saved session + if [ -f "$HOME/.session" ]; then + chosen_session=$(<"$HOME/.session") + rm -f "$HOME/.session" fi -fi -# Try default sessions in priority -for wm in "${sessions[@]}"; do - if command -v "$wm" >/dev/null 2>&1; then - echo "Starting session: $wm" - start_session "$wm" - exit + launch_session() { + local s="$1" + case "$s" in + bspwm) + export XDG_SESSION_TYPE="x11" + exec startx /usr/bin/bspwm + ;; + Hyprland|sway) + exec dbus-launch --sh-syntax --exit-with-session "$s" >/dev/null 2>&1 + ;; + gnome-session|startplasma-x11|startxfce4|openbox|i3) + exec "$s" + ;; + *) + return 1 + ;; + esac + } + + # Try saved session first + if [ -n "$chosen_session" ]; then + if launch_session "$chosen_session"; then + exit + else + echo "Saved session '$chosen_session' not found. Falling back..." + fi fi -done -# Fallback: Check for common display managers (GDM/LightDM/SDDM) -for dm in gdm lightdm sddm; do - if command -v "$dm" >/dev/null 2>&1; then - echo "Launching display manager: $dm" - exec "$dm" - fi -done + # Try default sessions in priority + for wm in "${sessions[@]}"; do + if command -v "$wm" >/dev/null 2>&1; then + echo "Starting session: $wm" + launch_session "$wm" + exit + fi + done + + # Fallback: Check for common display managers + for dm in gdm lightdm sddm; do + if command -v "$dm" >/dev/null 2>&1; then + echo "Launching display manager: $dm" + exec "$dm" + fi + done + + echo "No suitable window manager or display manager found." + exit 1 +} -echo "No suitable window manager or display manager found." -exit 1 +# ------------------------- +# Only run session loader when: +# - No DISPLAY (not inside an existing GUI) +# - On first VT (tty1) +# ------------------------- +if [ -z "$DISPLAY" ] && [ -n "$XDG_VTNR" ] && [ "$XDG_VTNR" -eq 1 ]; then + start_session +fi diff --git a/common/.zshenv b/common/.zshenv new file mode 100644 index 0000000..12b221e --- /dev/null +++ b/common/.zshenv @@ -0,0 +1,2 @@ +ZDOTDIR="$HOME/.config/zsh" +source -- "$ZDOTDIR/.zshenv" diff --git a/common/.zshrc b/common/.zshrc deleted file mode 100644 index bd22e32..0000000 --- a/common/.zshrc +++ /dev/null @@ -1,10 +0,0 @@ -# ~/.zshrc -[[ -f ~/.config/zsh/.zshrc ]] && source ~/.config/zsh/.zshrc - -# Point all zsh startup files to ~/.config/zsh -export ZDOTDIR="$HOME/.config/zsh" - -# If you want, you can still source your real zshenv from there: -if [[ -f "$ZDOTDIR/.zshenv" ]]; then - source "$ZDOTDIR/.zshenv" -fi diff --git a/common/install.sh b/common/install.sh index 6ef2787..4f531bf 100755 --- a/common/install.sh +++ b/common/install.sh @@ -4,10 +4,18 @@ # Created On: Tue 06 Sep 2025 16:20:52 PM CAT # Project: Dotfiles installation script -# TODO: allow optional change user/password, also optional change root password, first check if they are the same (auto) - # Dependencies: git, curl +# POSIX-compatible shim: if not running under bash (e.g., invoked via `sh -c "$(curl ...)"`), +# re-exec the remainder of this script with bash. +if [ -z "${BASH_VERSION:-}" ]; then + tmp="$(mktemp)" || exit 1 + # Read the rest of the script into a temp file, then exec bash on it + cat > "$tmp" + exec bash "$tmp" "$@" + exit 1 +fi + set -euo pipefail # Exit on error, undefined vars, pipe failures #====================================== @@ -140,6 +148,7 @@ declare -A INSTALLATION_STEPS=( ["install_dependencies"]="Install dependencies" ["install_dotfiles"]="Install dotfiles repository" ["setup_user_dirs"]="Setup user directories" + ["setup_passwords"]="Setup user and root passwords (optional)" ["install_essentials"]="Install essential tools" ["install_packages"]="Install system packages" ["setup_shell"]="Setup shell environment" @@ -159,6 +168,7 @@ STEP_ORDER=( "install_dotfiles" "deploy_config" "setup_user_dirs" + "setup_passwords" "install_essentials" "install_packages" "setup_shell" @@ -525,7 +535,18 @@ detect_package_manager() { # Find packages.yml in standard locations local original_dir="$PWD" cd "$HOME" 2>/dev/null || true - local packages_files=("$PACKAGES_FILE" "common/$PACKAGES_FILE" ".cfg/common/$PACKAGES_FILE") + # Search common locations for packages.yml, including repo-local and script directory + local __script_dir + __script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" + local packages_files=( + "$PACKAGES_FILE" \ + "common/$PACKAGES_FILE" \ + ".cfg/common/$PACKAGES_FILE" \ + "$__script_dir/../packages.yml" \ + "$__script_dir/packages.yml" \ + "$DOTFILES_DIR/common/$PACKAGES_FILE" \ + "$DOTFILES_DIR/packages.yml" + ) local found_packages_file="" for pf in "${packages_files[@]}"; do if [[ -f "$pf" ]]; then @@ -535,17 +556,54 @@ detect_package_manager() { done cd "$original_dir" 2>/dev/null || true + # Optionally merge a profile overlay packages.yml over the base file + local merged_packages_file="" if command_exists yq && [[ -n "$found_packages_file" ]]; then + local overlay_candidates=( + "$HOME/.cfg/profile/$INSTALL_MODE/packages.yml" + "$HOME/profile/$INSTALL_MODE/packages.yml" + "$__script_dir/../profile/$INSTALL_MODE/packages.yml" + "$__script_dir/profile/$INSTALL_MODE/packages.yml" + "$DOTFILES_DIR/profile/$INSTALL_MODE/packages.yml" + ) + local overlay_file="" + for opf in "${overlay_candidates[@]}"; do + [[ -f "$opf" ]] && { overlay_file="$opf"; break; } + done + if [[ -n "$overlay_file" ]]; then + merged_packages_file="$(mktemp)" + if yq eval-all 'select(fileIndex==0) * select(fileIndex==1)' "$found_packages_file" "$overlay_file" >"$merged_packages_file" 2>/dev/null; then + print_info "Using merged packages.yml (base + profile overlay: $INSTALL_MODE)" + else + print_warning "Failed to merge profile packages overlay; using base packages.yml" + rm -f "$merged_packages_file" 2>/dev/null || true + merged_packages_file="" + fi + fi + fi + + # If we have a resolved file, set PACKAGES_FILE to its absolute path for downstream steps + if [[ -n "$found_packages_file" ]]; then + if [[ -n "$merged_packages_file" ]]; then + PACKAGES_FILE="$merged_packages_file" + else + # Canonical absolute path + PACKAGES_FILE="$(cd "$(dirname "$found_packages_file")" && pwd -P)/$(basename "$found_packages_file")" + fi + export PACKAGES_FILE + fi + + if command_exists yq && [[ -n "${merged_packages_file:-$found_packages_file}" ]]; then # Prefer distro block, fallback to manager block # Initialize to avoid set -u (nounset) issues before assignment local pm_update="" pm_install="" if [[ -n "$DISTRO" ]]; then - pm_update=$(yq eval ".package_managers.${DISTRO}.update" "$found_packages_file" 2>/dev/null | grep -v "^null$" || echo "") - pm_install=$(yq eval ".package_managers.${DISTRO}.install" "$found_packages_file" 2>/dev/null | grep -v "^null$" || echo "") + pm_update=$(yq eval ".package_managers.${DISTRO}.update" "${merged_packages_file:-$found_packages_file}" 2>/dev/null | grep -v "^null$" || echo "") + pm_install=$(yq eval ".package_managers.${DISTRO}.install" "${merged_packages_file:-$found_packages_file}" 2>/dev/null | grep -v "^null$" || echo "") fi if [[ -z "$pm_update" || -z "$pm_install" ]]; then - pm_update=$(yq eval ".package_managers.${PACKAGE_MANAGER}.update" "$found_packages_file" 2>/dev/null | grep -v "^null$" || echo "") - pm_install=$(yq eval ".package_managers.${PACKAGE_MANAGER}.install" "$found_packages_file" 2>/dev/null | grep -v "^null$" || echo "") + pm_update=$(yq eval ".package_managers.${PACKAGE_MANAGER}.update" "${merged_packages_file:-$found_packages_file}" 2>/dev/null | grep -v "^null$" || echo "") + pm_install=$(yq eval ".package_managers.${PACKAGE_MANAGER}.install" "${merged_packages_file:-$found_packages_file}" 2>/dev/null | grep -v "^null$" || echo "") fi if [[ -n "$pm_update" && -n "$pm_install" ]]; then PACKAGE_UPDATE_CMD="$pm_update" @@ -2110,6 +2168,119 @@ setup_user_dirs() { mark_step_completed "setup_user_dirs" } +setup_passwords() { + print_section "Setting Up Passwords (Optional)" + save_state "setup_passwords" "started" + + if [[ "$ASK_MODE" != true && "$FORCE_MODE" != true ]]; then + print_info "Skipping password setup (non-interactive). Use --ask to be prompted." + mark_step_completed "setup_passwords" + return 0 + fi + + # Change current user password + if prompt_user "Change password for user '$USER'?" "N"; then + print_color "$YELLOW" "Enter new password for $USER: " + read -rs __pw_user; echo + print_color "$YELLOW" "Confirm new password for $USER: " + read -rs __pw_user2; echo + if [[ "$__pw_user" == "$__pw_user2" && -n "$__pw_user" ]]; then + if execute_with_privilege "bash -lc 'echo \"$USER:$__pw_user\" | chpasswd'"; then + print_success "Password updated for $USER" + else + print_error "Failed to update password for $USER" + fi + else + print_warning "Passwords did not match; skipping $USER" + fi + unset __pw_user __pw_user2 + else + print_skip "User password change (skipped)" + fi + + # Change root password + if prompt_user "Change password for 'root'?" "N"; then + print_color "$YELLOW" "Enter new password for root: " + read -rs __pw_root; echo + print_color "$YELLOW" "Confirm new password for root: " + read -rs __pw_root2; echo + if [[ "$__pw_root" == "$__pw_root2" && -n "$__pw_root" ]]; then + if execute_with_privilege "bash -lc 'echo \"root:$__pw_root\" | chpasswd'"; then + print_success "Password updated for root" + else + print_error "Failed to update password for root" + fi + else + print_warning "Passwords did not match; skipping root" + fi + unset __pw_root __pw_root2 + else + print_skip "Root password change (skipped)" + fi + + mark_step_completed "setup_passwords" +} + +# Safely sync a system file with backup. Usage: sync_system_file_with_backup /etc/target /path/to/source +sync_system_file_with_backup() { + local target="$1" src="$2" + if [[ -z "$target" || -z "$src" ]]; then + print_error "sync_system_file_with_backup: missing arguments" + return 1 + fi + if [[ ! -f "$src" ]]; then + print_error "Source file not found: $src" + return 1 + fi + local backup="${target}.bak.$(date +%Y%m%d-%H%M%S)" + run_privileged "mkdir -p '$(dirname "$target")'" || return 1 + if run_privileged "test -f '$target'"; then + run_privileged "cp -a '$target' '$backup'" || return 1 + print_info "Backed up $target to $backup" + fi + run_privileged "install -m 644 '$src' '$target'" && print_success "Updated $target" +} + +# Pre-install essentials (git, curl) early if missing +preinstall_essentials() { + local need_any=false + command_exists git || need_any=true + command_exists curl || need_any=true + if [[ "$need_any" != true ]]; then + return 0 + fi + detect_os + detect_package_manager || return 1 + update_package_database || true + local ok=true + command_exists git || install_single_package git dependency || ok=false + command_exists curl || install_single_package curl dependency || ok=false + [[ "$ok" == true ]] +} + +## Privileged file helpers (Utility) +# Ensure a line exists in a file (exact match). Creates file and parent dir if needed. Uses privilege. +ensure_line_in_file_privileged() { + local file="$1" + local line="$2" + + # Create parent dir if needed + local dir + dir="$(dirname "$file")" + run_privileged "mkdir -p '$dir'" || return 1 + + # Create file if missing + run_privileged "touch '$file'" || return 1 + + # Check exact line presence + if run_privileged "grep -Fqx -- '$(printf %s "$line" | sed "s/'/'\\''/g")' '$file'"; then + return 0 + fi + + # Append safely + run_privileged "printf '%s\n' '$(printf %s "$line" | sed "s/'/'\\''/g")' >> '$file'" +} + install_essentials() { print_section "Installing Essential Tools" save_state "install_essentials" "started" @@ -2351,8 +2522,6 @@ setup_shell() { mark_step_completed "setup_shell" } -## install_zsh_plugins deprecated; handled via packages.yml - setup_ssh() { print_section "Setting Up SSH" save_state "setup_ssh" "started" @@ -3718,13 +3887,14 @@ trap handle_interrupt INT # Execute main if script is run directly if [[ "${BASH_SOURCE[0]-}" == "$0" ]]; then - # Check basic requirements - for req in git curl; do - if ! command_exists "$req"; then - print_error "$req is required but not installed" + # Ensure basic requirements (attempt auto-install if possible) + if ! command_exists git || ! command_exists curl; then + print_warning "git/curl missing; attempting to install prerequisites" + preinstall_essentials || { + print_error "Required tools git/curl are not installed and could not be auto-installed" exit 1 - fi - done + } + fi main "$@" fi diff --git a/common/packages.yml b/common/packages.yml index 0fce986..2aa435f 100644 --- a/common/packages.yml +++ b/common/packages.yml @@ -1,6 +1,10 @@ # Dotfiles Installation Packages Configuration # This file defines packages to install based on installation profiles and distribution-specific mappings +# TODO: +# tree-sitter-cli +# make sure rust is installed, go pipx virtualenvwrapper + #====================================== # Installation Profiles #====================================== @@ -214,7 +218,6 @@ fedora: hdparm: hdparm acpi: acpi parted: parted - cups: cups sysstat: sysstat hwinfo: hwinfo @@ -254,7 +257,6 @@ rhel: hdparm: hdparm acpi: acpi parted: parted - cups: cups sysstat: sysstat opensuse: @@ -319,7 +321,6 @@ gentoo: hdparm: sys-apps/hdparm acpi: sys-power/acpi parted: sys-block/parted - cups: net-print/cups sysstat: app-admin/sysstat hwinfo: sys-apps/hwinfo hack-font: media-fonts/hack @@ -553,11 +554,11 @@ gentoo_use_flags: openssh: "ssl kerberos ldap pam" firefox: "dbus gtk3 pulseaudio startup-notification wifi" mpv: "alsa pulseaudio lua drm wayland X" - gtk: "wayland X cups introspection" + gtk: "wayland X introspection" pipewire: "alsa bluetooth jack pulseaudio sound-server" ffmpeg: "alsa encode mp3 opus pulseaudio theora vorbis webp x264 x265" networkmanager: "bluetooth dhclient introspection wifi" - bluez: "alsa cups obex readline" + bluez: "alsa obex readline" qemu: "aio alsa bluetooth curl gtk jpeg ncurses opengl png pulseaudio sdl spice ssh usb vnc" libvirt: "firewalld libssh nfs numa parted qemu sasl udev" @@ -814,7 +815,6 @@ services: - chronyd desktop: - bluetooth - - cups disable: server: - bluetooth @@ -845,9 +845,11 @@ development: - typescript - eslint - prettier + - tree-sitter-cli python: global_packages: + - pipx - black - flake8 - mypy -- cgit v1.2.3