git-2.eclass: Add exclusive file locking on EGIT_DIR
Packages that try to check out the same git directory sometimes race and
generate build errors due to git lock contention. This CL adds a file
lock around all of the git operations once EGIT_DIR has been set up so
that packages will block on contended git access rather than potentially
error. Additionally, clean up the logic around whether or not a git
checkout is in a valid state and needs to be cleaned up.
BUG=chromium:988143, chromium:991580
TEST=`build_packages --board=grunt` succeeds at building everything from source
Change-Id: Ia1850060297da7da2b0ca74b75ec2b2c0dc4e961
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/overlays/eclass-overlay/+/1726273
Tested-by: Chris McDonald <cjmcdonald@chromium.org>
Commit-Queue: Chris McDonald <cjmcdonald@chromium.org>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
diff --git a/eclass/git-2.eclass b/eclass/git-2.eclass
index 34a5527..fdc2f18 100644
--- a/eclass/git-2.eclass
+++ b/eclass/git-2.eclass
@@ -384,7 +384,29 @@
[[ ${EGIT_LOCAL_NONBARE} ]] && repo_type="non-bare repository" || repo_type="bare repository"
- if [[ ! -d ${EGIT_DIR} ]]; then
+ # Acquire a file lock on EGIT_DIR so that concurrent emerge jobs don't hit
+ # errors due to git contention.
+ [[ -z "${EGIT_DIR}" ]] && die "EGIT_DIR is unset!"
+ mkdir -p "$(dirname "${EGIT_DIR}")"
+ # Strip all trailing slashes from EGIT_DIR and add suffix to generate a
+ # canonical lockfile location for a given git repository.
+ # This lockfile can't be in EGIT_DIR itself because that directory must be
+ # empty for an initial clone to succeed.
+ local lockfile="$(realpath -m "${EGIT_DIR}")-EMERGE_LOCKFILE"
+ exec 200>"${lockfile}" || \
+ die "Unable to access file lock in EGIT_DIR: ${EGIT_DIR}"
+ flock -x 200
+
+ # If the repo directory is corrupt, delete EGIT_DIR to force a fresh clone.
+ if [[ -d "${EGIT_DIR}" ]]; then
+ git -C "${EGIT_DIR}" rev-parse HEAD &>/dev/null
+ if [[ $? -ne 0 ]]; then
+ ewarn "Existing git repo corrupt, removing and initialing clean checkout in ${EGIT_DIR}"
+ rm -rf "${EGIT_DIR}"
+ fi
+ fi
+
+ if [[ ! -d "${EGIT_DIR}" ]]; then
git-2_initial_clone
pushd "${EGIT_DIR}" > /dev/null || die
cursha=$(git rev-parse ${UPSTREAM_BRANCH})
@@ -421,6 +443,11 @@
git --no-pager diff --stat ${oldsha}..${UPSTREAM_BRANCH}
popd > /dev/null || die
fi
+
+ # Be sure to drop our file lock and close the file descriptor.
+ flock -u 200
+ exec 200>&-
+
# export the version the repository is at
export EGIT_VERSION="${cursha}"
# log the repo state