[Buildroot] [TO-BE-TESTED] support/download/hg: implement repository cache

Thomas De Schampheleire patrickdepinguin at gmail.com
Tue Feb 5 20:24:33 UTC 2019


From: Thomas De Schampheleire <thomas.de_schampheleire at nokia.com>

Similar to the git download helper, implement a repository cache for
Mercurial repositories.

The code is mostly guided by the implementation for git, with certain parts
copied almost verbatim.

Signed-off-by: Thomas De Schampheleire <thomas.de_schampheleire at nokia.com>
---
 support/download/hg | 81 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 78 insertions(+), 3 deletions(-)

Note: this patch only got limited testing so far and needs to be tested further.
But I already wanted to send it out for feedback and for those of you that want
to help test it.


diff --git a/support/download/hg b/support/download/hg
index efb515fca5..bb5cc87969 100755
--- a/support/download/hg
+++ b/support/download/hg
@@ -1,7 +1,7 @@
 #!/usr/bin/env bash
 
 # We want to catch any unexpected failure, and exit immediately
-set -e
+set -E
 
 # Download helper for hg, to be called from the download wrapper script
 #
@@ -10,11 +10,39 @@ set -e
 #   -o FILE     Generate archive in FILE.
 #   -u URI      Clone from repository at URI.
 #   -c CSET     Use changeset (or revision) CSET.
+#   -d DLDIR    Download directory path.
 #   -n NAME     Use basename NAME.
 #
 # Environment:
 #   HG       : the hg command to call
 
+# Save our path and options in case we need to call ourselves again
+myname="${0}"
+declare -a OPTS=("${@}")
+
+# This function is called when an error occurs. Its job is to attempt a clone
+# from scratch (only once!) in case the hg tree is borked, or in case an
+# unexpected and unsupported situation arises with uncommitted stuff (e.g. if
+# the user manually mucked around in the hg cache).
+# Note that this function would also be triggered by connection errors during
+# the clone/pull.
+_on_error() {
+    local ret=${?}
+
+    printf "Detected a possibly corrupted hg cache.\n" >&2
+    if ${BR_HG_BACKEND_FIRST_FAULT:-false}; then
+        printf "This is the second time in a row; bailing out\n" >&2
+        exit ${ret}
+    fi
+    export BR_HG_BACKEND_FIRST_FAULT=true
+
+    printf "Removing it and starting afresh.\n" >&2
+
+    rm -rf "${hg_cache}"
+
+    exec "${myname}" "${OPTS[@]}" || exit ${ret}
+}
+
 verbose=
 while getopts "${BR_BACKEND_DL_GETOPTS}" OPT; do
     case "${OPT}" in
@@ -22,6 +50,7 @@ while getopts "${BR_BACKEND_DL_GETOPTS}" OPT; do
     o)  output="${OPTARG}";;
     u)  uri="${OPTARG}";;
     c)  cset="${OPTARG}";;
+    d)  dl_dir="${OPTARG}";;
     n)  basename="${OPTARG}";;
     :)  printf "option '%s' expects a mandatory argument\n" "${OPTARG}"; exit 1;;
     \?) printf "unknown option '%s'\n" "${OPTARG}" >&2; exit 1;;
@@ -36,8 +65,54 @@ _hg() {
     eval ${HG} "${@}"
 }
 
-_hg clone ${verbose} "${@}" --noupdate "'${uri}'" "'${basename}'"
+# Create and cd into the directory that will contain the local hg cache
+hg_cache="${dl_dir}/hg"
+mkdir -p "${hg_cache}"
+
+# Any error now should try to recover
+trap _on_error ERR
+
+# Create a warning file, that the user should not use the hg cache.
+# It's ours. Our precious.
+cat <<-_EOF_ >"${dl_dir}/hg.readme"
+	IMPORTANT NOTE!
+
+	The hg tree located in this directory is for the exclusive use
+	by Buildroot, which uses it as a local cache to reduce bandwidth
+	usage.
+
+	Buildroot *will* trash any changes in that tree whenever it needs
+	to use it. Buildroot may even remove it in case it detects the
+	repository may have been damaged or corrupted.
+
+	Do *not* work in that directory; your changes will eventually get
+	lost. Do *not* even use it as a remote, or as the source for new
+	worktrees; your commits will eventually get lost.
+_EOF_
+
+if ! [ -d "${hg_cache}/.hg" ]; then
+    # While it would be possible to create an empty repo and use pull
+    # subsequently, we intentionally use clone the first time as it could be
+    # faster than pull thanks to clonebundles, if enabled on the server.
+    printf "Cloning repository from '${uri}' into '${hg_cache}'\n"
+    _hg clone ${verbose} "${@}" --noupdate "'${uri}'" "'${hg_cache}'"
+else
+    printf "Pulling repository from '${uri}' into '${hg_cache}'\n"
+    _hg pull ${verbose} "${@}" --repository "'${hg_cache}'" "'${uri}'"
+fi
+
+# Check that the changeset does exist. If it does not, re-cloning from
+# scratch won't help, so we don't want to trash the repository for a
+# missing commit. We just exit without going through the ERR trap.
+if ! _hg identify --repository "'${hg_cache}'" --rev "'${cset}'" >/dev/null 2>&1; then
+    printf "Commit '%s' does not exist in this repository\n." "${cset}"
+    exit 1
+fi
+
+# Make sure that there is no working directory. This will clear any user
+# temptation to work in this directory.
+_hg update --repository "'${hg_cache}'" null >/dev/null 2>&1
 
-_hg archive ${verbose} --repository "'${basename}'" --type tgz \
+_hg archive ${verbose} --repository "'${hg_cache}'" --type tgz \
             --prefix "'${basename}'" --rev "'${cset}'" \
             - >"${output}"
-- 
2.19.2



More information about the buildroot mailing list