diff --git a/Utilities/Scripts/update-third-party.bash b/Utilities/Scripts/update-third-party.bash index 98fc5a51ba..9f744b9c8b 100644 --- a/Utilities/Scripts/update-third-party.bash +++ b/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