|
| 1 | +#!/usr/bin/env bash |
| 2 | +# dsync - dotfiles sync |
| 3 | +# |
| 4 | +# - pulls dotfiles repo (if on main) and runs ./install |
| 5 | +# - pulls or sets up the private skills repo linked at ~/.claude/skills |
| 6 | + |
| 7 | +set -uo pipefail |
| 8 | + |
| 9 | +SKILLS_REPO_URL="git@github.com:noahp/noahp-private-skills.git" |
| 10 | +SKILLS_REPO_NAME="noahp-private-skills" |
| 11 | + |
| 12 | +# Resolve the dotfiles repo root from this script's real location |
| 13 | +SCRIPT_REAL="$(readlink -f "${BASH_SOURCE[0]}")" |
| 14 | +DOTFILES_DIR="$(cd "$(dirname "$SCRIPT_REAL")/.." && pwd)" |
| 15 | + |
| 16 | +info() { echo " $*"; } |
| 17 | +warn() { echo " [warn] $*"; } |
| 18 | +skip() { echo " [skip] $*"; } |
| 19 | +step() { echo "==> $*"; } |
| 20 | + |
| 21 | +# Pull dotfiles repo and re-run install |
| 22 | +sync_dotfiles() { |
| 23 | + step "Syncing dotfiles ($DOTFILES_DIR)..." |
| 24 | + |
| 25 | + local branch |
| 26 | + branch=$(git -C "$DOTFILES_DIR" branch --show-current 2>/dev/null) |
| 27 | + |
| 28 | + if [[ "$branch" != "main" ]]; then |
| 29 | + skip "Not on main (on '$branch')" |
| 30 | + return |
| 31 | + fi |
| 32 | + |
| 33 | + git -C "$DOTFILES_DIR" pull |
| 34 | + "$DOTFILES_DIR/install" |
| 35 | +} |
| 36 | + |
| 37 | +# Pull or set up the private skills repo |
| 38 | +sync_skills() { |
| 39 | + step "Checking ~/.claude/skills..." |
| 40 | + |
| 41 | + local skills_path="$HOME/.claude/skills" |
| 42 | + |
| 43 | + # Case 1: symlink — find the git repo root and pull if on main |
| 44 | + if [[ -L "$skills_path" ]]; then |
| 45 | + local target git_root branch |
| 46 | + target="$(readlink -f "$skills_path")" |
| 47 | + git_root="$(git -C "$target" rev-parse --show-toplevel 2>/dev/null || true)" |
| 48 | + |
| 49 | + if [[ -z "$git_root" ]]; then |
| 50 | + warn "~/.claude/skills is a symlink but not inside a git repo, skipping" |
| 51 | + return |
| 52 | + fi |
| 53 | + |
| 54 | + branch=$(git -C "$git_root" branch --show-current 2>/dev/null) |
| 55 | + if [[ "$branch" != "main" ]]; then |
| 56 | + skip "Skills repo not on main (on '$branch')" |
| 57 | + return |
| 58 | + fi |
| 59 | + |
| 60 | + info "Pulling skills repo ($git_root)..." |
| 61 | + git -C "$git_root" pull |
| 62 | + return |
| 63 | + fi |
| 64 | + |
| 65 | + # Case 2: doesn't exist or is empty — clone and symlink |
| 66 | + if [[ ! -e "$skills_path" ]] || [[ -z "$(ls -A "$skills_path" 2>/dev/null)" ]]; then |
| 67 | + local skills_repo_dir |
| 68 | + skills_repo_dir="$(cd "$DOTFILES_DIR/.." && pwd)/$SKILLS_REPO_NAME" |
| 69 | + |
| 70 | + if [[ ! -d "$skills_repo_dir" ]]; then |
| 71 | + info "Cloning $SKILLS_REPO_URL -> $skills_repo_dir..." |
| 72 | + git clone "$SKILLS_REPO_URL" "$skills_repo_dir" |
| 73 | + fi |
| 74 | + |
| 75 | + info "Symlinking ~/.claude/skills -> $skills_repo_dir/skills" |
| 76 | + [[ -e "$skills_path" ]] && rm -rf "$skills_path" |
| 77 | + ln -s "$skills_repo_dir/skills" "$skills_path" |
| 78 | + return |
| 79 | + fi |
| 80 | + |
| 81 | + # Case 3: exists, not a symlink, not empty |
| 82 | + warn "~/.claude/skills exists and is not a symlink — not touching it" |
| 83 | +} |
| 84 | + |
| 85 | +sync_dotfiles |
| 86 | +sync_skills |
| 87 | +step "Done." |
0 commit comments