From 4974d0297cff29aa3d3731782e0fc661be31530b Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Thu, 15 Dec 2016 02:07:07 -0500 Subject: wip --- git-mirror | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 124 insertions(+), 25 deletions(-) (limited to 'git-mirror') 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 +# Copyright © 2014, 2016 Luke Shumaker +# # 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 "$@" -- cgit v1.2.3