summaryrefslogtreecommitdiff
path: root/git-mirror
diff options
context:
space:
mode:
Diffstat (limited to 'git-mirror')
-rwxr-xr-xgit-mirror149
1 files changed, 124 insertions, 25 deletions
diff --git a/git-mirror b/git-mirror
index 76763c1..1a33774 100755
--- a/git-mirror
+++ b/git-mirror
@@ -1,5 +1,6 @@
#!/bin/bash
-# Copyright © 2014 Luke Shumaker <lukeshu@sbcglobal.net>
+# Copyright © 2014, 2016 Luke Shumaker <lukeshu@sbcglobal.net>
+#
# This work is free. You can redistribute it and/or modify it under the
# terms of the Do What The Fuck You Want To Public License, Version 2,
# as published by Sam Hocevar. See the COPYING file for more details.
@@ -8,46 +9,144 @@
# GNU/Linux-libre, those are the 'gitget' and 'librelib' packages,
# respectively.
#
-# For other systems, the both live at:
-# https://projects.parabolagnulinux.org/packages/libretools.git/
+# For other systems, they both live at:
+# https://git.parabola.nu/packages/libretools.git/
set -o pipefail
set -e
. libremessages
-config-get() {
- [[ $# == 1 ]] || panic
- git config --file "$conf_file" --get "$1"
+usage() {
+ print 'Usage %s CONFIG-FILE' "${0##*/}"
}
-list-repos() {
- [[ $# == 0 ]] || panic
- git config --file "$conf_file" --list | cut -s -d. -f2 | sort -u
+main() {
+ if [[ $# != 1 ]]; then
+ usage
+ exit
+ fi
+ declare -g cfg_file="$1"
+
+ local r=0
+ while read -r repo; do
+ handle-repo "$repo" || r=$?
+ done < <(cfg-list-repos)
+ return $r
}
-mirror-repo() {
+handle-repo() {
[[ $# == 1 ]] || panic
- repo=$1
- canonical_path="$(config-get "repo.${repo}.canonical")"
- local_path="$(config-get "repo.${repo}.local")"
- description="$(config-get "repo.${repo}.description" || printf 'mirror of %s' "${canonical_path}")"
+ local repo=$1
+ local local url upstream downstreams downstream r=0
+
+ # read configuration
+ local="$(cfg-get "repo.$repo.local")"
+ url="$(cfg-get "repo.$repo.url")" || true
+ upstream="$(cfg-get "repo.$repo.upstream")" || true
+ downstreams=($(cfg-get-all "repo.$repo.downstream")) || true
- gitget -f -n "$repo" bare "$canonical_path" "$local_path"
- printf '%s\n' "$description" > "$local_path/description.tmp"
- mv -- "$local_path/description.tmp" "$local_path/description"
+ # download
+ if [[ -n "$upstream" ]]; then
+ download "$upstream" "$local"
+ fi
+
+ # ensure that $local exists
+ test -f "$local"/HEAD
+
+ # upload
+ for downstream in "${downstreams[@]}"; do
+ upload "$url" "$local" "$downstream" || r=$?
+ done
+
+ return $r
}
-usage() {
- print 'Usage %s CONFIG-FILE' "${0##*/}"
+download() {
+ [[ $# == 3 ]] || panic
+ local repo=$1
+ local remote=$2
+ local local=$3
+
+ # download the repository
+ local url
+ url="$(remote "$remote" pull-url)"
+ gitget -f -n "$repo" "$url" "$local"
+ # download the metadata
+ remote "$remote" get-meta > "$local/git-mirror.tmp"
+ git config --file "$local/config" --rename-section git-mirror git-mirror-bak
+ local IFS='='
+ while read -r key val; do
+ git config --file "$local/config" --add git-mirror."$key" "$val"
+ done < "$local/git-mirror.tmp"
+ rm -f "$local/git-mirror.tmp"
+ git config --file "$local/config" --remove-section git-mirror-bak
}
-main() {
- if [[ $# != 1 ]]; then
- usage
- exit
+upload() {
+ [[ $# == 3 ]] || panic
+ local clonable_url=$1
+ local local=$2
+ local remote=$3
+
+ # push metadata
+ {
+ printf '%q ' set-meta "${remote#*:}"
+ [[ -z "$clonable_url" ]] || printf '%q ' "mirror=$clonable_url"
+ git config --file "$local/config" --get-regexp '^git-mirror[.]' -z|sed -z 's/ /=/'|xargs -0r printf '%q '
+ } | account "${remote%%:*}"
+ # push repository
+ local repo_mode
+ repo_mode=$(remote "$remote" repo-mode)
+ if [[ $repo_mode == push ]]; then
+ local push_url
+ push_url="$(remote "$remote" push-url)"
+ cd "$local" && git push --mirror "$push_url"
fi
- declare -g conf_file="$1"
- while read -r repo; do mirror-repo "$repo"; done < <(list-repos)
+}
+
+# Spawn an 'account.type' helper. It will read commands from stdin.
+account() {
+ [[ $# == 1 ]] || panic
+ local account=$1
+
+ local account_type
+ account_type="$(cfg-get "account.$account.type")"
+
+ {
+ cfg --list -z|sed -zn "s=^account[.]$account[.]=config =p"|grep -z -v '^type='|xargs -r0 printf '%s\n'
+ cat
+ } | git mirror-"$type" "$account"
+}
+
+# `account` is awkward to use; so let's wrap it.
+remote() {
+ [[ $# > 1 ]] || panic
+ local remote=$1
+
+ [[ $remote = *:* ]]
+ local account="${remote%%:*}"
+ local path="${remote#*:}"
+
+ printf '%q ' "$2" "$path" "${@:3}" | account "$account"
+}
+
+cfg() {
+ git config --file "$cfg_file" "$@"
+}
+
+cfg-get() {
+ [[ $# == 1 ]] || panic
+ cfg --get-all "$1"
+}
+
+cfg-get-all() {
+ [[ $# == 1 ]] || panic
+ cfg --get-all "$1"
+}
+
+cfg-list-repos() {
+ [[ $# == 0 ]] || panic
+ cfg --name-only --get-regexp '^repo[.].*[.].*$' -z|sed -z -e 's|^repo[.]||' -e 's|[.][^.]*$||'|sort -zu|xargs -r0 printf '%s\n'
}
main "$@"