git 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #!/usr/bin/env bash
  2. # We want to catch any unexpected failure, and exit immediately
  3. set -e
  4. # Download helper for git, to be called from the download wrapper script
  5. #
  6. # Call it as:
  7. # .../git [-q] [-r] OUT_FILE REPO_URL CSET BASENAME
  8. #
  9. # -q Be quiet.
  10. # -r Clone and archive sub-modules.
  11. #
  12. # Environment:
  13. # GIT : the git command to call
  14. verbose=
  15. recurse=0
  16. while getopts :qr OPT; do
  17. case "${OPT}" in
  18. q) verbose=-q; exec >/dev/null;;
  19. r) recurse=1;;
  20. \?) printf "unknown option '%s'\n" "${OPTARG}" >&2; exit 1;;
  21. esac
  22. done
  23. shift $((OPTIND-1))
  24. output="${1}"
  25. repo="${2}"
  26. cset="${3}"
  27. basename="${4}"
  28. # Caller needs to single-quote its arguments to prevent them from
  29. # being expanded a second time (in case there are spaces in them)
  30. _git() {
  31. eval ${GIT} "${@}"
  32. }
  33. # Try a shallow clone, since it is faster than a full clone - but that only
  34. # works if the version is a ref (tag or branch). Before trying to do a shallow
  35. # clone we check if ${cset} is in the list provided by git ls-remote. If not
  36. # we fall back on a full clone.
  37. #
  38. # Messages for the type of clone used are provided to ease debugging in case of
  39. # problems
  40. git_done=0
  41. if [ -n "$(_git ls-remote "'${repo}'" "'${cset}'" 2>&1)" ]; then
  42. printf "Doing shallow clone\n"
  43. if _git clone ${verbose} --depth 1 -b "'${cset}'" "'${repo}'" "'${basename}'"; then
  44. git_done=1
  45. else
  46. printf "Shallow clone failed, falling back to doing a full clone\n"
  47. fi
  48. fi
  49. if [ ${git_done} -eq 0 ]; then
  50. printf "Doing full clone\n"
  51. _git clone ${verbose} "'${repo}'" "'${basename}'"
  52. fi
  53. pushd "${basename}" >/dev/null
  54. # Try to get the special refs exposed by some forges (pull-requests for
  55. # github, changes for gerrit...). There is no easy way to know whether
  56. # the cset the user passed us is such a special ref or a tag or a sha1
  57. # or whatever else. We'll eventually fail at checking out that cset,
  58. # below, if there is an issue anyway. Since most of the cset we're gonna
  59. # have to clone are not such special refs, consign the output to oblivion
  60. # so as not to alarm unsuspecting users, but still trace it as a warning.
  61. if ! _git fetch origin "'${cset}:${cset}'" >/dev/null 2>&1; then
  62. printf "Could not fetch special ref '%s'; assuming it is not special.\n" "${cset}"
  63. fi
  64. # Checkout the required changeset, so that we can update the required
  65. # submodules.
  66. _git checkout -q "'${cset}'"
  67. # Get date of commit to generate a reproducible archive.
  68. # %cD is RFC2822, so it's fully qualified, with TZ and all.
  69. date="$( _git log -1 --pretty=format:%cD )"
  70. # There might be submodules, so fetch them.
  71. if [ ${recurse} -eq 1 ]; then
  72. _git submodule update --init --recursive
  73. fi
  74. # We do not need the .git dir; we keep other .git files, in case they
  75. # are the only files in their directory.
  76. rm -rf .git
  77. popd >/dev/null
  78. # Generate the archive, sort with the C locale so that it is reproducible
  79. tar cf - --numeric-owner --owner=0 --group=0 --mtime="${date}" \
  80. -T <(find "${basename}" -not -type d |LC_ALL=C sort) \
  81. |gzip -n >"${output}"