| #!/usr/bin/env bash |
| # |
| # This script updates the copy of ANGLE in Source/ThirdParty/ANGLE |
| # with the latest changes from upstream. |
| # |
| |
| set -e |
| cd "$(dirname "$0")/../../Source/ThirdParty/ANGLE" |
| ANGLE_DIR="$PWD" |
| ANGLE_TARGET_COMMIT="origin/main" |
| WEBKIT_TARGET_COMMIT=$(git rev-parse HEAD) |
| WEBKIT_TARGET_COMMIT_SHORT=$(git rev-parse --abbrev-ref HEAD) |
| q="-q" |
| |
| # Check for modified files in WebKit ignoring untracked file except in ANGLE dir |
| check_uncommitted_changes() { |
| modified_files=$(git status --porcelain | grep -e "^[^?]" -e "^?? Source/ThirdParty/ANGLE") || true |
| if [ -n "$modified_files" ]; then |
| echo "WebKit has uncommitted or untracked changes. Commit, stash, or remove them:" |
| echo "$modified_files" |
| exit 1 |
| fi |
| } |
| |
| generate_changes_diff() { |
| # Exclude WebKit-added build files from the diff. |
| git diff "$1" --ignore-submodules=all --full-index --cached -b --ignore-cr-at-eol -- . \ |
| ':(exclude)ANGLE.plist' \ |
| ':(exclude)ANGLE.xcodeproj' \ |
| ':(exclude)Configurations' \ |
| ':(exclude)**CMakeLists.txt' \ |
| ':(exclude)*.cmake' \ |
| ':(exclude)adjust-angle-include-paths*' \ |
| ':(exclude)changes.diff' \ |
| ':(exclude)gni-to-cmake.py' \ |
| ':(exclude)Makefile' \ |
| ':(exclude)third_party/zlib/google/compression_utils_portable*' \ |
| ':(exclude)third_party/kotlin_stdlib*' \ |
| ':(exclude)**.DS_Store' \ |
| ':(exclude)WebKit' \ |
| ':(exclude)WebKitBuild' \ |
| ':(exclude)third_party/r8/custom_d8.jar' \ |
| ':(exclude)third_party/googletest' \ |
| ':(exclude)parsetab.py' \ |
| > changes.diff |
| } |
| |
| generate_changes() { |
| PREVIOUS_ANGLE_COMMIT_HASH=$(grep -m 1 -o -E "[a-z0-9]{40}" ANGLE.plist) |
| rm -rf .git |
| git init ${q} |
| git remote add origin https://chromium.googlesource.com/angle/angle |
| git fetch ${q} --depth 1 origin "$PREVIOUS_ANGLE_COMMIT_HASH" |
| git add -A |
| generate_changes_diff "$PREVIOUS_ANGLE_COMMIT_HASH" |
| rm -rf .git |
| } |
| |
| generate_sources() { |
| source_list_file="$(mktemp /tmp/ANGLEShaderProgramVersionSourceList.txt.XXXX)" |
| find src -type f -iname '*.h' -o -iname '*.cpp' -o -iname '*.c' -o -iname '*.cc' -o -iname '*.mm' -o -iname '*.inc' > ${source_list_file} |
| ./src/program_serialize_data_version.py WebKit/ANGLEShaderProgramVersion.h ${source_list_file} |
| rm ${source_list_file} |
| } |
| |
| usage() { |
| SCRIPT_NAME=$(basename "$0") |
| echo "USAGE: $SCRIPT_NAME [-h|--help] [--generate-changes | --generate-sources | <commit>]" |
| echo " -h or --help Print this help message." |
| echo " -v or --verbose Print more output." |
| echo " --generate-changes Generate ANGLE changes.diff, difference to last merged upstream revision." |
| echo " --generate-sources Generate ANGLE generated sources." |
| echo " <commit> The ANGLE commit to update to. Defaults to origin/main" |
| } |
| |
| while [[ $# -gt 0 ]]; do |
| opt="$1"; |
| shift; |
| case "$opt" in |
| -h|--help) |
| usage |
| exit 0 |
| ;; |
| -v|--verbose) |
| echo "WEBKIT_TARGET_COMMIT: $WEBKIT_TARGET_COMMIT ($WEBKIT_TARGET_COMMIT_SHORT)" |
| q="" |
| ;; |
| --generate-changes) |
| generate_changes |
| exit 0 |
| ;; |
| --generate-sources) |
| generate_sources |
| exit 0 |
| ;; |
| --*) |
| echo "ERROR: Unrecognized argument: $opt" |
| usage |
| exit 1 |
| ;; |
| *) |
| ANGLE_TARGET_COMMIT="$opt" |
| ;; |
| esac |
| done |
| |
| check_uncommitted_changes |
| |
| if ! which git-filter-repo > /dev/null; then |
| echo "Please install git-filter-repo from https://github.com/newren/git-filter-repo" |
| exit 1 |
| fi |
| |
| in_rebase() { |
| test -d .git && { test -d "$(git rev-parse --git-path rebase-merge)" || test -d "$(git rev-parse --git-path rebase-apply)"; } ; |
| } |
| |
| wait_for_rebase_to_complete() { |
| if ! in_rebase; then |
| return 1 |
| fi |
| echo |
| echo "For patches that have been upstreamed, you should choose the 'ours' version," |
| echo "and the resulting commits after rebase should be mostly empty. For patches" |
| echo "that haven't been upstreamed, resolve conflicts prioritizing 'theirs' when" |
| echo "possible to preserve WebKit's changes." |
| echo |
| echo "The script will pause now. Please complete the rebase, then come back and" |
| echo "press Enter to continue:" |
| read -r |
| while in_rebase && ! GIT_EDITOR=true git rebase --continue; do |
| echo |
| echo "Rebase still in progress. Complete the rebase and press Enter to continue:" |
| read -r |
| done |
| } |
| |
| cleanup_after_successful_rebase_and_exit() { |
| cd "$ANGLE_DIR" |
| echo |
| generate_changes_diff "$ANGLE_TARGET_COMMIT" |
| git --no-pager diff -b --cached "$LAST_ROLL_COMMIT_HASH" -- Compiler.cmake GLESv2.cmake |
| echo |
| echo "Rebase complete!" |
| echo "Above are the changes to Compiler.cmake and GLESv2.cmake." |
| echo "Now you'll need to apply the equivalent changes to the ANGLE XCode" |
| echo "project and make sure it builds. Please examine changes.diff and" |
| echo "undo any unintentional changes or unnecessary added files." |
| echo "You can examine the rebased history in the temporary git repository in" |
| echo "Source/ThirdParty/ANGLE to see where changes came from." |
| echo |
| echo "This script will pause now. Press Enter to continue when you're" |
| echo "done. The script will generate changes.diff and delete the" |
| echo "temporary git repository in Source/ThirdParty/ANGLE." |
| echo |
| echo "Press Enter to continue after fixing build:" |
| generate_sources |
| read -r |
| generate_sources |
| generate_changes_diff "$ANGLE_TARGET_COMMIT" |
| echo "Generating contents of commit message into commit-message.txt." |
| echo "Be sure to copy out this file's contents and delete it before committing." |
| echo "Update ANGLE to $(git log -1 ${COMMIT_HASH} --format=%cs) (${COMMIT_HASH})" > commit-message.txt |
| echo "Need the bug URL (OOPS!)." >> commit-message.txt |
| echo "Include a Radar link (OOPS!)." >> commit-message.txt |
| echo "" >> commit-message.txt |
| echo "Reviewed by NOBODY (OOPS!)" >> commit-message.txt |
| echo "" >> commit-message.txt |
| echo "Contains upstream commits:" >> commit-message.txt |
| echo git log --oneline "$PREVIOUS_ANGLE_COMMIT_HASH".."$COMMIT_HASH" --pretty="%h %s" >> commit-message.txt |
| git log --oneline "$PREVIOUS_ANGLE_COMMIT_HASH".."$COMMIT_HASH" --pretty="%h %s" >> commit-message.txt |
| echo "Removing temporary git repository from Source/ThirdParty/ANGLE" |
| rm -rf .git |
| git add -A . |
| # Undo the addition of commit-message.txt to make it easier for the user to remove. |
| git restore --staged commit-message.txt |
| echo |
| echo "ANGLE update is now staged. Ready to commit and upload patch." |
| exit 0 |
| } |
| |
| if wait_for_rebase_to_complete ; then |
| cleanup_after_successful_rebase_and_exit |
| fi |
| |
| cd ../../.. |
| echo "Creating WebKit branch that only contains ANGLE changes, using git-filter-repo." |
| echo "This may take a few minutes, but massively speeds up rebasing later." |
| git branch -f just-angle ${WEBKIT_TARGET_COMMIT} && git-filter-repo --refs refs/heads/just-angle --path Source/ThirdParty/ANGLE --path-rename Source/ThirdParty/ANGLE/: --force |
| cd "$ANGLE_DIR" |
| |
| echo "Downloading latest ANGLE via git clone." |
| # Remove all files including hidden ones, but not . or .. |
| rm -rf ..?* .[!.]* ./* |
| git clone https://chromium.googlesource.com/angle/angle . |
| echo "Successfully downloaded latest ANGLE." |
| git checkout -q "$ANGLE_TARGET_COMMIT" |
| echo "Commit hash: " |
| COMMIT_HASH=$(git rev-parse HEAD) |
| echo "$COMMIT_HASH" |
| echo "" |
| |
| echo "Generating angle_commit.h" |
| angle_commit_file="$(mktemp /tmp/angle_commit.h.TEMP.XXXX)" |
| ./src/commit_id.py gen "${angle_commit_file}" |
| |
| echo "Applying WebKit's local ANGLE changes to the old ANGLE version." |
| echo "Fetching WebKit changes into ANGLE repo." |
| git remote add webkit ../../.. -t just-angle |
| git fetch webkit |
| git checkout just-angle |
| |
| PREVIOUS_ANGLE_COMMIT_HASH=$(grep -m 1 -o -E "[a-z0-9]{40}" ANGLE.plist) |
| LAST_ROLL_COMMIT_HASH=$(git log --format="%H" -1 ANGLE.plist) |
| |
| echo "Updating ANGLE.plist commit hashes." |
| sed -i.bak -e "s/\([^a-z0-9]\)[a-z0-9]\{40\}\([^a-z0-9]\)/\1$COMMIT_HASH\2/g" ANGLE.plist |
| echo "Updating ANGLE.plist date." |
| sed -i.bak -e "s/<string>[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]<\/string>/<string>$(date +%Y-%m-%d)<\/string>/g" ANGLE.plist |
| rm ANGLE.plist.bak |
| |
| echo "Translating gni build files to cmake." |
| git checkout "$ANGLE_TARGET_COMMIT" -- src/compiler.gni src/libGLESv2.gni src/libANGLE/renderer/d3d/BUILD.gn |
| ./gni-to-cmake.py src/compiler.gni Compiler.cmake |
| ./gni-to-cmake.py src/libGLESv2.gni GLESv2.cmake |
| ./gni-to-cmake.py src/libANGLE/renderer/d3d/BUILD.gn D3D.cmake --prepend 'src/libANGLE/renderer/d3d/' |
| ./gni-to-cmake.py src/libANGLE/renderer/gl/BUILD.gn GL.cmake --prepend 'src/libANGLE/renderer/gl/' |
| ./gni-to-cmake.py src/libANGLE/renderer/metal/BUILD.gn Metal.cmake --prepend 'src/libANGLE/renderer/metal/' |
| git checkout src/compiler.gni src/libGLESv2.gni |
| |
| echo "Moving angle_commit.h into place" |
| mv "${angle_commit_file}" WebKit/angle_commit.h |
| |
| git add -A . |
| git commit -m "Updated ANGLE.plist, angle_commit.h and cmake files." |
| |
| # Graft the WebKit commit history on top of the ANGLE commit history at |
| # the point of the last ANGLE roll. This will allow us to rebase just |
| # the WebKit changes since the last roll on top of ANGLE main. |
| git replace --graft "$LAST_ROLL_COMMIT_HASH" "$PREVIOUS_ANGLE_COMMIT_HASH" |
| # Rebase the WebKit commit history on top of ANGLE main. |
| git checkout -b rebased-webkit-changes |
| |
| echo "Rebasing WebKit's local changes on latest ANGLE main." |
| if ! git rebase "$ANGLE_TARGET_COMMIT"; then |
| echo |
| echo "There is now a temporary git repo in Source/ThirdParty/ANGLE with a" |
| echo "rebase in progress. You must resolve the merge conflict and continue" |
| echo "the rebase. Make sure to do this in the temporary" |
| echo "Source/ThirdParty/ANGLE repo, not the main WebKit repo." |
| wait_for_rebase_to_complete |
| fi |
| cleanup_after_successful_rebase_and_exit |