]> Git Repo - buildroot-mgba.git/blame - support/download/git
download/git: ensure we checkout to a clean state
[buildroot-mgba.git] / support / download / git
CommitLineData
acc76a6e 1#!/usr/bin/env bash
95a57228 2
7e40a110 3# We want to catch any unexpected failure, and exit immediately
b7efb43e 4set -E
95a57228 5
7e40a110 6# Download helper for git, to be called from the download wrapper script
50c8b7e9 7#
91e776b5
YM
8# Options:
9# -q Be quiet.
10# -r Clone and archive sub-modules.
11# -o FILE Generate archive in FILE.
12# -u URI Clone from repository at URI.
13# -c CSET Use changeset CSET.
14# -n NAME Use basename NAME.
50c8b7e9
YM
15#
16# Environment:
19afad50 17# GIT : the git command to call
95a57228 18
b7efb43e
YM
19# Save our path and options in case we need to call ourselves again
20myname="${0}"
21declare -a OPTS=("${@}")
22
23# This function is called when an error occurs. Its job is to attempt a
24# clone from scratch (only once!) in case the git tree is borked, or in
25# case an unexpected and unsupported situation arises with submodules
26# or uncommitted stuff (e.g. if the user manually mucked around in the
27# git cache).
28_on_error() {
29 local ret=${?}
30
31 printf "Detected a corrupted git cache.\n" >&2
32 if ${BR_GIT_BACKEND_FIRST_FAULT:-false}; then
33 printf "This is the second time in a row; bailing out\n" >&2
34 exit ${ret}
35 fi
36 export BR_GIT_BACKEND_FIRST_FAULT=true
37
38 printf "Removing it and starting afresh.\n" >&2
39
40 popd >/dev/null
41 rm -rf "${git_cache}"
42
43 exec "${myname}" "${OPTS[@]}" || exit ${ret}
44}
45
3dea23cf 46verbose=
f109e7ee 47recurse=0
91e776b5 48while getopts "${BR_BACKEND_DL_GETOPTS}" OPT; do
50c8b7e9 49 case "${OPT}" in
4bf1174a 50 q) verbose=-q; exec >/dev/null;;
f109e7ee 51 r) recurse=1;;
91e776b5
YM
52 o) output="${OPTARG}";;
53 u) uri="${OPTARG}";;
54 c) cset="${OPTARG}";;
6d938bcb 55 d) dl_dir="${OPTARG}";;
91e776b5
YM
56 n) basename="${OPTARG}";;
57 :) printf "option '%s' expects a mandatory argument\n" "${OPTARG}"; exit 1;;
50c8b7e9
YM
58 \?) printf "unknown option '%s'\n" "${OPTARG}" >&2; exit 1;;
59 esac
60done
95a57228 61
91e776b5 62shift $((OPTIND-1)) # Get rid of our options
ff559846 63
57731568 64# Create and cd into the directory that will contain the local git cache
a07da16e 65git_cache="${dl_dir}/git"
57731568
YM
66mkdir -p "${git_cache}"
67pushd "${git_cache}" >/dev/null
a07da16e 68
b7efb43e
YM
69# Any error now should try to recover
70trap _on_error ERR
71
3f2bdd07
YM
72# Caller needs to single-quote its arguments to prevent them from
73# being expanded a second time (in case there are spaces in them)
74_git() {
a07da16e 75 eval GIT_DIR="${git_cache}/.git" ${GIT} "${@}"
3f2bdd07
YM
76}
77
f1eb192e
YM
78# Create a warning file, that the user should not use the git cache.
79# It's ours. Our precious.
80cat <<-_EOF_ >"${dl_dir}/git.readme"
81 IMPORTANT NOTE!
82
83 The git tree located in this directory is for the exclusive use
84 by Buildroot, which uses it as a local cache to reduce bandwidth
85 usage.
86
87 Buildroot *will* trash any changes in that tree whenever it needs
88 to use it. Buildroot may even remove it in case it detects the
89 repository may have been damaged or corrupted.
90
91 Do *not* work in that directory; your changes will eventually get
92 lost. Do *not* even use it as a remote, or as the source for new
93 worktrees; your commits will eventually get lost.
94_EOF_
95
d48a1b0d
YM
96# Initialise a repository in the git cache. If the repository already
97# existed, this is a noop, unless the repository was broken, in which
98# case this magically restores it to working conditions. In the latter
99# case, we might be missing blobs, but that's not a problem: we'll
100# fetch what we need later anyway.
101#
102# We can still go through the wrapper, because 'init' does not use the
103# path pointed to by GIT_DIR, but really uses the directory passed as
104# argument.
57731568 105_git init .
6d938bcb 106
6dfaa33d 107# Ensure the repo has an origin (in case a previous run was killed).
a07da16e 108if ! _git remote |grep -q -E '^origin$'; then
6dfaa33d
YM
109 _git remote add origin "'${uri}'"
110fi
111
6d938bcb
MH
112_git remote set-url origin "'${uri}'"
113
114# Try to fetch with limited depth, since it is faster than a full clone - but
115# that only works if the version is a ref (tag or branch). Before trying to do
116# a shallow clone we check if ${cset} is in the list provided by git ls-remote.
117# If not we fallback to a full fetch.
ef92d32f 118#
6d938bcb
MH
119# Messages for the type of clone used are provided to ease debugging in
120# case of problems
9d1ab432 121git_done=0
6d938bcb
MH
122if [ -n "$(_git ls-remote origin "'${cset}'" 2>&1)" ]; then
123 printf "Doing a shallow fetch\n"
124 if _git fetch "${@}" --depth 1 origin "'${cset}'"; then
ebe6154f 125 git_done=1
7e40a110 126 else
6d938bcb 127 printf "Shallow fetch failed, falling back to fetching all refs\n"
ebe6154f
YM
128 fi
129fi
130if [ ${git_done} -eq 0 ]; then
6d938bcb 131 printf "Fetching all references\n"
e2b71e85 132 _git fetch origin
6d938bcb 133 _git fetch origin -t
13c89c2f
YM
134fi
135
13c89c2f
YM
136# Try to get the special refs exposed by some forges (pull-requests for
137# github, changes for gerrit...). There is no easy way to know whether
138# the cset the user passed us is such a special ref or a tag or a sha1
139# or whatever else. We'll eventually fail at checking out that cset,
140# below, if there is an issue anyway. Since most of the cset we're gonna
141# have to clone are not such special refs, consign the output to oblivion
142# so as not to alarm unsuspecting users, but still trace it as a warning.
143if ! _git fetch origin "'${cset}:${cset}'" >/dev/null 2>&1; then
144 printf "Could not fetch special ref '%s'; assuming it is not special.\n" "${cset}"
95a57228
YM
145fi
146
b7efb43e
YM
147# Check that the changeset does exist. If it does not, re-cloning from
148# scratch won't help, so we don't want to trash the repository for a
149# missing commit. We just exit without going through the ERR trap.
428a0649
YM
150if ! _git rev-parse --quiet --verify "'${cset}^{commit}'" >/dev/null 2>&1; then
151 printf "Commit '%s' does not exist in this repository\n." "${cset}"
152 exit 1
153fi
154
f109e7ee
YM
155# Checkout the required changeset, so that we can update the required
156# submodules.
3d2e0188
YM
157_git checkout -f -q "'${cset}'"
158
159# Get rid of now-untracked directories (in case a git operation was
160# interrupted in a previous run).
161_git clean -ffdx
3abd5ba4
YM
162
163# Get date of commit to generate a reproducible archive.
164# %cD is RFC2822, so it's fully qualified, with TZ and all.
1e39f087 165date="$( _git log -1 --pretty=format:%cD )"
3abd5ba4 166
f109e7ee
YM
167# There might be submodules, so fetch them.
168if [ ${recurse} -eq 1 ]; then
169 _git submodule update --init --recursive
170fi
171
6d938bcb
MH
172# Generate the archive, sort with the C locale so that it is reproducible.
173# We do not want the .git dir; we keep other .git files, in case they are the
174# only files in their directory.
5d6ec40b
RM
175# The .git dir would generate non reproducible tarballs as it depends on
176# the state of the remote server. It also would generate large tarballs
177# (gigabytes for some linux trees) when a full clone took place.
6d938bcb
MH
178find . -not -type d \
179 -and -not -path "./.git/*" >"${output}.list"
180LC_ALL=C sort <"${output}.list" >"${output}.list.sorted"
95a57228 181
0f369a92
AV
182# Create GNU-format tarballs, since that's the format of the tarballs on
183# sources.buildroot.org and used in the *.hash files
6e2f5d02
YM
184tar cf - --transform="s#^\./#${basename}/#" \
185 --numeric-owner --owner=0 --group=0 --mtime="${date}" --format=gnu \
6d938bcb 186 -T "${output}.list.sorted" >"${output}.tar"
04a22cf1 187gzip -6 -n <"${output}.tar" >"${output}"
6d938bcb
MH
188
189rm -f "${output}.list"
190rm -f "${output}.list.sorted"
191
192popd >/dev/null
This page took 0.537678 seconds and 4 git commands to generate.