fix: Make the install script clone the repo instead of linking it and reflected changes into the updater

This commit is contained in:
Gu://em_ 2026-05-04 15:15:51 +02:00
parent c51330c1c2
commit 38d2572e84
2 changed files with 102 additions and 79 deletions

View file

@ -115,11 +115,18 @@ header() {
clear
printf "${BOLD}${BLUE}"
cat << 'EOF'
╔══════════════════════════════════════════════════════════╗
║ Some ASCII Art ║
╠══════════════════════════════════════════════════════════╣
║ Installer · Arch Linux ║
╚══════════════════════════════════════════════════════════╝
╔══════════════════════════════════════════════════════════════════╗
║ _ _ _____ _ _ ║
║ /\ | | | | | __ \ | | | |
║ / \ | |_| | __ _ ___ | | | | ___ ___| | _| |_ ___ _ __ ║
║ / /\ \| __| |/ _` / __| | | | |/ _ \/ __| |/ / __/ _ \| '_ \
║ / ____ \ |_| | (_| \__ \ | |__| | __/\__ \ <| || (_) | |_) |
║ /_/ \_\__|_|\__,_|___/ |_____/ \___||___/_|\_\\__\___/| .__/ ║
| |
|_|
╠══════════════════════════════════════════════════════════════════╣
║ Installer · Arch Linux ║
╚══════════════════════════════════════════════════════════════════╝
EOF
printf "${RESET}\n"
}
@ -537,25 +544,63 @@ install_packages() {
}
# ─────────────────────────────────────────────────────────────────────────────
# STEP 9 — Stow dotfiles
# STEP 9 — Clone into ~/.atlas-dotfiles and stow
# ─────────────────────────────────────────────────────────────────────────────
stow_dotfiles() {
phase "Stowing dotfiles"
phase "Copying and stowing dotfiles"
step "Linking ${CONFIG_DIR}${HOME}"
# ~/.atlas-dotfiles is the permanent home of the repo. They 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)
# The config/ dir IS the stow package (its contents mirror $HOME)
# We treat config/ as a single stow package named "config"
# stow will create symlinks in $HOME for everything inside config/
if [[ -z $remote_url ]]; then
die "Could not determine remote URL from $REPO_DIR (is origin set?)"
fi
# Backup any existing files that would conflict
step "Setting up ~/.atlas-dotfiles as the permanent repo"
info "Remote: $remote_url"
if [[ -d $DOTFILES_DIR/.git ]]; then
# Already a git repo — verify it points to the same remote
local existing_remote
existing_remote=$(git -C "$DOTFILES_DIR" remote get-url origin 2>/dev/null || true)
if [[ $existing_remote == $remote_url ]]; then
ok "~/.atlas-dotfiles already cloned from correct remote"
run_quiet "Pulling latest" git -C "$DOTFILES_DIR" pull --ff-only origin main
else
warn "~/.atlas-dotfiles exists but points to a different remote:"
warn " existing: $existing_remote"
warn " expected: $remote_url"
if confirm "Replace it with the correct repo?" y; then
rm -rf "$DOTFILES_DIR"
run_quiet "Cloning dotfiles" git clone "$remote_url" "$DOTFILES_DIR"
else
die "Aborted — ~/.atlas-dotfiles remote mismatch"
fi
fi
elif [[ -e $DOTFILES_DIR ]]; then
warn "~/.atlas-dotfiles exists but is not a git repo — moving to ~/.atlas-dotfiles.bak"
mv "$DOTFILES_DIR" "${DOTFILES_DIR}.bak"
run_quiet "Cloning dotfiles" git clone "$remote_url" "$DOTFILES_DIR"
else
run_quiet "Cloning dotfiles" git clone "$remote_url" "$DOTFILES_DIR"
fi
#TODO Checkout ?
ok "~/.atlas-dotfiles → $remote_url"
# Backup any real files that would conflict with stow links
local stow_config_dir="$DOTFILES_DIR/config"
local conflicts=()
while IFS= read -r link; do
local target="$HOME/${link#$CONFIG_DIR/}"
local rel="${link#$stow_config_dir/}"
local target="$HOME/$rel"
if [[ -e $target && ! -L $target ]]; then
conflicts+=("$target")
fi
done < <(find "$CONFIG_DIR" -type f)
done < <(find "$stow_config_dir" -type f 2>/dev/null)
if (( ${#conflicts[@]} )); then
warn "${#conflicts[@]} existing file(s) will be backed up (.bak):"
@ -565,29 +610,9 @@ stow_dotfiles() {
done
fi
# Create DOTFILES_DIR as a symlink to CONFIG_DIR, or use CONFIG_DIR directly
# We symlink ~/.atlas-dotfiles → repo's config dir so stow state lives in the repo
if [[ -L $DOTFILES_DIR ]]; then
local existing_target; existing_target=$(readlink -f "$DOTFILES_DIR")
if [[ $existing_target != "$CONFIG_DIR" ]]; then
warn "~/.atlas-dotfiles already points elsewhere: $existing_target"
warn "Removing and re-linking to $CONFIG_DIR"
rm "$DOTFILES_DIR"
ln -s "$CONFIG_DIR" "$DOTFILES_DIR"
fi
elif [[ -d $DOTFILES_DIR ]]; then
warn "~/.atlas-dotfiles exists as a real directory. Renaming to ~/.atlas-dotfiles.bak"
mv "$DOTFILES_DIR" "${DOTFILES_DIR}.bak"
ln -s "$CONFIG_DIR" "$DOTFILES_DIR"
else
ln -s "$CONFIG_DIR" "$DOTFILES_DIR"
fi
ok "~/.atlas-dotfiles → $CONFIG_DIR"
# Now run stow from inside the repo's parent, treating config as the package
# Stow from ~/.atlas-dotfiles treating config/ as the stow package
run_quiet "Stowing config" \
stow --dir="$REPO_DIR" --target="$HOME" --restow config
stow --dir="$DOTFILES_DIR" --target="$HOME" --restow config
phase_done
}
@ -709,28 +734,37 @@ enable_services() {
install_updater() {
phase "Dotfiles updater"
local updater_src="$SCRIPTS_DIR/update.sh"
local updater_link="$HOME/.local/bin/atlas-update"
local updater_in_dotfiles="$DOTFILES_DIR/scripts/update.sh"
local updater_link="$HOME/.local/bin/dotfiles-update"
if [[ ! -f $updater_src ]]; then
warn "Updater not found at $updater_src — skipping"
if [[ ! -f $updater_in_dotfiles ]]; then
warn "update.sh not found in ~/.atlas-dotfiles/scripts/ — skipping"
info "Expected: $updater_in_dotfiles"
phase_done
return
fi
chmod +x "$updater_in_dotfiles"
mkdir -p "$HOME/.local/bin"
chmod +x "$updater_src"
# Create symlink (stow might also handle this if update.sh is in config/)
# Here we link directly so it's always in PATH regardless of stow layout
ln -sf "$updater_src" "$updater_link"
ok "atlas-update → $updater_src"
info "Run ${BOLD}atlas-update${RESET} any time to sync with upstream"
# Symlink into PATH — stow may also handle this if scripts/ is a stow pkg,
# but we do it explicitly here so it works regardless of stow layout.
ln -sf "$updater_in_dotfiles" "$updater_link"
ok "dotfiles-update → $updater_in_dotfiles"
info "Run ${BOLD}dotfiles-update${RESET} any time to sync with upstream"
# Save repo path into state so updater knows where it lives
mkdir -p "$STATE_DIR"
state_set "repo_dir" "$REPO_DIR"
state_set "last_commit" "$(git -C "$REPO_DIR" rev-parse HEAD)"
# Initialise state inside the permanent repo
local state_dir="$DOTFILES_DIR/.state"
mkdir -p "$state_dir"
# Point state file at the permanent repo, not the installer's location
grep -q "^repo_dir=" "$state_dir/update.state" 2>/dev/null || echo "repo_dir=$DOTFILES_DIR" >> "$state_dir/update.state"
# Stamp the current HEAD so the first `dotfiles-update` knows the baseline
local head; head=$(git -C "$DOTFILES_DIR" rev-parse HEAD)
if grep -q "^last_commit=" "$state_dir/update.state" 2>/dev/null; then
sed -i "s|^last_commit=.*|last_commit=${head}|" "$state_dir/update.state"
else
echo "last_commit=$head" >> "$state_dir/update.state"
fi
phase_done
}
@ -744,7 +778,7 @@ finish() {
cat << 'EOF'
╔══════════════════════════════════════════════════════════╗
║ ║
║ ✔ Installation complete! ║
║ ✔ Installation complete!
║ ║
╚══════════════════════════════════════════════════════════╝
EOF

View file

@ -190,9 +190,13 @@ git_fetch_and_check() {
# ── Conflict detection ────────────────────────────────────────────────────────
collect_changed_files() {
# Files changed between old commit and new commit in the repo
# 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.
git -C "$DOTFILES_DIR" diff --name-only "${OLD_HASH}" "${NEW_HASH}" \
| grep -v '^packages/' | grep -v '^\.' || true
| grep '^config/' \
| sed 's|^config/||' \
|| true
}
handle_conflicts() {
@ -292,33 +296,17 @@ apply_git_update() {
# ── Stow ─────────────────────────────────────────────────────────────────────
apply_stow() {
section "Stowing dotfiles"
cd "$DOTFILES_DIR"
# Discover stow packages (top-level dirs, excluding hidden & packages/)
local stow_pkgs=()
while IFS= read -r d; do
local name
name=$(basename "$d")
[[ $name == packages ]] && continue
stow_pkgs+=("$name")
done < <(find "$DOTFILES_DIR" -mindepth 1 -maxdepth 1 -type d ! -name '.*' | sort)
if (( ${#stow_pkgs[@]} == 0 )); then
warn "No stow packages found in $DOTFILES_DIR"
return
local err_file; err_file=$(mktemp)
if stow --dir="$STOW_DIR" --target="$STOW_TARGET" --restow "$STOW_PKG" 2>"$err_file"; then
ok "stow: $STOW_PKG"
else
warn "stow: $STOW_PKG (errors below)"
while IFS= read -r line; do
echo " ${DIM}${line}${RESET}"
done < "$err_file"
fi
for pkg in "${stow_pkgs[@]}"; do
if stow --restow --target="$STOW_TARGET" "$pkg" 2>/tmp/stow_err; then
ok "stow: $pkg"
else
warn "stow: $pkg (see error below)"
while IFS= read -r line; do
echo " ${DIM}${line}${RESET}"
done < /tmp/stow_err
fi
done
rm -f /tmp/stow_err
rm -f "$err_file"
}
# ── Package management ────────────────────────────────────────────────────────
@ -493,7 +481,8 @@ process_aur_group() {
# ── Entry point ───────────────────────────────────────────────────────────────
main() {
echo
echo "${BOLD} Hyprland Dotfiles Updater${RESET} ${DIM}(Arch Linux)${RESET}"
echo "${BOLD} Atlas Desktop Updater${RESET}"
echo "${DIM} Arch Linux${RESET}"
echo " ${DIM}Target: ${DOTFILES_DIR}${RESET}"
[[ -d $DOTFILES_DIR/.git ]] || die "$DOTFILES_DIR is not a git repository."