1#!/bin/bash 2# 3# Copyright (C) 2019 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17set -e 18 19supportRoot="$(cd $(dirname $0)/.. && pwd)" 20checkoutRoot="$(cd ${supportRoot}/../.. && pwd)" 21 22function die() { 23 echo "$@" >&2 24 exit 1 25} 26 27function usage() { 28 violation="$1" 29 die " 30 Usage: $0 <git treeish> 31 $0 <path>:<git treeish> <path>:<git treeish> 32 33 Validates that libraries built from the given versions are the same as 34 the build outputs built at HEAD. This can be used to validate that a refactor 35 did not change the outputs. 36 If a git treeish is given with no path, the path is considered to be frameworks/support 37 38 Example: $0 HEAD^ 39 Example: $0 prebuilts/androidx/external:HEAD^ frameworks/support:work^ 40 41 * A git treeish is what you type when you run 'git checkout <git treeish>' 42 See also https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddeftree-ishatree-ishalsotreeish . 43 44 You can also supply additional arguments that will be passed through to validateRefactorHelper.py, using -P 45 For example, the baseline arguments that validateRefactorHelper.py accepts. 46 Example: $0 HEAD^ -p agpKmp 47 48 validateRefactor also accepts git treeishes as named arguments using -g 49 Example: $0 -g HEAD^ -p agpKmp 50 " 51 return 1 52} 53 54# Fills in a default repository path of "frameworks/support:" for any args that don't specify 55# their repository. Given an input of: "work^ prebuilts/androidx/external:HEAD^", should return 56# "frameworks/support:work^ prebuilts/androidx/external:HEAD^". 57function expandCommitArgs() { 58 inputSpecs="$@" 59 outputSpecs="" 60 for spec in $inputSpecs; do 61 if echo "$spec" | grep -v ":" >/dev/null; then 62 spec="frameworks/support:$spec" 63 fi 64 outputSpecs="$outputSpecs $spec" 65 done 66 echo $outputSpecs 67} 68 69# Given a list of paths like "frameworks/support prebuilts/androidx/external", 70# runs `git checkout -` in each 71function uncheckout() { 72 repositoryPaths="$@" 73 for repositoryPath in $repositoryPaths; do 74 echoAndDo git -C "$checkoutRoot/$repositoryPath" checkout - 75 done 76} 77# Given a list of version specs like "a/b:c d/e:f", returns just the paths: "a/b d/e" 78function getParticipatingProjectPaths() { 79 specs="$@" 80 result="" 81 for arg in $specs; do 82 echo parsing $arg >&2 83 repositoryPath="$(echo $arg | sed 's|\([^:]*\):\([^:]*\)|\1|')" 84 otherVersion="$(echo $arg | sed 's|\([^:]*\):\([^:]*\)|\2|')" 85 if [ "$otherVersion" != "HEAD" ]; then 86 result="$result $repositoryPath" 87 fi 88 done 89 echo $result 90} 91# Given a list of paths, returns a string containing the currently checked-out version of each 92function getCurrentCommits() { 93 repositoryPaths="$@" 94 result="" 95 for repositoryPath in $repositoryPaths; do 96 currentVersion="$(cd $checkoutRoot/$repositoryPath && git log -1 --format=%H)" 97 result="$result $repositoryPath:$currentVersion" 98 done 99 echo $result 100} 101function echoAndDo() { 102 echo "$*" 103 eval "$*" 104} 105# Given a list of version specs like "a/b:c d/e:f", checks out the appropriate version in each 106# In this example it would be `cd a/b && git checkout e` and `cd e/e && git checkout f` 107function checkout() { 108 versionSpecs="$1" 109 for versionSpec in $versionSpecs; do 110 project="$(echo $versionSpec | sed 's|\([^:]*\):\([^:]*\)|\1|')" 111 ref="$(echo $versionSpec | sed 's|\([^:]*\):\([^:]*\)|\2|')" 112 echo "checking out $ref in project $project" 113 echoAndDo git -C "$checkoutRoot/$project" checkout "$ref" 114 done 115} 116function unzipInPlace() { 117 archiveName="$1" 118 echoAndDo unzip -q "$archiveName" -d "${archiveName}.unzipped" 119} 120function doBuild() { 121 # build androidx 122 echoAndDo ./gradlew createAllArchives zipDocs --no-daemon --rerun-tasks --offline -Pandroidx.highMemory -Pandroidx.constraints=true 123 archiveName="top-of-tree-m2repository-all-0.zip" 124 unzipInPlace "${tempOutPath}/dist/top-of-tree-m2repository-all-0.zip" 125 unzipInPlace "${tempOutPath}/dist/docs-tip-of-tree-0.zip" 126 unzipInPlace "${tempOutPath}/dist/docs-public-0.zip" 127} 128 129nonNamedArgs=() 130oldCommits=() 131passThruArgs=() 132while [ $OPTIND -le "$#" ]; do 133 if getopts ":p:g:" opt; then 134 case $opt in 135 \? ) usage;; 136 g ) oldCommits+="$(expandCommitArgs $OPTARG)";; 137 p ) passThruArgs+="$OPTARG";; 138 esac 139 case $OPTARG in 140 -*) usage;; 141 esac 142 else 143 nonNamedArgs+=("${!OPTIND}") 144 ((OPTIND++)) 145 fi 146done 147 148oldCommits+="$(expandCommitArgs $nonNamedArgs)" 149 150projectPaths="$(getParticipatingProjectPaths $oldCommits)" 151if [ "$oldCommits" == "" ]; then 152 usage 153fi 154 155newCommits="$(getCurrentCommits $projectPaths)" 156cd "$supportRoot" 157if [[ $(git update-index --refresh) ]]; then echo "You have local changes; stash or commit them or this script won't work"; exit 1; fi 158if [[ $(git diff-index --quiet HEAD) ]]; then echo "You have local changes; stash or commit them or this script won't work"; exit 1; fi 159echo old commits: $oldCommits 160echo new commits: $newCommits 161cd "$supportRoot" 162oldOutPath="${checkoutRoot}/out-old" 163newOutPath="${checkoutRoot}/out-new" 164tempOutPath="${checkoutRoot}/out" 165 166rm -rf "$oldOutPath" "$newOutPath" "$tempOutPath" 167 168echo building new commit 169doBuild 170mv "$tempOutPath" "$newOutPath" 171 172echo building previous commit 173 174checkout "$oldCommits" 175if doBuild; then 176 echo previous build succeeded 177else 178 echo previous build failed 179 uncheckout "$projectPaths" 180 exit 1 181fi 182uncheckout "$projectPaths" 183mv "$tempOutPath" "$oldOutPath" 184 185 186echo 187echo diffing results 188# This script performs the diff, and filters out known issues and non-issues with baselines 189python3 development/validateRefactorHelper.py "$passThruArgs" 190echo end of difference 191