git-cache 3.56 KB
#!/bin/sh

git_cache() {
    git -C "${GIT_CACHE_DIR}" $*
}

init() {
    set -ex
    local _git_dir="$(git_cache rev-parse --git-dir 2>/dev/null)"
    test "$_git_dir" == "." -o "$_git_dir" == ".git" || {
        mkdir -p "${GIT_CACHE_DIR}"

        git_cache init --bare
        git_cache config core.compression 1
    }
    set +ex
}

add() {
    set -ex
    if [ $# -eq 1 ]; then
        local repo="$1"
        local name="$(_remote_name $repo)"
    else
        local repo="$1"
        local name="$2"
    fi

    if ! is_cached "$repo"; then
        git_cache remote add "$name" "$repo"
    else
        echo "git-cache: $url already in cache"
    fi
    set +ex
}

update() {
    set -ex
    local REMOTE=${1:---all}
    git_cache fetch $REMOTE
    set +ex
}

is_cached() {
    set +ex
    local url="$1"
    local REMOTES="$(git_cache remote show)"
    for remote in $REMOTES; do
        test "$(git_cache remote get-url $remote)" == "$url" && return 0
    done
    set -ex
    return 1
}

list() {
    local REMOTES="$(git_cache remote show)"
    for remote in $REMOTES; do
        echo "${remote}: $(git_cache remote get-url $remote)"
    done
}

drop() {
    set -ex
    local REMOTE=${1}
    [ -z "$REMOTE" ] && {
        echo "usage: git cache drop <name>"
        exit 1
    }
    git_cache remote remove $REMOTE
    set +ex
}

_check_commit() {
    git_cache cat-file -e ${1}^{commit}
}

_remote_name() {
    basename "$*" .git
}

clone() {
    set -ex
    local REMOTE="${1}"
    local SHA1="${2}"
    local REMOTE_NAME="$(_remote_name $REMOTE)"
    local TARGET_PATH="${3:-${REMOTE_NAME}}"

    if [ "$GIT_CACHE_AUTOADD" == "1" ]; then
        if ! is_cached "$REMOTE"; then
            add "$REMOTE"
            update "$(_remote_name $REMOTE)"
        fi
    fi

    if _check_commit $2 2>&1; then
        git init "${TARGET_PATH}"
        git_cache tag commit$SHA1 $SHA1 || true # ignore possibly already existing tag
        git -C "${TARGET_PATH}" fetch --tags --depth=1 "${GIT_CACHE_DIR}" refs/tags/commit$SHA1
        git -C "${TARGET_PATH}" checkout FETCH_HEAD
    else
        git clone "${REMOTE}" "${TARGET_PATH}"
        git -C "${TARGET_PATH}" checkout $SHA1
    fi
    set +ex
}

usage() {
    echo "git cache uses a bare git repository containing all objects from multiple"
    echo "upstream git repositories."
    echo ""
    echo "usage:"
    echo ""
    echo "    git cache init                initialize git cache"
    echo "    git cache add <url> [<name>]  add repository <url> with name <name>"
    echo "                                  (if no name given, use \"basename $url .git\""
    echo "    git cache list                list cached repositories"
    echo "    git cache drop <name>         drop repo from cache"
    echo "    git cache update [<name>]     fetch repo named <name> (or all)"
    echo "    git cache clone <url> <SHA1>  clone repository <url> from cache"
    echo "    git cache show-path           print's the path that can be used as "
    echo "                                  '--reference' parameter"
    echo ""
    echo "To retrieve objects from cache (will use remote repository if needed):"
    echo '    git clone --reference $(git cache show-path) <repo>'
}

ACTION=$1
shift

export GIT_CACHE_DIR=${GIT_CACHE_DIR:-${HOME}/.gitcache}

case $ACTION in
    init)
        init $*
        ;;
    add)
        add $*
        ;;
    update)
        update $*
        ;;
    list)
        list $*
        ;;
    drop)
        drop $*
        ;;
    show-path)
        echo ${GIT_CACHE_DIR}
        ;;
    clone)
        clone $*
        ;;
    *)
        usage
        ;;
esac