Files
dotfiles/dot_local/bin/executable_ghg-clone
T
2026-10-14 13:31:37 -04:00

117 lines
5.2 KiB
Bash
Executable File

#!/bin/sh
# ghq get + resolve the on-disk clone path; prints the repo directory.
# Shell wrappers (fish/bash/zsh `ghg` functions) cd into the printed path —
# a child process can't change the caller's cwd.
#
# Then sets up a prad.codes mirror when the repo has none (best effort; the
# clone never fails over it):
# github.com/<owner>/<name> you admin → pull mirror into a prad.codes org
# (picked with gum, guessed from the language; esc skips), every 8h
# prad.codes/<org>/<name> that isn't itself a mirror → push mirror to
# github.com/<you>/<name> (created if missing), on every push and every 8h
repo=$1
if [ -z "$repo" ]; then
echo "usage: ghg-clone <repo>" >&2
exit 1
fi
# ghq natively understands https://, ssh://, git@host:…, and host/user/repo.
# Keep its output on stderr so stdout stays clean for the wrapper's cd.
ghq get "$repo" >&2 || exit
# Reduce the input to ghq's on-disk shape: <host>/<user>/<repo> —
# strip scheme (https://, ssh://, git://), user@ (git@github.com:…),
# turn scp host:path into host/path, drop trailing .git.
rel=$(printf '%s\n' "$repo" \
| sed -E 's#^[[:alnum:]]+://##; s#^[^@/]+@##; s#:#/#; s#\.git$##')
# bare "user/repo" with no host → default to github.com
case "$rel" in
*.*/*) ;;
*) rel=github.com/$rel ;;
esac
dir=$(ghq root)/$rel
if [ ! -d "$dir" ]; then
echo "ghg: expected clone at $dir but it does not exist" >&2
exit 1
fi
command -v zoxide >/dev/null 2>&1 && zoxide add "$dir"
# ── Mirrors ───────────────────────────────────────────────────────────────
# Everything below talks on stderr; stdout carries only the final path.
have() { command -v "$1" >/dev/null 2>&1; }
# prad.codes orgs are per language; guess one from GitHub's primary language.
lang_org() {
case $1 in
Go) echo go ;;
Python | "Jupyter Notebook") echo py ;;
Rust) echo rs ;;
Dart) echo dart ;;
TeX) echo tex ;;
JavaScript | TypeScript | Astro | Svelte | Vue | HTML | CSS) echo js ;;
Markdown | MDX) echo md ;;
*) echo env ;; # Lua, Shell, no code at all (dotfiles, configs)
esac
}
pull_mirror() { # owner name
info=$(gh repo view "$1/$2" --json viewerPermission,isPrivate,primaryLanguage \
-q '[.viewerPermission, .isPrivate, .primaryLanguage.name // ""] | @tsv' 2>/dev/null) || return 0
perm=$(printf '%s\n' "$info" | cut -f1)
private=$(printf '%s\n' "$info" | cut -f2)
lang=$(printf '%s\n' "$info" | cut -f3)
[ "$perm" = ADMIN ] || return 0 # someone else's repo: just a clone
# tea api exits 0 even on errors, hence jq -e on every response.
tea api "/api/v1/repos/search?q=$2&limit=50" | jq -e --arg u "github.com/$1/$2" \
'any(.data[]; (.original_url // "") | ascii_downcase | sub("(\\.git)?/?$"; "") | endswith($u | ascii_downcase))' \
>/dev/null && return 0
org=$(tea api '/api/v1/orgs?limit=50' | jq -r '.[].username' |
gum choose --header "Pull-mirror github.com/$1/$2 into which prad.codes org? (esc skips)" \
--selected "$(lang_org "$lang")") || return 0
[ -n "$org" ] || return 0
echo "→ pull mirror: github.com/$1/$2 → prad.codes/$org/$2 (every 8h)" >&2
priv=
[ "$private" = true ] && priv=--private
# shellcheck disable=SC2086 # $priv is one optional flag
tea repos migrate --name "$2" --owner "$org" --clone-url "https://github.com/$1/$2.git" \
--service git --mirror --mirror-interval 8h --auth-token "$(gh auth token)" $priv >&2 ||
echo "ghg: pull mirror failed" >&2
}
push_mirror() { # org name
repo=$(tea api "/api/v1/repos/$1/$2")
printf '%s' "$repo" | jq -e '.id and (.mirror | not)' >/dev/null || return 0
tea api "/api/v1/repos/$1/$2/push_mirrors" | jq -e 'length == 0' >/dev/null || return 0
me=$(gh api user -q .login 2>/dev/null) || return 0
if gh repo view "$me/$2" >/dev/null 2>&1; then
gum confirm "Push-mirror prad.codes/$1/$2 to the existing github.com/$me/$2? Mirror pushes overwrite it." || return 0
else
gum confirm "Push-mirror prad.codes/$1/$2 to a new github.com/$me/$2?" || return 0
vis=--public
[ "$(printf '%s' "$repo" | jq -r .private)" = true ] && vis=--private
gh repo create "$me/$2" "$vis" --description "Mirror of https://prad.codes/$1/$2" >&2 || return 0
fi
if jq -n --arg url "https://github.com/$me/$2.git" --arg user "$me" --arg pass "$(gh auth token)" \
'{remote_address: $url, remote_username: $user, remote_password: $pass,
interval: "8h0m0s", sync_on_commit: true}' |
tea api -d @- "/api/v1/repos/$1/$2/push_mirrors" | jq -e .remote_name >/dev/null; then
tea api -X POST "/api/v1/repos/$1/$2/push_mirrors-sync" >/dev/null # first push now
echo "→ push mirror: prad.codes/$1/$2 → github.com/$me/$2 (on push + every 8h)" >&2
else
echo "ghg: push mirror failed" >&2
fi
}
if have gh && have tea && have jq && have gum; then
owner=${rel#*/} name=${owner#*/} owner=${owner%%/*}
case $rel in
github.com/*/*) pull_mirror "$owner" "$name" ;;
prad.codes/*/*) push_mirror "$owner" "$name" ;;
esac
fi
printf '%s\n' "$dir"