Skip to content

Instantly share code, notes, and snippets.

@jodersky
Last active January 21, 2018 04:03
Show Gist options
  • Save jodersky/19f81db9feeb8b8a778298eb065d084a to your computer and use it in GitHub Desktop.
Save jodersky/19f81db9feeb8b8a778298eb065d084a to your computer and use it in GitHub Desktop.
#!/bin/bash
# Manage a collection of github mirrors.
#
# This script provides functionality to clone and update git
# repositories as mirrors. The update functionality is silent on
# successful updates and is designed to be called in an automated way,
# such as with cron.
#
# All mirror repositories are assumed to be contained under one base
# directory (by default ~/public_git), configurable via a flag.
set -o errexit
print_usage() {
echo "git mirror [--base=<base_dir>] [update [repo...]]"
echo "git mirror [--base=<base_dir>] clone <url>"
}
opts=$(getopt -o hb: --long help,base: -n 'git-mirror' -- "$@")
eval set -- "$opts"
base_dir="$HOME/public_git"
action="update"
urls=()
repo_dirs=()
while true; do
case "$1" in
-h|--help) print_usage; exit 0 ;;
-b|--base)
shift
base_dir="$1"
shift
;;
--) shift; break ;;
*) echo "Option parse error"; exit 1; ;;
esac
done
while true; do
case "$1" in
update|"")
action="update"
if [[ "$#" -gt 1 ]]; then
shift
for repo_name in "$@"; do
repo_dirs+=("$base_dir/$repo_name")
done
else
while IFS= read -r -d '' repo_dir; do
repo_dirs+=("$repo_dir")
done < <(find "$base_dir" -maxdepth 1 -type d -name '*.git' -print0)
fi
break
;;
clone)
action="clone"
[ "$#" -gt 1 ] || (print_usage ; exit 1)
shift
urls=("$@")
break
;;
*)
print_usage
exit 1
esac
done
update_mirror() {
local repo_dir="$1"
local repo_url
repo_url=$(git --git-dir="$repo_dir" config --get remote.origin.url)
# Fetch from remote and update upstream refs
git --git-dir="$repo_dir" remote update --prune > /dev/null
# Get additional information for certain upstream repos
local host
host=$(echo "$repo_url" \
| sed -n --regexp-extended 's|https?://([^/]*).*|\1|p')
case "$host" in
github.com)
local slug
slug=$(echo "$repo_url" \
| perl -pe 's|^https?://github.com/(.*?)(\.git)?$|\1|p')
local username
username=$(echo "$slug" | sed -nr 's|([^/]*)/.*|\1|p')
local repo
repo=$(echo "$slug" | sed -nr 's|[^/]*/(.*)|\1|p')
curl --silent --show-error \
"https://api.github.com/repos/$username/$repo" \
| jq .description --raw-output > "$repo_dir/description"
;;
*)
;;
esac
}
case "$action" in
update)
for repo_dir in "${repo_dirs[@]}"; do
update_mirror "$repo_dir" || echo "Error updating $repo_dir" >&2
done
;;
clone)
for repo_url in "${urls[@]}"; do
git -C "$base_dir" clone --mirror "$repo_url"
done
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment