blob: f9fe9c661e35557b6c182602a82f70de7edf2dc2 [file] [log] [blame]
#!/bin/bash
#
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# 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
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
set -e
supportRoot="$(cd $(dirname $0)/.. && pwd)"
checkoutRoot="$(cd ${supportRoot}/../.. && pwd)"
function die() {
echo "$@" >&2
exit 1
}
function usage() {
violation="$1"
die "
Usage: $0 <git treeish>
$0 <path>:<git treeish> <path>:<git treeish>
Validates that libraries built from the given versions are the same as
the build outputs built at HEAD. This can be used to validate that a refactor
did not change the outputs.
If a git treeish is given with no path, the path is considered to be frameworks/support
Example: $0 HEAD^
Example: $0 prebuilts/androidx/external:HEAD^ frameworks/support:work^
* A git treeish is what you type when you run 'git checkout <git treeish>'
See also https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddeftree-ishatree-ishalsotreeish .
You can also supply additional arguments that will be passed through to validateRefactorHelper.py, using -P
For example, the baseline arguments that validateRefactorHelper.py accepts.
Example: $0 HEAD^ -p agpKmp
validateRefactor also accepts git treeishes as named arguments using -g
Example: $0 -g HEAD^ -p agpKmp
"
return 1
}
# Fills in a default repository path of "frameworks/support:" for any args that don't specify
# their repository. Given an input of: "work^ prebuilts/androidx/external:HEAD^", should return
# "frameworks/support:work^ prebuilts/androidx/external:HEAD^".
function expandCommitArgs() {
inputSpecs="$@"
outputSpecs=""
for spec in $inputSpecs; do
if echo "$spec" | grep -v ":" >/dev/null; then
spec="frameworks/support:$spec"
fi
outputSpecs="$outputSpecs $spec"
done
echo $outputSpecs
}
# Given a list of paths like "frameworks/support prebuilts/androidx/external",
# runs `git checkout -` in each
function uncheckout() {
repositoryPaths="$@"
for repositoryPath in $repositoryPaths; do
echoAndDo git -C "$checkoutRoot/$repositoryPath" checkout -
done
}
# Given a list of version specs like "a/b:c d/e:f", returns just the paths: "a/b d/e"
function getParticipatingProjectPaths() {
specs="$@"
result=""
for arg in $specs; do
echo parsing $arg >&2
repositoryPath="$(echo $arg | sed 's|\([^:]*\):\([^:]*\)|\1|')"
otherVersion="$(echo $arg | sed 's|\([^:]*\):\([^:]*\)|\2|')"
if [ "$otherVersion" != "HEAD" ]; then
result="$result $repositoryPath"
fi
done
echo $result
}
# Given a list of paths, returns a string containing the currently checked-out version of each
function getCurrentCommits() {
repositoryPaths="$@"
result=""
for repositoryPath in $repositoryPaths; do
currentVersion="$(cd $checkoutRoot/$repositoryPath && git log -1 --format=%H)"
result="$result $repositoryPath:$currentVersion"
done
echo $result
}
function echoAndDo() {
echo "$*"
eval "$*"
}
# Given a list of version specs like "a/b:c d/e:f", checks out the appropriate version in each
# In this example it would be `cd a/b && git checkout e` and `cd e/e && git checkout f`
function checkout() {
versionSpecs="$1"
for versionSpec in $versionSpecs; do
project="$(echo $versionSpec | sed 's|\([^:]*\):\([^:]*\)|\1|')"
ref="$(echo $versionSpec | sed 's|\([^:]*\):\([^:]*\)|\2|')"
echo "checking out $ref in project $project"
echoAndDo git -C "$checkoutRoot/$project" checkout "$ref"
done
}
function unzipInPlace() {
archiveName="$1"
echoAndDo unzip -q "$archiveName" -d "${archiveName}.unzipped"
}
function doBuild() {
# build androidx
echoAndDo ./gradlew createAllArchives zipDocs --no-daemon --rerun-tasks --offline -Pandroidx.highMemory -Pandroidx.constraints=true
archiveName="top-of-tree-m2repository-all-0.zip"
unzipInPlace "${tempOutPath}/dist/top-of-tree-m2repository-all-0.zip"
unzipInPlace "${tempOutPath}/dist/docs-tip-of-tree-0.zip"
unzipInPlace "${tempOutPath}/dist/docs-public-0.zip"
}
nonNamedArgs=()
oldCommits=()
passThruArgs=()
while [ $OPTIND -le "$#" ]; do
if getopts ":p:g:" opt; then
case $opt in
\? ) usage;;
g ) oldCommits+="$(expandCommitArgs $OPTARG)";;
p ) passThruArgs+="$OPTARG";;
esac
case $OPTARG in
-*) usage;;
esac
else
nonNamedArgs+=("${!OPTIND}")
((OPTIND++))
fi
done
oldCommits+="$(expandCommitArgs $nonNamedArgs)"
projectPaths="$(getParticipatingProjectPaths $oldCommits)"
if [ "$oldCommits" == "" ]; then
usage
fi
newCommits="$(getCurrentCommits $projectPaths)"
cd "$supportRoot"
if [[ $(git update-index --refresh) ]]; then echo "You have local changes; stash or commit them or this script won't work"; exit 1; fi
if [[ $(git diff-index --quiet HEAD) ]]; then echo "You have local changes; stash or commit them or this script won't work"; exit 1; fi
echo old commits: $oldCommits
echo new commits: $newCommits
cd "$supportRoot"
oldOutPath="${checkoutRoot}/out-old"
newOutPath="${checkoutRoot}/out-new"
tempOutPath="${checkoutRoot}/out"
rm -rf "$oldOutPath" "$newOutPath" "$tempOutPath"
echo building new commit
doBuild
mv "$tempOutPath" "$newOutPath"
echo building previous commit
checkout "$oldCommits"
if doBuild; then
echo previous build succeeded
else
echo previous build failed
uncheckout "$projectPaths"
exit 1
fi
uncheckout "$projectPaths"
mv "$tempOutPath" "$oldOutPath"
echo
echo diffing results
# This script performs the diff, and filters out known issues and non-issues with baselines
python3 development/validateRefactorHelper.py "$passThruArgs"
echo end of difference