Browse Source

update-common.sh: synchronize with upstream

Of note is the support for finding imports with matching trees, not just
commits.
Ben Boeckel 3 weeks ago
parent
commit
1b03059674
1 changed files with 59 additions and 17 deletions
  1. 59 17
      Utilities/Scripts/update-third-party.bash

+ 59 - 17
Utilities/Scripts/update-third-party.bash

@@ -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