Add the installer, uninstaller, and generated docs

This commit is contained in:
2026-09-20 00:19:38 -04:00
parent 0c422e7345
commit 3e65d176e3
100 changed files with 2585 additions and 0 deletions
Executable
+196
View File
@@ -0,0 +1,196 @@
#!/bin/bash
set -e
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
blob_path="$HOME/.local/share/blob"
config_dir="$HOME/.config"
state_dir="$HOME/.local/state/blob"
session_dir="/usr/share/wayland-sessions"
font_dir="$HOME/.local/share/fonts"
force=false
check=false
changes=0
usage() {
cat <<USAGE
Usage: ./install.sh [OPTIONS]
--check Report what would change, write nothing
--force Overwrite files that have local changes
--help Show this message
USAGE
exit 0
}
while (( $# > 0 )); do
case "$1" in
--force) force=true; shift ;;
--check) check=true; shift ;;
--help) usage ;;
*) echo "Unknown option: $1" >&2; usage ;;
esac
done
say() {
printf '%s\n' "$1"
}
note_change() {
changes=$((changes + 1))
}
# BLOB_PATH is a symlink to this checkout rather than a copy, so bin/, shell/,
# themes/ and default/ are always the working tree. Every path the shell
# resolves as $BLOB_PATH/... therefore needs no install step at all.
link_blob_path() {
local current=""
[[ -L $blob_path ]] && current="$(readlink -f "$blob_path")"
if [[ $current == "$repo_dir" ]]; then
say "ok BLOB_PATH -> $repo_dir"
return
fi
if [[ -e $blob_path && ! -L $blob_path ]]; then
say "WARN $blob_path exists and is not a symlink; move it aside first"
note_change
return
fi
note_change
if [[ $check == true ]]; then
say "would link BLOB_PATH -> $repo_dir"
return
fi
ln -sfn "$repo_dir" "$blob_path"
say "link BLOB_PATH -> $repo_dir"
}
# Copy a file only when the destination is missing or matches what we last
# wrote. A destination that differs is a local edit, reported and kept unless
# --force says otherwise.
install_file() {
local source="$1" dest="$2" label="$3"
if [[ ! -e $source ]]; then
say "SKIP $label (missing in repo)"
return
fi
if [[ -e $dest ]] && cmp -s "$source" "$dest"; then
say "ok $label"
return
fi
note_change
if [[ -e $dest ]] && [[ $force == false ]]; then
say "DIFF $label (local changes kept; --force to overwrite)"
return
fi
if [[ $check == true ]]; then
say "would write $label"
return
fi
mkdir -p "$(dirname "$dest")"
[[ -e $dest ]] && cp "$dest" "$dest.bak"
cp "$source" "$dest"
say "write $label"
}
install_tree() {
local source="$1" dest="$2" label="$3"
if [[ ! -d $source ]]; then
say "SKIP $label (missing in repo)"
return
fi
local relative
while IFS= read -r relative; do
install_file "$source/$relative" "$dest/$relative" "$label/$relative"
done < <(cd "$source" && find . -type f -printf '%P\n' | sort)
}
install_session_entry() {
local source="$repo_dir/session/blob.desktop"
local dest="$session_dir/blob.desktop"
if [[ -e $dest ]] && cmp -s "$source" "$dest"; then
say "ok wayland session entry"
return
fi
note_change
if [[ $check == true ]]; then
say "would install wayland session entry (needs sudo)"
return
fi
sudo install -Dm644 "$source" "$dest"
say "write wayland session entry"
}
say "Blob installer"
say "repo: $repo_dir"
if [[ $check == true ]]; then
say "mode: check (nothing will be written)"
fi
say ""
link_blob_path
if [[ $check == false ]]; then
mkdir -p "$state_dir"/{toggles/hypr,indicators,notifications}
mkdir -p "$config_dir/blob"/{hooks,extensions,plugins,themed,themes}
mkdir -p "$HOME/wallpapers"
fi
install_tree "$repo_dir/hypr" "$config_dir/hypr" "hypr"
# config/ is the shipped-defaults directory. Everything in it is reachable as
# $BLOB_PATH/config/... so `blob-refresh-config` can reset a file, and most of it
# is also the right thing to deploy on a fresh install. Two subdirectories are
# reference-only and must not be copied into ~/.config:
#
# blob/ the shell defaults; copying them over ~/.config/blob/shell.json would
# replace the user's bar layout with the stock one
# hypr/ the stock Hyprland config; the personal hypr/ below is authoritative
# and is installed to the same place
for entry in "$repo_dir"/config/*; do
entry_name="$(basename "$entry")"
[[ $entry_name == blob || $entry_name == hypr ]] && continue
if [[ -d $entry ]]; then
install_tree "$entry" "$config_dir/$entry_name" "config/$entry_name"
else
install_file "$entry" "$config_dir/$entry_name" "config/$entry_name"
fi
done
install_tree "$repo_dir/hooks" "$config_dir/blob/hooks" "hooks"
install_tree "$repo_dir/branding" "$config_dir/blob/branding" "branding"
install_file "$repo_dir/shell.json" "$config_dir/blob/shell.json" "shell.json"
install_file "$repo_dir/session/uwsm/default" "$config_dir/uwsm/default" "uwsm/default"
install_file "$repo_dir/session/uwsm/env.d/10-blob" "$config_dir/uwsm/env.d/10-blob" "uwsm/env.d/10-blob"
install_file "$repo_dir/fonts/omarchy.ttf" "$font_dir/omarchy.ttf" "fonts/omarchy.ttf"
install_session_entry
zen_profile="$(find "$config_dir/zen" -maxdepth 1 -type d -name '*.Default (release)*' 2>/dev/null | head -1)"
if [[ -n $zen_profile ]]; then
install_file "$repo_dir/zen/userChrome.css" "$zen_profile/chrome/userChrome.css" "zen/userChrome.css"
else
say "SKIP zen/userChrome.css (no Zen profile found)"
fi
say ""
if [[ $check == true ]]; then
say "$changes item(s) would change."
(( changes == 0 )) || exit 1
else
say "$changes item(s) changed."
say ""
say "Next: log out and pick the Blob session, then run 'blob theme set <name>'."
fi