Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | set -e |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 3 | |
| 4 | scriptName="$(basename $0)" |
| 5 | |
| 6 | function usage() { |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 7 | echo "NAME" |
| 8 | echo " diagnose-build-failure.sh" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 9 | echo |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 10 | echo "SYNOPSIS" |
Jeff Gaston | 1ffc485 | 2021-06-24 12:02:44 -0400 | [diff] [blame] | 11 | echo " ./development/diagnose-build-failure/diagnose-build-failure.sh [--message <message>] [--timeout <seconds> ] '<tasks>'" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 12 | echo |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 13 | echo "DESCRIPTION" |
| 14 | echo " Attempts to identify why "'`'"./gradlew <tasks>"'`'" fails" |
| 15 | echo |
| 16 | echo "OPTIONS" |
| 17 | echo "--message <message>" |
| 18 | echo " Replaces the requirement for "'`'"./gradlew <tasks>"'`'" to fail with the requirement that it produces the given message" |
| 19 | echo |
| 20 | echo "SAMPLE USAGE" |
Jeff Gaston | 6c1bd59 | 2021-04-29 12:53:47 -0400 | [diff] [blame] | 21 | echo " $0 assembleRelease # or any other arguments you would normally give to ./gradlew" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 22 | echo |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 23 | echo "OUTPUT" |
| 24 | echo " diagnose-build-failure will conclude one of the following:" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 25 | echo |
| 26 | echo " A) Some state saved in memory by the Gradle daemon is triggering an error" |
| 27 | echo " B) Your source files have been changed" |
Jeff Gaston | 61cef33 | 2020-12-22 11:23:09 -0500 | [diff] [blame] | 28 | echo " To (slowly) generate a simpler reproduction case, you can run simplify-build-failure.sh" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 29 | echo " C) Some file in the out/ dir is triggering an error" |
| 30 | echo " If this happens, $scriptName will identify which file(s) specifically" |
| 31 | echo " D) The build is nondeterministic and/or affected by timestamps" |
| 32 | echo " E) The build via gradlew actually passes" |
| 33 | exit 1 |
| 34 | } |
| 35 | |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 36 | expectedMessage="" |
Jeff Gaston | 1ffc485 | 2021-06-24 12:02:44 -0400 | [diff] [blame] | 37 | timeoutSeconds="" |
Jeff Gaston | 3fee10a | 2021-10-19 13:34:12 -0400 | [diff] [blame] | 38 | grepOptions="" |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 39 | while true; do |
| 40 | if [ "$#" -lt 1 ]; then |
| 41 | usage |
| 42 | fi |
| 43 | arg="$1" |
| 44 | shift |
| 45 | if [ "$arg" == "--message" ]; then |
| 46 | expectedMessage="$1" |
| 47 | shift |
| 48 | continue |
| 49 | fi |
Jeff Gaston | 1ffc485 | 2021-06-24 12:02:44 -0400 | [diff] [blame] | 50 | if [ "$arg" == "--timeout" ]; then |
| 51 | timeoutSeconds="$1" |
| 52 | shift |
| 53 | continue |
| 54 | fi |
| 55 | |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 56 | gradleArgs="$arg" |
| 57 | break |
| 58 | done |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 59 | if [ "$gradleArgs" == "" ]; then |
| 60 | usage |
| 61 | fi |
Jeff Gaston | 1ffc485 | 2021-06-24 12:02:44 -0400 | [diff] [blame] | 62 | if [ "$timeoutSeconds" == "" ]; then |
| 63 | timeoutArg="" |
| 64 | else |
| 65 | timeoutArg="--timeout $timeoutSeconds" |
| 66 | fi |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 67 | # split Gradle arguments into options and tasks |
| 68 | gradleOptions="" |
| 69 | gradleTasks="" |
| 70 | for arg in $gradleArgs; do |
| 71 | if [[ "$arg" == "-*" ]]; then |
| 72 | gradleOptions="$gradleOptions $arg" |
| 73 | else |
| 74 | gradleTasks="$gradleTasks $arg" |
| 75 | fi |
| 76 | done |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 77 | |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 78 | if [ "$#" -gt 0 ]; then |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 79 | echo "Unrecognized argument: $1" >&2 |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 80 | exit 1 |
| 81 | fi |
| 82 | |
Jeff Gaston | 6323450 | 2019-07-09 13:47:31 -0400 | [diff] [blame] | 83 | workingDir="$(pwd)" |
| 84 | if [ ! -e "$workingDir/gradlew" ]; then |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 85 | echo "Error; ./gradlew does not exist. Must cd to a dir containing a ./gradlew first" >&2 |
Jeff Gaston | 6323450 | 2019-07-09 13:47:31 -0400 | [diff] [blame] | 86 | # so that this script knows which gradlew to use (in frameworks/support or frameworks/support/ui) |
| 87 | exit 1 |
| 88 | fi |
| 89 | |
Jeff Gaston | 65c35b9 | 2021-05-11 12:20:45 -0400 | [diff] [blame] | 90 | # resolve some paths |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 91 | scriptPath="$(cd $(dirname $0) && pwd)" |
Jeff Gaston | 599b9e3 | 2020-08-05 18:36:56 -0400 | [diff] [blame] | 92 | vgrep="$scriptPath/impl/vgrep.sh" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 93 | supportRoot="$(cd $scriptPath/../.. && pwd)" |
| 94 | checkoutRoot="$(cd $supportRoot/../.. && pwd)" |
Jeff Gaston | a58e308 | 2019-08-05 19:44:26 -0400 | [diff] [blame] | 95 | tempDir="$checkoutRoot/diagnose-build-failure/" |
Jeff Gaston | 65c35b9 | 2021-05-11 12:20:45 -0400 | [diff] [blame] | 96 | if [ "$OUT_DIR" != "" ]; then |
| 97 | mkdir -p "$OUT_DIR" |
| 98 | OUT_DIR="$(cd $OUT_DIR && pwd)" |
Jeff Gaston | baa4ca5 | 2021-07-20 15:50:39 -0400 | [diff] [blame] | 99 | EFFECTIVE_OUT_DIR="$OUT_DIR" |
| 100 | else |
| 101 | EFFECTIVE_OUT_DIR="$checkoutRoot/out" |
Jeff Gaston | 65c35b9 | 2021-05-11 12:20:45 -0400 | [diff] [blame] | 102 | fi |
| 103 | if [ "$DIST_DIR" != "" ]; then |
| 104 | mkdir -p "$DIST_DIR" |
| 105 | DIST_DIR="$(cd $DIST_DIR && pwd)" |
Jeff Gaston | baa4ca5 | 2021-07-20 15:50:39 -0400 | [diff] [blame] | 106 | EFFECTIVE_DIST_DIR=$DIST_DIR |
| 107 | else |
| 108 | # If $DIST_DIR was unset, we leave it unset just in case setting it could affect the build |
| 109 | # However, we still need to keep track of where the files are going to go, so |
| 110 | # we set EFFECTIVE_DIST_DIR |
| 111 | EFFECTIVE_DIST_DIR="$EFFECTIVE_OUT_DIR/dist" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 112 | fi |
| 113 | COLOR_WHITE="\e[97m" |
| 114 | COLOR_GREEN="\e[32m" |
| 115 | |
Jeff Gaston | d7a34d2 | 2024-05-21 15:53:30 -0400 | [diff] [blame] | 116 | function outputAdvice() { |
| 117 | adviceName="$1" |
| 118 | cd "$scriptPath" |
| 119 | adviceFilepath="classifications/${adviceName}.md" |
| 120 | echo >&2 |
| 121 | echo "Advice ${scriptPath}/${adviceFilepath}:" >&2 |
| 122 | echo >&2 |
| 123 | cat "$adviceFilepath" >&2 |
| 124 | exit 0 |
| 125 | } |
Jeff Gaston | 52c2799 | 2024-05-01 10:50:20 -0400 | [diff] [blame] | 126 | |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 127 | function checkStatusRepo() { |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 128 | repo status >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 129 | } |
| 130 | |
| 131 | function checkStatusGit() { |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 132 | git status >&2 |
| 133 | git log -1 >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 134 | } |
| 135 | |
| 136 | function checkStatus() { |
| 137 | cd "$checkoutRoot" |
| 138 | if [ "-e" .repo ]; then |
| 139 | checkStatusRepo |
| 140 | else |
| 141 | checkStatusGit |
| 142 | fi |
| 143 | } |
| 144 | |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 145 | # echos a shell command for running the build in the current directory |
Jeff Gaston | ec553a3 | 2020-09-03 10:55:44 -0400 | [diff] [blame] | 146 | function getBuildCommand() { |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 147 | if [ "$expectedMessage" == "" ]; then |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 148 | testCommand="$* 2>&1" |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 149 | else |
Jeff Gaston | 1f8c267 | 2022-04-14 12:39:41 -0400 | [diff] [blame] | 150 | # escape single quotes (end the previous quote, add an escaped quote, and start a new quote) |
| 151 | escapedMessage="$(echo "$expectedMessage" | sed "s/'/'\\\\''/g")" |
| 152 | testCommand="$* >log 2>&1; $vgrep '$escapedMessage' log $grepOptions" |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 153 | fi |
Jeff Gaston | 599b9e3 | 2020-08-05 18:36:56 -0400 | [diff] [blame] | 154 | echo "$testCommand" |
| 155 | } |
| 156 | |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 157 | # Echos a shell command for testing the state in the current directory |
| 158 | # Status can be inverted by the '--invert' flag |
| 159 | # The dir of the state being tested is $testDir |
| 160 | # The dir of the source code is $workingDir |
| 161 | function getTestStateCommand() { |
| 162 | successStatus=0 |
| 163 | failureStatus=1 |
| 164 | if [[ "$1" == "--invert" ]]; then |
| 165 | successStatus=1 |
| 166 | failureStatus=0 |
| 167 | shift |
| 168 | fi |
| 169 | |
| 170 | setupCommand="testDir=\$(pwd) |
| 171 | $scriptPath/impl/restore-state.sh . $workingDir --move && cd $workingDir |
| 172 | " |
| 173 | buildCommand="$*" |
Jeff Gaston | 80fb4a3a | 2022-04-21 11:27:40 -0400 | [diff] [blame] | 174 | cleanupCommand="$scriptPath/impl/backup-state.sh \$testDir --move >/dev/null" |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 175 | |
| 176 | fullFiltererCommand="$setupCommand |
Jeff Gaston | 735b125 | 2021-06-24 14:26:40 -0400 | [diff] [blame] | 177 | if $buildCommand >/dev/null 2>/dev/null; then |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 178 | $cleanupCommand |
| 179 | exit $successStatus |
| 180 | else |
| 181 | $cleanupCommand |
| 182 | exit $failureStatus |
| 183 | fi" |
| 184 | |
| 185 | echo "$fullFiltererCommand" |
| 186 | } |
| 187 | |
Jeff Gaston | 599b9e3 | 2020-08-05 18:36:56 -0400 | [diff] [blame] | 188 | function runBuild() { |
| 189 | testCommand="$(getBuildCommand $*)" |
Jeff Gaston | 40660e7 | 2020-01-21 16:46:14 -0500 | [diff] [blame] | 190 | cd "$workingDir" |
Jeff Gaston | 65c35b9 | 2021-05-11 12:20:45 -0400 | [diff] [blame] | 191 | echo Running $testCommand |
| 192 | if bash -c "$testCommand"; then |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 193 | echo -e "$COLOR_WHITE" |
| 194 | echo |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 195 | echo '`'$testCommand'`' succeeded |
Jeff Gaston | 599b9e3 | 2020-08-05 18:36:56 -0400 | [diff] [blame] | 196 | return 0 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 197 | else |
| 198 | echo -e "$COLOR_WHITE" |
| 199 | echo |
Jeff Gaston | a6c66504 | 2020-07-22 12:57:33 -0400 | [diff] [blame] | 200 | echo '`'$testCommand'`' failed |
Jeff Gaston | 599b9e3 | 2020-08-05 18:36:56 -0400 | [diff] [blame] | 201 | return 1 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 202 | fi |
| 203 | } |
| 204 | |
| 205 | function backupState() { |
| 206 | cd "$scriptPath" |
| 207 | backupDir="$1" |
Jeff Gaston | 65c35b9 | 2021-05-11 12:20:45 -0400 | [diff] [blame] | 208 | shift |
Jeff Gaston | 80fb4a3a | 2022-04-21 11:27:40 -0400 | [diff] [blame] | 209 | ./impl/backup-state.sh "$backupDir" "$@" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 210 | } |
| 211 | |
| 212 | function restoreState() { |
| 213 | cd "$scriptPath" |
| 214 | backupDir="$1" |
Jeff Gaston | 80fb4a3a | 2022-04-21 11:27:40 -0400 | [diff] [blame] | 215 | ./impl/restore-state.sh "$backupDir" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 216 | } |
| 217 | |
| 218 | function clearState() { |
| 219 | restoreState /dev/null |
| 220 | } |
| 221 | |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 222 | echo >&2 |
| 223 | echo "diagnose-build-failure making sure that we can reproduce the build failure" >&2 |
Jeff Gaston | baa4ca5 | 2021-07-20 15:50:39 -0400 | [diff] [blame] | 224 | if runBuild ./gradlew -Pandroidx.summarizeStderr $gradleArgs; then |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 225 | echo >&2 |
| 226 | echo "This script failed to reproduce the build failure." >&2 |
Jeff Gaston | d7a34d2 | 2024-05-21 15:53:30 -0400 | [diff] [blame] | 227 | outputAdvice "subsequent-success" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 228 | else |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 229 | echo >&2 |
| 230 | echo "Reproduced build failure" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 231 | fi |
| 232 | |
Jeff Gaston | baa4ca5 | 2021-07-20 15:50:39 -0400 | [diff] [blame] | 233 | if [ "$expectedMessage" == "" ]; then |
| 234 | summaryLog="$EFFECTIVE_DIST_DIR/logs/error_summary.log" |
| 235 | echo |
| 236 | echo "No failure message specified. Computing appropriate failure message from $summaryLog" |
| 237 | echo |
| 238 | longestLine="$(awk '{ if (length($0) > maxLength) {maxLength = length($0); longestLine = $0} } END { print longestLine }' $summaryLog)" |
| 239 | echo "Longest line:" |
| 240 | echo |
| 241 | echo "$longestLine" |
| 242 | echo |
Jeff Gaston | 3fee10a | 2021-10-19 13:34:12 -0400 | [diff] [blame] | 243 | grepOptions="-F" # interpret grep query as a fixed string, not a regex |
| 244 | if grep $grepOptions "$longestLine" "$summaryLog" >/dev/null 2>/dev/null; then |
Jeff Gaston | baa4ca5 | 2021-07-20 15:50:39 -0400 | [diff] [blame] | 245 | echo "We will use this as the message to test for" |
| 246 | echo |
| 247 | expectedMessage="$longestLine" |
| 248 | else |
| 249 | echo "The identified line could not be found in the summary log via grep. Is it possible that diagnose-build-failure did not correctly escape the message?" |
| 250 | exit 1 |
| 251 | fi |
| 252 | fi |
| 253 | |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 254 | echo |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 255 | echo "diagnose-build-failure stopping the Gradle Daemon and rebuilding" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 256 | cd "$supportRoot" |
| 257 | ./gradlew --stop || true |
| 258 | if runBuild ./gradlew --no-daemon $gradleArgs; then |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 259 | echo >&2 |
| 260 | echo "The build passed when disabling the Gradle Daemon" >&2 |
Jeff Gaston | d7a34d2 | 2024-05-21 15:53:30 -0400 | [diff] [blame] | 261 | outputAdvice "memory-state" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 262 | else |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 263 | echo >&2 |
| 264 | echo "The build failed even with the Gradle Daemon disabled." >&2 |
| 265 | echo "This may mean that there is state stored in a file somewhere, triggering the build to fail." >&2 |
| 266 | echo "We will investigate the possibility of saved state next." >&2 |
| 267 | echo >&2 |
Jeff Gaston | a1280e0 | 2021-04-16 16:43:02 -0400 | [diff] [blame] | 268 | # We're going to immediately overwrite the user's current state, |
| 269 | # so we can simply move the current state into $tempDir/prev rather than copying it |
| 270 | backupState "$tempDir/prev" --move |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 271 | fi |
| 272 | |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 273 | echo >&2 |
| 274 | echo "Checking whether a clean build passes" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 275 | clearState |
| 276 | backupState "$tempDir/empty" |
| 277 | successState="$tempDir/empty" |
| 278 | if runBuild ./gradlew --no-daemon $gradleArgs; then |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 279 | echo >&2 |
| 280 | echo "The clean build passed, so we can now investigate what cached state is triggering this build to fail." >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 281 | backupState "$tempDir/clean" |
| 282 | else |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 283 | echo >&2 |
| 284 | echo "The clean build also reproduced the issue." >&2 |
Jeff Gaston | d7a34d2 | 2024-05-21 15:53:30 -0400 | [diff] [blame] | 285 | outputAdvice "clean-error" |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 286 | echo "Checking the status of the checkout:" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 287 | checkStatus |
| 288 | exit 1 |
| 289 | fi |
| 290 | |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 291 | echo >&2 |
| 292 | echo "Checking whether a second build passes when starting from the output of the first clean build" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 293 | if runBuild ./gradlew --no-daemon $gradleArgs; then |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 294 | echo >&2 |
| 295 | echo "The next build after the clean build passed, so we can use the output of the first clean build as the successful state to compare against" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 296 | successState="$tempDir/clean" |
| 297 | else |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 298 | echo >&2 |
| 299 | echo "The next build after the clean build failed." >&2 |
| 300 | echo "Although this is unexpected, we should still be able to diagnose it." >&2 |
| 301 | echo "This might be slower than normal, though, because it may require us to rebuild more things more often" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 302 | fi |
| 303 | |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 304 | echo >&2 |
| 305 | echo "Next we'll double-check that after restoring the failing state, the build fails" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 306 | restoreState "$tempDir/prev" |
| 307 | if runBuild ./gradlew --no-daemon $gradleArgs; then |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 308 | echo >&2 |
| 309 | echo "After restoring the saved state, the build passed." >&2 |
Jeff Gaston | d7a34d2 | 2024-05-21 15:53:30 -0400 | [diff] [blame] | 310 | outputAdvice "unknown-state" |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 311 | exit 1 |
| 312 | else |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 313 | echo >&2 |
| 314 | echo "After restoring the saved state, the build failed. This confirms that this script is successfully saving and restoring the relevant state" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 315 | fi |
| 316 | |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 317 | # Ask diff-filterer.py to run a binary search to determine the minimum set of tasks that must be passed to reproduce this error |
| 318 | # (it's possible that the caller passed more tasks than needed, particularly if the caller is a script) |
| 319 | requiredTasksDir="$tempDir/requiredTasks" |
| 320 | function determineMinimalSetOfRequiredTasks() { |
| 321 | echo Calculating the list of tasks to run |
| 322 | allTasksLog="$tempDir/tasks.log" |
| 323 | restoreState "$successState" |
| 324 | rm -f "$allTasksLog" |
| 325 | bash -c "cd $workingDir && ./gradlew --no-daemon --dry-run $gradleArgs > $allTasksLog 2>&1" || true |
| 326 | |
| 327 | # process output and split into files |
| 328 | taskListFile="$tempDir/tasks.list" |
| 329 | cat "$allTasksLog" | grep '^:' | sed 's/ .*//' > "$taskListFile" |
| 330 | requiredTasksWork="$tempDir/requiredTasksWork" |
| 331 | rm -rf "$requiredTasksWork" |
| 332 | cp -r "$tempDir/prev" "$requiredTasksWork" |
| 333 | mkdir -p "$requiredTasksWork/tasks" |
| 334 | bash -c "cd $requiredTasksWork/tasks && split -l 1 '$taskListFile'" |
Jeff Gaston | 64ab708 | 2022-03-17 13:50:52 -0400 | [diff] [blame] | 335 | # also include the original tasks in case either we failed to compute the list of tasks (due to the build failing during project configuration) or there are too many tasks to fit in one command line invocation |
| 336 | echo "$gradleTasks" > "$requiredTasksWork/tasks/givenTasks" |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 337 | |
| 338 | rm -rf "$requiredTasksDir" |
| 339 | # Build the command for passing to diff-filterer. |
| 340 | # We call xargs because the full set of tasks might be too long for the shell, and xargs will |
| 341 | # split into multiple gradlew invocations if needed. |
| 342 | # We also cd into the tasks/ dir before calling 'cat' to avoid reaching its argument length limit. |
| 343 | # note that the variable "$testDir" gets set by $getTestStateCommand |
| 344 | buildCommand="$(getBuildCommand "rm -f log && (cd \$testDir/tasks && cat *) | xargs --no-run-if-empty ./gradlew $gradleOptions")" |
| 345 | |
| 346 | # command for moving state, running build, and moving state back |
| 347 | fullFiltererCommand="$(getTestStateCommand --invert $buildCommand)" |
| 348 | |
Jeff Gaston | 1ffc485 | 2021-06-24 12:02:44 -0400 | [diff] [blame] | 349 | if $supportRoot/development/file-utils/diff-filterer.py $timeoutArg --work-path "$tempDir" "$requiredTasksWork" "$tempDir/prev" "$fullFiltererCommand"; then |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 350 | echo diff-filterer successfully identified a minimal set of required tasks. Saving into $requiredTasksDir >&2 |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 351 | cp -r "$tempDir/bestResults/tasks" "$requiredTasksDir" |
| 352 | else |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 353 | echo diff-filterer was unable to identify a minimal set of tasks required to reproduce the error >&2 |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 354 | exit 1 |
| 355 | fi |
| 356 | } |
| 357 | determineMinimalSetOfRequiredTasks |
| 358 | # update variables |
| 359 | gradleTasks="$(cat $requiredTasksDir/*)" |
| 360 | gradleArgs="$gradleOptions $gradleTasks" |
| 361 | |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 362 | # Now ask diff-filterer.py to run a binary search to determine what the relevant differences are between "$tempDir/prev" and "$tempDir/clean" |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 363 | echo >&2 |
| 364 | echo "Binary-searching the contents of the two output directories until the relevant differences are identified." >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 365 | echo "This may take a while." |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 366 | echo >&2 |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 367 | |
| 368 | # command for running a build |
Jeff Gaston | 5725bdc | 2021-05-13 17:53:20 -0400 | [diff] [blame] | 369 | buildCommand="$(getBuildCommand "./gradlew --no-daemon $gradleArgs")" |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 370 | # command for moving state, running build, and moving state back |
Jeff Gaston | 0616043 | 2023-07-06 16:04:52 -0400 | [diff] [blame] | 371 | fullFiltererCommand="$(getTestStateCommand --invert $buildCommand)" |
Jeff Gaston | f1817f7 | 2021-06-07 15:28:42 -0400 | [diff] [blame] | 372 | |
Jeff Gaston | 0616043 | 2023-07-06 16:04:52 -0400 | [diff] [blame] | 373 | if $supportRoot/development/file-utils/diff-filterer.py $timeoutArg --assume-input-states-are-correct --work-path $tempDir $tempDir/prev $successState "$fullFiltererCommand"; then |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 374 | echo >&2 |
| 375 | echo "There should be something wrong with the above file state" >&2 |
| 376 | echo "Hopefully the output from diff-filterer.py above is enough information for you to figure out what is wrong" >&2 |
| 377 | echo "If not, you could ask a team member about your original error message and see if they have any ideas" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 378 | else |
Jeff Gaston | 2a60972 | 2021-10-19 13:05:17 -0400 | [diff] [blame] | 379 | echo >&2 |
| 380 | echo "Something went wrong running diff-filterer.py" >&2 |
| 381 | echo "Maybe that means the build is nondeterministic" >&2 |
| 382 | echo "Maybe that means that there's something wrong with this script ($0)" >&2 |
Jeff Gaston | cc0993d | 2019-04-02 18:02:44 -0400 | [diff] [blame] | 383 | fi |