fix: New README, new documentation for developpers, and many install.sh and update.sh fixes

This commit is contained in:
Gu://em_ 2026-05-04 22:57:12 +02:00
parent 38d2572e84
commit 6b92f7a0a0
5 changed files with 282 additions and 45 deletions

101
README.md
View file

@ -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. ## What's included
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. - **Window manager**: Hyprland
More generally give a look to the [Quick start guide](https://hedgedoc.oblic-parallels.fr/s/JSR33pjd_) - **Status bar**: Waybar
- **Display manager**: Ly
If something doesn't work or behaves anormally don't hesitate to contact me so that it will be fixed for future users. - **Launcher**: Rofi
- **Notifications center**: Swaync
- **Terminal**: Foot
- **Shell**: Zsh + Zinit + Powerlevel10k
## Requirements ## Requirements
You'll just need an already functional (even basic) **Arch Linux** system with `sudo` installed. - A basic Arch Linux install (cli is enough, no DE required)
Setup will take care of configuring AppArmor and Zram if it hasn't been done yet. - 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 ```sh
curl -fsSL https://forge.oblic-parallels.fr/guillm/atlas-desktop/raw/branch/main/scripts/install.sh | bash
Very simple, clone the project (or download it directly from the web interface)
```sh=
git clone https://forge.oblic-parallels.fr/guillm/atlas-install
``` ```
And run `setup.sh`
```sh=
./setup.sh
```
Then just follow the instructions and you should be good to go ! 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 ## 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 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.
I particularly think of helix which is used as the default text editor but may not suit some people needs. 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. 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`. 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 `<file>.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 ## Future improvements
- Waybar switch script
- A defaults system allowing you to easily choose your default programs
- Nvidia cards handling - Nvidia cards handling
- Cleaner way to enable/disable some packages / configuratuions

57
doc/Developpers.md Normal file
View file

@ -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
│ └── <group>.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/<group>`. 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.

0
packages/optional.groups Normal file
View file

View file

@ -497,6 +497,9 @@ install_packages() {
local pkg_file pkgs group local pkg_file pkgs group
# Helper: install a group and save state # 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() { install_group() {
local group="$1" local group="$1"
local pkg_file="$PACKAGES_DIR/${group}.pkgs" local pkg_file="$PACKAGES_DIR/${group}.pkgs"
@ -506,25 +509,114 @@ install_packages() {
(( ${#pkgs[@]} == 0 )) && { info "${group}: empty — skipping"; return; } (( ${#pkgs[@]} == 0 )) && { info "${group}: empty — skipping"; return; }
step "Group: ${group} (${#pkgs[@]} packages)" step "Group: ${group} (${#pkgs[@]} packages)"
local succeeded=() failed=()
if [[ $group == aur ]]; then 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 else
run_quiet " Installing ${group}" pacman_install "${pkgs[@]}" 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 fi
save_pkg_list "$group" "${pkgs[@]}" 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
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) # stow itself (needed for the next step)
run_quiet "Ensuring stow is present" sudo pacman -S --needed --noconfirm stow 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" install_group "core"
# Hardware # 2. Hardware (auto-detected)
install_group "${HW_CPU}-cpu" 2>/dev/null || true install_group "${HW_CPU}-cpu"
install_group "${HW_GPU}-gpu" 2>/dev/null || true 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 if [[ $INSTALL_SECURITY == true ]]; then
local sec_pkgs=(ufw apparmor zram-generator) local sec_pkgs=(ufw apparmor zram-generator)
step "Security extras" step "Security extras"
@ -532,12 +624,12 @@ install_packages() {
save_pkg_list "security" "${sec_pkgs[@]}" save_pkg_list "security" "${sec_pkgs[@]}"
fi fi
# Optional chosen groups # 5. Optional chosen groups
for group in "${CHOSEN_OPTIONAL_GROUPS[@]}"; do for group in "${CHOSEN_OPTIONAL_GROUPS[@]}"; do
install_group "$group" install_group "$group"
done done
# AUR group (always, if paru is present) # 6. AUR group
install_group "aur" install_group "aur"
phase_done phase_done
@ -547,9 +639,9 @@ install_packages() {
# STEP 9 — Clone into ~/.atlas-dotfiles and stow # STEP 9 — Clone into ~/.atlas-dotfiles and stow
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
stow_dotfiles() { 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. # clone after installation without breaking anything.
local remote_url local remote_url
remote_url=$(git -C "$REPO_DIR" remote get-url origin 2>/dev/null || true) remote_url=$(git -C "$REPO_DIR" remote get-url origin 2>/dev/null || true)

View file

@ -15,6 +15,8 @@ STATE_DIR="$DOTFILES_DIR/.state"
PKG_STATE_DIR="$STATE_DIR/packages" PKG_STATE_DIR="$STATE_DIR/packages"
STATE_FILE="$STATE_DIR/update.state" STATE_FILE="$STATE_DIR/update.state"
PACKAGES_DIR="$DOTFILES_DIR/packages" PACKAGES_DIR="$DOTFILES_DIR/packages"
STOW_DIR="$DOTFILES_DIR"
STOW_PKG="config"
STOW_TARGET="$HOME" STOW_TARGET="$HOME"
# ── Colours ────────────────────────────────────────────────────────────────── # ── Colours ──────────────────────────────────────────────────────────────────
@ -188,20 +190,32 @@ git_fetch_and_check() {
OLD_HASH="$local_hash" OLD_HASH="$local_hash"
} }
# ── Conflict detection ──────────────────────────────────────────────────────── # ── Change detection ────────────────────────────────────────────────────────────────
collect_changed_files() {
# Files changed inside the config/ stow package between old and new commit. # Files changed inside config/ (stow package) — used for conflict detection.
# Strip the leading "config/" prefix so paths are relative to $HOME, # Paths are stripped of the "config/" prefix so they match $HOME-relative targets.
# matching what stow creates as symlink targets. collect_changed_config_files() {
git -C "$DOTFILES_DIR" diff --name-only "${OLD_HASH}" "${NEW_HASH}" \ git -C "$DOTFILES_DIR" diff --name-only "${OLD_HASH}" "${NEW_HASH}" \
| grep '^config/' \ | grep '^config/' \
| sed 's|^config/||' \ | sed 's|^config/||' \
|| true || 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() { handle_conflicts() {
local repo_changed_files 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 if (( ${#repo_changed_files[@]} == 0 )); then
return return
@ -502,10 +516,37 @@ main() {
if [[ $HAS_UPDATE == true ]]; then if [[ $HAS_UPDATE == true ]]; then
handle_conflicts handle_conflicts
apply_git_update apply_git_update
# Re-stow config/ whenever dotfiles changed
apply_stow apply_stow
state_set "last_commit" "$NEW_HASH"
# 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 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_packages
process_aur_group process_aur_group