diff --git a/README.md b/README.md index 30c07d8..2207dca 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,11 @@ A script for use as a git mergetool; runs Emacs ediff as the mergetool. Lists all the authors of commits in a git repository. [Documentation](git-authors) at top of file. +### git-clone-or-pull + +Either clones a repository, or pulls it if it is already cloned. +[Documentation](git-clone-or-pull) at top of file. + ### git-clone-related Clones a repository related to the one where this script is called, trying diff --git a/git-clone-or-pull b/git-clone-or-pull new file mode 100755 index 0000000..8d6c2c7 --- /dev/null +++ b/git-clone-or-pull @@ -0,0 +1,60 @@ +#!/bin/sh + +# git-clone-or-pull: clone a GitHub repository, or pull it if already cloned. +# +# Usage: git-clone-or-pull ORG REPO_NAME [DESTINATION_PARENT] [GIT_CLONE_ARGS...] +# ORG is the GitHub organization +# REPO_NAME is the repository name (without the organization) +# DESTINATION_PARENT is the directory that contains the clone directory. It +# defaults to the current directory. +# GIT_CLONE_ARGS is extra arguments to git clone. It defaults to +# "-q --single-branch --depth 1" (without the quotes). +# It is not used if the destination already exists. + +SCRIPT_NAME="$(basename "$0")" + +if [ "$#" -lt 2 ]; then + echo "Usage: ${SCRIPT_NAME} ORG REPO_NAME [DESTINATION_PARENT] [GIT_CLONE_ARGS...]" >&2 + exit 1 +fi + +beginswith() { case $2 in "$1"*) true ;; *) false ;; esac } + +ORG=$1 +shift +REPO_NAME=$1 +shift +DESTINATION_PARENT=. +if [ "$#" -ne 0 ]; then + if ! beginswith "-" "$1"; then + # Does not start with "-" and therefore isn't a command-line argument. + DESTINATION_PARENT=$1 + shift + if [ ! -d "${DESTINATION_PARENT}" ]; then + mkdir -p "${DESTINATION_PARENT}" + fi + fi +fi +if [ "$#" -eq 0 ]; then + # Default command-line arguments. + set -- -q --single-branch --depth 1 +fi + +REPO_URL="https://github.com/${ORG}/${REPO_NAME}.git" +DESTINATION="${DESTINATION_PARENT:?}/${REPO_NAME}" + +# Try twice in case of network lossage. 60 seconds is not enough to clone a branch of the JDK. +if test -d "${DESTINATION}"; then + (cd "${DESTINATION}" && (timeout 180 git pull -q || (sleep 1m && (timeout 180 git pull || true)))) +else + if ! timeout 180 git clone "$@" "${REPO_URL}" "${DESTINATION}"; then + rm -rf "${DESTINATION}" + sleep 180 + if ! timeout 180 git clone "$@" "${REPO_URL}" "${DESTINATION}"; then + echo "Failed to clone ${REPO_URL}" + exit 1 + fi + fi +fi + +echo "${SCRIPT_NAME}: ${REPO_NAME} is at $(cd "${DESTINATION}" && git rev-parse HEAD)" diff --git a/git-clone-related b/git-clone-related index 2b12450..5b24970 100755 --- a/git-clone-related +++ b/git-clone-related @@ -175,15 +175,16 @@ else fi echo "${SCRIPT_NAME}: About to run: git clone -q -b ${REPO_BRANCH} $* ${REPO_URL} ${DESTINATION}" # Try twice in case of network lossage. 60 seconds is not enough to clone a branch of the JDK. - timeout 180 git clone -q -b "${REPO_BRANCH}" "$@" "${REPO_URL}" "${DESTINATION}" \ - || { echo "Retrying 'git clone ... ${REPO_URL} ${DESTINATION}' after timeout" \ - && rm -rf "${DESTINATION}" \ - && sleep 180 \ - && { timeout 180 git clone -q -b "${REPO_BRANCH}" "$@" "${REPO_URL}" "${DESTINATION}" \ - || { - echo "${SCRIPT_NAME}: failed: git clone -q -b ${REPO_BRANCH}" "$@" "${REPO_URL} ${DESTINATION}" - exit 2 - }; }; } + if ! timeout 180 git clone -q -b "${REPO_BRANCH}" "$@" "${REPO_URL}" "${DESTINATION}"; then + echo "Retrying 'git clone ... ${REPO_URL} ${DESTINATION}'" + rm -rf "${DESTINATION}" + sleep 180 + if ! timeout 180 git clone -b "${REPO_BRANCH}" "$@" "${REPO_URL}" "${DESTINATION}"; then + echo "${SCRIPT_NAME}: failed: git clone -b ${REPO_BRANCH}" "$@" "${REPO_URL} ${DESTINATION}" + exit 2 + fi + fi + fi echo "${SCRIPT_NAME}: ${DESTINATION} is at $(cd "${DESTINATION}" && git rev-parse HEAD)" diff --git a/tests/git-clone-related-test/test-git-clone-related.sh b/tests/git-clone-related-test/test-git-clone-related.sh index 3974014..39f4405 100755 --- a/tests/git-clone-related-test/test-git-clone-related.sh +++ b/tests/git-clone-related-test/test-git-clone-related.sh @@ -15,6 +15,9 @@ ARGS=$3 GOAL_REPO=$4 GOAL_BRANCH=$5 +DEBUG= +# DEBUG=--debug + set -o errexit -o nounset # set -o pipefail @@ -38,10 +41,10 @@ unset TRAVIS unset CIRCLE_COMPARE_URL unset GITHUB_HEAD_REF -echo "$0: About to run: (cd $startdir && ${GIT_SCRIPTS}/git-clone-related $ARGS $resultdir)" -# shellcheck disable=SC2086 # $ARGS should not be quoted -(cd "$startdir" && "${GIT_SCRIPTS}"/git-clone-related $ARGS "$resultdir") -echo "$0: Done: (cd $startdir && ${GIT_SCRIPTS}/git-clone-related $ARGS $resultdir)" +echo "$0: About to run: (cd $startdir && ${GIT_SCRIPTS}/git-clone-related $DEBUG $ARGS $resultdir)" +# shellcheck disable=SC2086 # $DEBUG and $ARGS should not be quoted +(cd "$startdir" && "${GIT_SCRIPTS}"/git-clone-related $DEBUG $ARGS "$resultdir") +echo "$0: Done: (cd $startdir && ${GIT_SCRIPTS}/git-clone-related $DEBUG $ARGS $resultdir)" clonedrepo=$(git -C "$resultdir" config --get remote.origin.url) # git 2.22 and later has `git branch --show-current`; CircleCI doesn't have that version yet.