#!/bin/bash # # Purpose : Install and manage CoreDesktop sibling projects # # A sibling is a git repository cloned into ~/.local/share/siblings/. # If it has an install.sh, that runs once when the sibling is added. # Every `update` pulls each sibling and runs its update.sh, if it has one # (see updates.d/71-siblings.sh). SIBLINGS="$HOME/.local/share/siblings" usage() { cat << EOF Usage: sibling [command] add [url] Install a sibling project from a git repository (default) list Show installed sibling projects remove Uninstall a sibling project EOF } # Derive a directory name from a git URL, e.g. # https://host/user/my-project.git -> my-project sibling_name() { local name="${1%/}" name="${name##*/}" name="${name##*:}" echo "${name%.git}" } add_sibling() { local url="$1" name dir if [ -z "$url" ]; then read -rp "Git repository URL for the sibling project: " url fi if [ -z "$url" ]; then echo "No URL given." return 1 fi name="$(sibling_name "$url")" if [[ -z "$name" || "$name" == .* ]]; then echo "Could not work out a project name from: $url" return 1 fi dir="$SIBLINGS/$name" mkdir -p "$SIBLINGS" if [ -d "$dir/.git" ]; then local existing existing="$(git -C "$dir" remote get-url origin 2>/dev/null)" if [ "$existing" != "$url" ]; then echo "A different sibling named '$name' is already installed from: $existing" return 1 fi echo "$name is already installed; pulling the latest version..." git -C "$dir" pull --ff-only || return 1 else echo "Cloning $name..." git clone "$url" "$dir" || return 1 fi if [ -f "$dir/install.sh" ]; then echo "Running $name's install.sh..." if ! (cd "$dir" && bash install.sh); then echo "$name's install.sh failed. Fix the problem and run 'sibling add $url' again." return 1 fi fi # Confirm the install if [ -d "$dir/.git" ] && git -C "$dir" rev-parse --verify --quiet HEAD > /dev/null; then echo "Installed $name at $dir ($(git -C "$dir" log -1 --format='%h %s'))." echo "'update' will keep it up to date." else echo "$name does not look installed correctly at $dir." return 1 fi } list_siblings() { local dir found=0 for dir in "$SIBLINGS"/*/; do [ -d "$dir/.git" ] || continue found=1 printf '%-24s %s (%s)\n' "$(basename "$dir")" \ "$(git -C "$dir" remote get-url origin 2>/dev/null)" \ "$(git -C "$dir" log -1 --format='%h, %cr' 2>/dev/null)" done [ $found -eq 1 ] || echo "No sibling projects installed." } remove_sibling() { local name="$1" if [[ -z "$name" || "$name" == */* || "$name" == .* ]]; then usage return 1 fi if [ ! -d "$SIBLINGS/$name" ]; then echo "No sibling named '$name' is installed." return 1 fi read -rp "Remove $SIBLINGS/$name? [y/N] " response case "$response" in [yY][eE][sS]|[yY]) rm -rf "${SIBLINGS:?}/$name" echo "Removed $name. Anything its install.sh set up outside that folder is still there." ;; *) echo "Nothing removed." ;; esac } case "$1" in ""|add) add_sibling "$2" ;; list|ls) list_siblings ;; remove|rm) remove_sibling "$2" ;; -h|--help|help) usage ;; *) usage; exit 1 ;; esac