update-common.sh: synchronize with upstream

Of note is the support for finding imports with matching trees, not just
commits.
This commit is contained in:
Ben Boeckel
2025-11-07 15:00:41 -05:00
parent 98e410c4db
commit 1b03059674
+59 -17
View File
@@ -5,7 +5,7 @@
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,6 +14,12 @@
# limitations under the License.
#=============================================================================
set -e
# Disable noise from `pre-commit` when no configuration is present on the
# imported tree.
export PRE_COMMIT_ALLOW_NO_CONFIG=1
########################################################################
# Script for updating third party packages.
#
@@ -33,6 +39,10 @@
# The tag, branch or commit hash to use for upstream.
# shortlog
# Optional. Set to 'true' to get a shortlog in the commit message.
# exact_tree_match
# Optional. Set to 'false' to disable tree-object based matching for
# previous import commit (required for projects that allow modifying
# imported trees). In such cases, log-based searching is performed.
#
# Additionally, an "extract_source" function must be defined. It will be
# run within the checkout of the project on the requested tag. It should
@@ -85,7 +95,8 @@ disable_custom_gitattributes() {
pushd "${extractdir}/${name}-reduced"
# Git does not allow custom attributes in a subdirectory where we
# are about to merge the `.gitattributes` file, so disable them.
sed -i '/^\[attr\]/ {s/^/#/;}' .gitattributes
sed -i.bak -e '/^\[attr\]/ {s/^/#/;}' .gitattributes
rm .gitattributes.bak
popd
}
@@ -95,12 +106,13 @@ die () {
}
warn () {
echo >&2 "warning: $@"
echo >&2 "warning:" "$@"
}
readonly regex_date='20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
readonly basehash_regex="$name $regex_date ([0-9a-f]*)"
readonly toplevel_dir="$( git rev-parse --show-toplevel )"
toplevel_dir="$( git rev-parse --show-toplevel )"
readonly toplevel_dir
cd "$toplevel_dir"
@@ -117,17 +129,39 @@ cd "$toplevel_dir"
die "'repo' is empty"
[ -n "$tag" ] || \
die "'tag' is empty"
[ -n "$exact_tree_match" ] || \
exact_tree_match=true
# Check for an empty destination directory on disk. By checking on disk and
# not in the repo it allows a library to be freshly re-initialized in a single
# commit rather than first deleting the old copy in one commit and adding the
# new copy in a separate commit.
if [ ! -d "$(git rev-parse --show-toplevel)/$subtree" ]; then
readonly basehash=""
if [ ! -d "$( git rev-parse --show-toplevel )/$subtree" ]; then
basehash=""
elif $exact_tree_match; then
# Find the tree object for the current subtree.
current_tree="$( git rev-parse "HEAD:$subtree" )"
# Search history for a commit whose subtree matches this tree object.
basehash=""
# Limit candidate commits to those with expected import commit messages for efficiency.
for commit in $( git rev-list --author="$ownership" --grep="$basehash_regex" HEAD ); do
imported_tree="$( git rev-parse "$commit^{tree}" )"
# Verify the imported tree is what is currently imported. If so, we
# have found the desired import commit.
if [ "$imported_tree" = "$current_tree" ] && [ -n "$imported_tree" ]; then
basehash="$commit"
break
fi
done
if [ -z "$basehash" ]; then
die "No previous import commit found with matching tree object for $subtree. (exact_tree_match enabled)"
fi
else
readonly basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )"
basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )"
fi
readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p;}' | egrep '^[0-9a-f]+$' )"
readonly basehash
upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p;}' | grep -E '^[0-9a-f]+$' )"
readonly upstream_old_short
[ -n "$basehash" ] || \
warn "'basehash' is empty; performing initial import"
@@ -142,6 +176,9 @@ readonly extractdir="$workdir/extract"
trap "rm -rf '$workdir'" EXIT
# Skip LFS downloading; imports should not need LFS data.
export GIT_LFS_SKIP_SMUDGE=1
# Get upstream
git clone --recursive "$repo" "$upstreamdir"
@@ -166,20 +203,25 @@ pushd "$upstreamdir"
git checkout "$tag"
git submodule sync --recursive
git submodule update --recursive --init
readonly upstream_hash="$( git rev-parse HEAD )"
readonly upstream_hash_short="$( git rev-parse --short=8 "$upstream_hash" )"
readonly upstream_datetime="$( git rev-list "$upstream_hash" --format='%ci' -n 1 | grep -e "^$regex_date" )"
readonly upstream_date="$( echo "$upstream_datetime" | grep -o -e "$regex_date" )"
upstream_hash="$( git rev-parse HEAD )"
readonly upstream_hash
upstream_hash_short="$( git rev-parse --short=8 "$upstream_hash" )"
readonly upstream_hash_short
upstream_datetime="$( git rev-list "$upstream_hash" --format='%ci' -n 1 | grep -e "^$regex_date" )"
readonly upstream_datetime
upstream_date="$( echo "$upstream_datetime" | grep -o -e "$regex_date" )"
readonly upstream_date
if $do_shortlog && [ -n "$basehash" ]; then
readonly commit_shortlog="
commit_shortlog="
Upstream Shortlog
-----------------
$( git shortlog --no-merges --abbrev=8 --format='%h %s' "$upstream_old_short".."$upstream_hash" )"
else
readonly commit_shortlog=""
commit_shortlog=""
fi
readonly commit_shortlog
extract_source || \
die "failed to extract source"
popd
@@ -193,7 +235,7 @@ pushd "$extractdir"
mv -v "$name-reduced/"* .
rmdir "$name-reduced/"
git add -A .
git commit -n --author="$ownership" --date="$upstream_datetime" -F - <<-EOF
git commit --no-verify --no-post-rewrite --author="$ownership" --date="$upstream_datetime" -F - <<-EOF
$commit_summary
Code extracted from:
@@ -213,9 +255,9 @@ else
# will fail, so use the flag by default.
unrelated_histories_flag=""
if git --version | grep -q windows; then
unrelated_histories_flag="--allow-unrelated-histories "
unrelated_histories_flag="--allow-unrelated-histories"
elif git merge --help | grep -q -e allow-unrelated-histories; then
unrelated_histories_flag="--allow-unrelated-histories "
unrelated_histories_flag="--allow-unrelated-histories"
fi
readonly unrelated_histories_flag