From 6b92f7a0a06c118b0ff0abcd1e774e818b013764 Mon Sep 17 00:00:00 2001 From: "Gu://em_" Date: Mon, 4 May 2026 22:57:12 +0200 Subject: [PATCH] fix: New README, new documentation for developpers, and many install.sh and update.sh fixes --- README.md | 103 +++++++++++++++++++++++++---------- doc/Developpers.md | 57 ++++++++++++++++++++ packages/optional.groups | 0 scripts/install.sh | 114 +++++++++++++++++++++++++++++++++++---- scripts/update.sh | 53 +++++++++++++++--- 5 files changed, 282 insertions(+), 45 deletions(-) create mode 100644 doc/Developpers.md create mode 100644 packages/optional.groups diff --git a/README.md b/README.md index 4880934..8367b7d 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,99 @@ -# Atlas Desktop installer +# Atlas Desktop -This project is an automated installer for the Atlas Desktop. +A fully automated Archlinux setup for people that care about their computer. -## Disclaimer +```sh +curl -fsSL https://forge.oblic-parallels.fr/guillm/atlas-desktop/raw/branch/main/scripts/install.sh | bash +``` -### ⚠ Use at your own risk. -Some platforms may not yet be supported such as Nvidia graphic cards for which you'll have to install all the drivers yourself. Sadly I don't have any equipment to test that out. - -Also you will very probably miss some software you're used to. I'll strongly recommend you to check the [Additionnal packages](https://hedgedoc.oblic-parallels.fr/s/JSR33pjd_#Additional-packages) section to know about some open source utilities that fit perfectly within the desktop. -More generally give a look to the [Quick start guide](https://hedgedoc.oblic-parallels.fr/s/JSR33pjd_) - -If something doesn't work or behaves anormally don't hesitate to contact me so that it will be fixed for future users. +## What's included + +- **Window manager**: Hyprland +- **Status bar**: Waybar +- **Display manager**: Ly +- **Launcher**: Rofi +- **Notifications center**: Swaync +- **Terminal**: Foot +- **Shell**: Zsh + Zinit + Powerlevel10k ## Requirements -You'll just need an already functional (even basic) **Arch Linux** system with `sudo` installed. -Setup will take care of configuring AppArmor and Zram if it hasn't been done yet. +- A basic Arch Linux install (cli is enough, no DE required) +- A user account with `sudo` access +- `git` installed (`sudo pacman -Sy git`) +- Internet connection + +Setup will take care of configuring AppArmor and Zram or even firewall if you haven't done it yet. + +## Installation + +**Disclaimer**: Some platforms may not yet be supported such as Nvidia graphic cards for which you'll have to install all the drivers yourself. Sadly I don't have any equipment to test that out. -## Usage - -Very simple, clone the project (or download it directly from the web interface) -```sh= -git clone https://forge.oblic-parallels.fr/guillm/atlas-install +```sh +curl -fsSL https://forge.oblic-parallels.fr/guillm/atlas-desktop/raw/branch/main/scripts/install.sh | bash ``` -And run `setup.sh` -```sh= -./setup.sh -``` - Then just follow the instructions and you should be good to go ! -If you encounter any error or bug, don't hesitate to open an issue on this repo. +After the setup finishes you may need to reboot in order to login: +```sh +sudo reboot +``` + +> **Note**: If you encounter any error or bug, don't hesitate to open an issue on this repo. + +> **Note:** After installation the original clone is no longer needed. +> `~/.dotfiles` is the real repo and is what the updater tracks. + ## Configuration -I suggest you to give a look to the packages that will be installed on your system as it's important to know how things will work or to disable some things you wouldn't necessarely want. -I particularly think of helix which is used as the default text editor but may not suit some people needs. +I suggest you to give a look to the [Quick start guide](https://hedgedoc.oblic-parallels.fr/s/JSR33pjd_) that explains how the system works if you're not used to it. +As you will very probably miss some software you're used to. I'll strongly recommend you to check the [Additionnal packages](https://hedgedoc.oblic-parallels.fr/s/JSR33pjd_#Additional-packages) section to know about some open source utilities that fit perfectly within the desktop. Note that the default keyboard layout is QWERTY (us-fr). You can switch with the AZERTY layout by using `Mod+Ctrl+Space`. That said, the default layout already has french accents if you need them. If you need to modify the layout, go to `~/.config/hypr/config/default/kb_layouts`. -### Defaults -I'm working on a system to easily change the default programs. I don't know yet if it will result into anything but it's worth trying. +## Staying up to date + +```sh +atlas-update +``` + +This will: + +- Fetch origin/main and show new commits +- Detect conflicts between upstream changes and local edits, asking you which to keep per file +- Pull and re-stow config/ +- Re-prompt for any new optional groups added upstream + + +## Troubleshooting + +**Stow reports conflicts on first install** +- Existing real files that clash with stow links are automatically renamed to `.bak`. + +**An AUR package failed to install** +- The installer reports it and continues. It won't be saved to state, so `atlas-update` will retry it next run. + +**`atlas-update` says "already up to date" but a package is missing** +- Delete its state file to force a re-sync: +```bash +rm ~/.atlas-dotfiles/.state/packages/mygroup.pkgs +atlas-update +``` + +**Waybar doesn't reload after switching layout** +- Reload desktop using `Mod+Shift+R` or run the following command: +```bash +pkill waybar && waybar & +``` + ## Future improvements +- Waybar switch script +- A defaults system allowing you to easily choose your default programs - Nvidia cards handling -- Cleaner way to enable/disable some packages / configuratuions diff --git a/doc/Developpers.md b/doc/Developpers.md new file mode 100644 index 0000000..a965e50 --- /dev/null +++ b/doc/Developpers.md @@ -0,0 +1,57 @@ +# Developpers documentation + +## Repository structure + +``` +dotfiles/ +├── install.sh +├── scripts/ +│ └── update.sh ← dotfiles-update +├── packages/ +│ ├── core.pkgs ← always installed +│ ├── desktop.pkgs ← always installed (automatic) +│ ├── aur.pkgs ← AUR packages (paru) +│ ├── intel-cpu.pkgs ← auto: Intel CPU +│ ├── amd-cpu.pkgs ← auto: AMD CPU +│ ├── intel-gpu.pkgs ← auto: Intel GPU +│ ├── amd-gpu.pkgs ← auto: AMD GPU +│ ├── nvidia.pkgs ← auto: NVIDIA GPU +│ ├── gaming.pkgs ← optional +│ ├── development.pkgs ← optional +│ ├── ... +│ ├── optional.groups ← lists which groups are optional +│ └── .desc ← one-line description shown in installer +└── config/ ← stow package; mirrors $HOME + ├── .config/ + │ ├── hypr/ + │ ├── waybar/ + │ │ ├── vertical/ + │ │ └── horizontal/ + │ ├── rofi/ + │ └── ... + └── .local/ + └── bin/ + └── atlas-update +``` + +### Package group conventions + +| File | When installed | +|---|---| +| `core.pkgs` | Always | +| Any unlisted `*.pkgs` (e.g. `desktop.pkgs`) | Always (automatic) | +| `aur.pkgs` | Always, via paru | +| `intel-gpu.pkgs`, `amd-gpu.pkgs`, etc. | Auto-detected via `lspci` / `/proc/cpuinfo` | +| Groups listed in `optional.groups` | User-chosen during install, remembered on updates | + +To add a new automatic group: create `packages/mygroup.pkgs` and commit. +To add a new optional group: also add its name to `packages/optional.groups` and optionally a `packages/mygroup.desc` one-liner. + + +## Package state tracking + +After each install or update, a snapshot of every installed group is saved to `~/.dotfiles/.state/packages/`. On the next run, each group is diffed: + +- **New packages** in the `.pkgs` file → installed automatically +- **Removed packages** → you are asked before uninstalling +Delete `~/.dotfiles/.state/` to reset all state and force a full reinstall on the next update. diff --git a/packages/optional.groups b/packages/optional.groups new file mode 100644 index 0000000..e69de29 diff --git a/scripts/install.sh b/scripts/install.sh index cdf931a..e4b1cfc 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -497,6 +497,9 @@ install_packages() { local pkg_file pkgs group # Helper: install a group and save state + # Note: AUR packages are installed one-by-one so a single failure does not abort + # the whole group. Official repo packages are bulk-installed with a per- + # package fallback. Only successfully installed packages are saved to state. install_group() { local group="$1" local pkg_file="$PACKAGES_DIR/${group}.pkgs" @@ -506,25 +509,114 @@ install_packages() { (( ${#pkgs[@]} == 0 )) && { info "${group}: empty — skipping"; return; } step "Group: ${group} (${#pkgs[@]} packages)" + + local succeeded=() failed=() + if [[ $group == aur ]]; then - run_quiet " Installing ${group}" paru_install "${pkgs[@]}" + for pkg in "${pkgs[@]}"; do + local tmp; tmp=$(mktemp) + if [[ $IS_TTY == true ]]; then + spinner_start " [aur] $pkg" + if paru -S --needed --noconfirm "$pkg" >"$tmp" 2>&1; then + spinner_stop ok "[aur] $pkg"; succeeded+=("$pkg") + else + spinner_stop fail "[aur] $pkg" + warn "paru output:"; cat "$tmp" | indent; failed+=("$pkg") + fi + else + printf " ... [aur] %s\n" "$pkg" + if paru -S --needed --noconfirm "$pkg" >"$tmp" 2>&1; then + ok "[aur] $pkg"; succeeded+=("$pkg") + else + err "[aur] $pkg" + warn "paru output:"; cat "$tmp" | indent; failed+=("$pkg") + fi + fi + rm -f "$tmp" + done else run_quiet " Installing ${group}" pacman_install "${pkgs[@]}" + local tmp; tmp=$(mktemp) + if pacman_install "${pkgs[@]}" >"$tmp" 2>&1; then + succeeded=("${pkgs[@]}"); rm -f "$tmp" + else + rm -f "$tmp" + warn "Bulk install failed for group '${group}' — retrying per package" + for pkg in "${pkgs[@]}"; do + local tmp2; tmp2=$(mktemp) + if [[ $IS_TTY == true ]]; then + spinner_start " [${group}] $pkg" + if pacman_install "$pkg" >"$tmp2" 2>&1; then + spinner_stop ok "[${group}] $pkg"; succeeded+=("$pkg") + else + spinner_stop fail "[${group}] $pkg" + warn "pacman output:"; cat "$tmp2" | indent; failed+=("$pkg") + fi + else + printf " ... [%s] %s\n" "$group" "$pkg" + if pacman_install "$pkg" >"$tmp2" 2>&1; then + ok "[${group}] $pkg"; succeeded+=("$pkg") + else + err "[${group}] $pkg" + warn "pacman output:"; cat "$tmp2" | indent; failed+=("$pkg") + fi + fi + rm -f "$tmp2" + done + fi fi - save_pkg_list "$group" "${pkgs[@]}" + + if (( ${#succeeded[@]} )); then + save_pkg_list "$group" "${succeeded[@]}" + fi + + if (( ${#failed[@]} )); then + warn "Failed in group '${group}' (will retry on next update):" + for pkg in "${failed[@]}"; do + printf " - %s\n" "$pkg" + done + fi + return 0 } # stow itself (needed for the next step) run_quiet "Ensuring stow is present" sudo pacman -S --needed --noconfirm stow - # Core + # Build the set of groups that are handled specially so we can exclude them + # when iterating all .pkgs files for automatic groups. + local hw_groups=("${HW_CPU}-cpu" "${HW_GPU}-gpu") + local optional_group_names=() + local optional_file="$PACKAGES_DIR/optional.groups" + if [[ -f $optional_file ]]; then + mapfile -t optional_group_names < <(grep -v '^\s*#' "$optional_file" | grep -v '^\s*$') + fi + + is_special_group() { + local g="$1" + # Returns 0 if the group is hw, optional, aur, or security (handled separately) + [[ $g == aur || $g == security ]] && return 0 + for hw in "${hw_groups[@]}"; do [[ $g == "$hw" ]] && return 0; done + for og in "${optional_group_names[@]}"; do [[ $g == "$og" ]] && return 0; done + return 1 + } + + # 1. Core install_group "core" - # Hardware - install_group "${HW_CPU}-cpu" 2>/dev/null || true - install_group "${HW_GPU}-gpu" 2>/dev/null || true + # 2. Hardware (auto-detected) + install_group "${HW_CPU}-cpu" + install_group "${HW_GPU}-gpu" - # Security extras + # 3. All remaining automatic groups (every .pkgs file that is not special) + while IFS= read -r pkg_file; do + local group; group=$(basename "$pkg_file" .pkgs) + is_special_group "$group" && continue + [[ $group == core ]] && continue # already done above + install_group "$group" + done < <(find "$PACKAGES_DIR" -maxdepth 1 -name "*.pkgs" | sort) + + + # 4. Security extras if [[ $INSTALL_SECURITY == true ]]; then local sec_pkgs=(ufw apparmor zram-generator) step "Security extras" @@ -532,12 +624,12 @@ install_packages() { save_pkg_list "security" "${sec_pkgs[@]}" fi - # Optional chosen groups + # 5. Optional chosen groups for group in "${CHOSEN_OPTIONAL_GROUPS[@]}"; do install_group "$group" done - # AUR group (always, if paru is present) + # 6. AUR group install_group "aur" phase_done @@ -547,9 +639,9 @@ install_packages() { # STEP 9 — Clone into ~/.atlas-dotfiles and stow # ───────────────────────────────────────────────────────────────────────────── stow_dotfiles() { - phase "Copying and stowing dotfiles" + phase "Cloning and stowing dotfiles" - # ~/.atlas-dotfiles is the permanent home of the repo. They can delete the original + # ~/.atlas-dotfiles is the permanent home of the repo. You can delete the original # clone after installation without breaking anything. local remote_url remote_url=$(git -C "$REPO_DIR" remote get-url origin 2>/dev/null || true) diff --git a/scripts/update.sh b/scripts/update.sh index 36c28bc..52dd255 100644 --- a/scripts/update.sh +++ b/scripts/update.sh @@ -15,6 +15,8 @@ STATE_DIR="$DOTFILES_DIR/.state" PKG_STATE_DIR="$STATE_DIR/packages" STATE_FILE="$STATE_DIR/update.state" PACKAGES_DIR="$DOTFILES_DIR/packages" +STOW_DIR="$DOTFILES_DIR" +STOW_PKG="config" STOW_TARGET="$HOME" # ── Colours ────────────────────────────────────────────────────────────────── @@ -188,20 +190,32 @@ git_fetch_and_check() { OLD_HASH="$local_hash" } -# ── Conflict detection ──────────────────────────────────────────────────────── -collect_changed_files() { - # Files changed inside the config/ stow package between old and new commit. - # Strip the leading "config/" prefix so paths are relative to $HOME, - # matching what stow creates as symlink targets. +# ── Change detection ──────────────────────────────────────────────────────────────── + +# Files changed inside config/ (stow package) — used for conflict detection. +# Paths are stripped of the "config/" prefix so they match $HOME-relative targets. +collect_changed_config_files() { git -C "$DOTFILES_DIR" diff --name-only "${OLD_HASH}" "${NEW_HASH}" \ | grep '^config/' \ | sed 's|^config/||' \ || true } +# Returns 0 (true) if any file under packages/ changed between the two commits. +packages_changed() { + git -C "$DOTFILES_DIR" diff --name-only "${OLD_HASH}" "${NEW_HASH}" \ + | grep -q '^packages/' +} + +# Returns 0 (true) if any file under scripts/ changed between the two commits. +scripts_changed() { + git -C "$DOTFILES_DIR" diff --name-only "${OLD_HASH}" "${NEW_HASH}" \ + | grep -q '^scripts/' +} + handle_conflicts() { local repo_changed_files - mapfile -t repo_changed_files < <(collect_changed_files) + mapfile -t repo_changed_files < <(collect_changed_config_files) if (( ${#repo_changed_files[@]} == 0 )); then return @@ -502,10 +516,37 @@ main() { if [[ $HAS_UPDATE == true ]]; then handle_conflicts apply_git_update + + # Re-stow config/ whenever dotfiles changed apply_stow + + # Re-stow scripts/ when it changed (keeps ~/.local/bin helpers up to date) + if scripts_changed; then + info "scripts/ changed — re-linking binaries" + local err_file; err_file=$(mktemp) + if stow --dir="$DOTFILES_DIR" --target="$HOME" --restow scripts \ + 2>"$err_file"; then + ok "stow: scripts" + else + warn "stow: scripts (errors below)" + while IFS= read -r line; do + echo " ${DIM}${line}${RESET}" + done < "$err_file" + fi + rm -f "$err_file" + fi + state_set "last_commit" "$NEW_HASH" + + # Re-process packages whenever packages/ changed, even if no git update + # produced new dotfiles — package lists are independent of stowed files. + if packages_changed; then + info "packages/ changed — running full package sync" + fi fi + # Package sync runs on every invocation (diff vs saved state catches changes). + # This also handles the case where a previous run partially failed. process_packages process_aur_group