git 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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. # Options:
  7. # -q Be quiet.
  8. # -r Clone and archive sub-modules.
  9. # -o FILE Generate archive in FILE.
  10. # -u URI Clone from repository at URI.
  11. # -c CSET Use changeset CSET.
  12. # -n NAME Use basename NAME.
  13. #
  14. # Environment:
  15. # GIT : the git command to call
  16. verbose=
  17. recurse=0
  18. while getopts "${BR_BACKEND_DL_GETOPTS}" OPT; do
  19. case "${OPT}" in
  20. q) verbose=-q; exec >/dev/null;;
  21. r) recurse=1;;
  22. o) output="${OPTARG}";;
  23. u) uri="${OPTARG}";;
  24. c) cset="${OPTARG}";;
  25. d) dl_dir="${OPTARG}";;
  26. n) basename="${OPTARG}";;
  27. :) printf "option '%s' expects a mandatory argument\n" "${OPTARG}"; exit 1;;
  28. \?) printf "unknown option '%s'\n" "${OPTARG}" >&2; exit 1;;
  29. esac
  30. done
  31. shift $((OPTIND-1)) # Get rid of our options
  32. # We want to check if a cache of the git clone of this repo already exists.
  33. git_cache="${dl_dir}/git"
  34. # Caller needs to single-quote its arguments to prevent them from
  35. # being expanded a second time (in case there are spaces in them)
  36. _git() {
  37. eval GIT_DIR="${git_cache}/.git" ${GIT} "${@}"
  38. }
  39. # Create a warning file, that the user should not use the git cache.
  40. # It's ours. Our precious.
  41. cat <<-_EOF_ >"${dl_dir}/git.readme"
  42. IMPORTANT NOTE!
  43. The git tree located in this directory is for the exclusive use
  44. by Buildroot, which uses it as a local cache to reduce bandwidth
  45. usage.
  46. Buildroot *will* trash any changes in that tree whenever it needs
  47. to use it. Buildroot may even remove it in case it detects the
  48. repository may have been damaged or corrupted.
  49. Do *not* work in that directory; your changes will eventually get
  50. lost. Do *not* even use it as a remote, or as the source for new
  51. worktrees; your commits will eventually get lost.
  52. _EOF_
  53. # Initialise a repository in the git cache. If the repository already
  54. # existed, this is a noop, unless the repository was broken, in which
  55. # case this magically restores it to working conditions. In the latter
  56. # case, we might be missing blobs, but that's not a problem: we'll
  57. # fetch what we need later anyway.
  58. #
  59. # We can still go through the wrapper, because 'init' does not use the
  60. # path pointed to by GIT_DIR, but really uses the directory passed as
  61. # argument.
  62. _git init "'${git_cache}'"
  63. pushd "${git_cache}" >/dev/null
  64. # Ensure the repo has an origin (in case a previous run was killed).
  65. if ! _git remote |grep -q -E '^origin$'; then
  66. _git remote add origin "'${uri}'"
  67. fi
  68. _git remote set-url origin "'${uri}'"
  69. # Try to fetch with limited depth, since it is faster than a full clone - but
  70. # that only works if the version is a ref (tag or branch). Before trying to do
  71. # a shallow clone we check if ${cset} is in the list provided by git ls-remote.
  72. # If not we fallback to a full fetch.
  73. #
  74. # Messages for the type of clone used are provided to ease debugging in
  75. # case of problems
  76. git_done=0
  77. if [ -n "$(_git ls-remote origin "'${cset}'" 2>&1)" ]; then
  78. printf "Doing a shallow fetch\n"
  79. if _git fetch "${@}" --depth 1 origin "'${cset}'"; then
  80. git_done=1
  81. else
  82. printf "Shallow fetch failed, falling back to fetching all refs\n"
  83. fi
  84. fi
  85. if [ ${git_done} -eq 0 ]; then
  86. printf "Fetching all references\n"
  87. _git fetch origin
  88. _git fetch origin -t
  89. fi
  90. # Try to get the special refs exposed by some forges (pull-requests for
  91. # github, changes for gerrit...). There is no easy way to know whether
  92. # the cset the user passed us is such a special ref or a tag or a sha1
  93. # or whatever else. We'll eventually fail at checking out that cset,
  94. # below, if there is an issue anyway. Since most of the cset we're gonna
  95. # have to clone are not such special refs, consign the output to oblivion
  96. # so as not to alarm unsuspecting users, but still trace it as a warning.
  97. if ! _git fetch origin "'${cset}:${cset}'" >/dev/null 2>&1; then
  98. printf "Could not fetch special ref '%s'; assuming it is not special.\n" "${cset}"
  99. fi
  100. # Checkout the required changeset, so that we can update the required
  101. # submodules.
  102. _git checkout -q "'${cset}'"
  103. # Get date of commit to generate a reproducible archive.
  104. # %cD is RFC2822, so it's fully qualified, with TZ and all.
  105. date="$( _git log -1 --pretty=format:%cD )"
  106. # There might be submodules, so fetch them.
  107. if [ ${recurse} -eq 1 ]; then
  108. _git submodule update --init --recursive
  109. fi
  110. # Generate the archive, sort with the C locale so that it is reproducible.
  111. # We do not want the .git dir; we keep other .git files, in case they are the
  112. # only files in their directory.
  113. # The .git dir would generate non reproducible tarballs as it depends on
  114. # the state of the remote server. It also would generate large tarballs
  115. # (gigabytes for some linux trees) when a full clone took place.
  116. find . -not -type d \
  117. -and -not -path "./.git/*" >"${output}.list"
  118. LC_ALL=C sort <"${output}.list" >"${output}.list.sorted"
  119. # Create GNU-format tarballs, since that's the format of the tarballs on
  120. # sources.buildroot.org and used in the *.hash files
  121. tar cf - --transform="s#^\./#${basename}/#" \
  122. --numeric-owner --owner=0 --group=0 --mtime="${date}" --format=gnu \
  123. -T "${output}.list.sorted" >"${output}.tar"
  124. gzip -6 -n <"${output}.tar" >"${output}"
  125. rm -f "${output}.list"
  126. rm -f "${output}.list.sorted"
  127. popd >/dev/null