git 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  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. shift 4 # Get rid of our options
  29. # Caller needs to single-quote its arguments to prevent them from
  30. # being expanded a second time (in case there are spaces in them)
  31. _git() {
  32. eval ${GIT} "${@}"
  33. }
  34. # Try a shallow clone, since it is faster than a full clone - but that only
  35. # works if the version is a ref (tag or branch). Before trying to do a shallow
  36. # clone we check if ${cset} is in the list provided by git ls-remote. If not
  37. # we fall back on a full clone.
  38. #
  39. # Messages for the type of clone used are provided to ease debugging in case of
  40. # problems
  41. git_done=0
  42. if [ -n "$(_git ls-remote "'${repo}'" "'${cset}'" 2>&1)" ]; then
  43. printf "Doing shallow clone\n"
  44. if _git clone ${verbose} "${@}" --depth 1 -b "'${cset}'" "'${repo}'" "'${basename}'"; then
  45. git_done=1
  46. else
  47. printf "Shallow clone failed, falling back to doing a full clone\n"
  48. fi
  49. fi
  50. if [ ${git_done} -eq 0 ]; then
  51. printf "Doing full clone\n"
  52. _git clone ${verbose} "${@}" "'${repo}'" "'${basename}'"
  53. fi
  54. pushd "${basename}" >/dev/null
  55. # Try to get the special refs exposed by some forges (pull-requests for
  56. # github, changes for gerrit...). There is no easy way to know whether
  57. # the cset the user passed us is such a special ref or a tag or a sha1
  58. # or whatever else. We'll eventually fail at checking out that cset,
  59. # below, if there is an issue anyway. Since most of the cset we're gonna
  60. # have to clone are not such special refs, consign the output to oblivion
  61. # so as not to alarm unsuspecting users, but still trace it as a warning.
  62. if ! _git fetch origin "'${cset}:${cset}'" >/dev/null 2>&1; then
  63. printf "Could not fetch special ref '%s'; assuming it is not special.\n" "${cset}"
  64. fi
  65. # Checkout the required changeset, so that we can update the required
  66. # submodules.
  67. _git checkout -q "'${cset}'"
  68. # Get date of commit to generate a reproducible archive.
  69. # %cD is RFC2822, so it's fully qualified, with TZ and all.
  70. date="$( _git log -1 --pretty=format:%cD )"
  71. # There might be submodules, so fetch them.
  72. if [ ${recurse} -eq 1 ]; then
  73. _git submodule update --init --recursive
  74. fi
  75. # We do not need the .git dir; we keep other .git files, in case they
  76. # are the only files in their directory.
  77. rm -rf .git
  78. popd >/dev/null
  79. # Generate the archive, sort with the C locale so that it is reproducible
  80. find "${basename}" -not -type d >"${basename}.list"
  81. LC_ALL=C sort <"${basename}.list" >"${basename}.list.sorted"
  82. tar cf - --numeric-owner --owner=0 --group=0 --mtime="${date}" \
  83. -T "${basename}.list.sorted" >"${output}.tar"
  84. gzip -n <"${output}.tar" >"${output}"