#!/bin/bash -eu
#
# Copyright 2017 Google Inc. All rights reserved.
#
# 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
# This file makes it easy to confirm that a set of changes in source code don't result in any
# changes to the generated ninja files. This is to reduce the effort required to be confident
# in the correctness of refactorings
function die() {
echo "$@" >&2
exit 1
}
function usage() {
violation="$1"
die "$violation
Usage: diff_build_graphs.sh [--products=product1,product2...] <OLD_VERSIONS> <NEW_VERSIONS>
This file builds and parses the build files (Android.mk, Android.bp, etc) for each requested
product and for both sets of versions, and checks whether the ninja files (which implement
the build graph) changed between the two versions.
Example: diff_build_graphs.sh 'build/soong:work^ build/blueprint:work^' 'build/soong:work build/blueprint:work'
Options:
--products=PRODUCTS comma-separated list of products to check"
}
PRODUCTS_ARG=""
OLD_VERSIONS=""
NEW_VERSIONS=""
function parse_args() {
# parse optional arguments
while true; do
arg="${1-}"
case "$arg" in
--products=*) PRODUCTS_ARG="$arg";;
*) break;;
esac
shift
done
# parse required arguments
if [ "$#" != "2" ]; then
usage ""
fi
#argument validation
OLD_VERSIONS="$1"
NEW_VERSIONS="$2"
}
parse_args "$@"
# find some file paths
cd "$(dirname $0)"
SCRIPT_DIR="$PWD"
cd ../../..
CHECKOUT_ROOT="$PWD"
OUT_DIR="${OUT_DIR-}"
if [ -z "$OUT_DIR" ]; then
OUT_DIR=out
fi
WORK_DIR="$OUT_DIR/diff"
OUT_DIR_OLD="$WORK_DIR/out_old"
OUT_DIR_NEW="$WORK_DIR/out_new"
OUT_DIR_TEMP="$WORK_DIR/out_temp"
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 $ref in project $project"
git -C "$project" checkout "$ref"
done
}
function run_build() {
echo
echo "Starting build"
# rebuild multiproduct_kati, in case it was missing before,
# or in case it is affected by some of the changes we're testing
make blueprint_tools
# find multiproduct_kati and have it build the ninja files for each product
builder="$(echo $OUT_DIR/soong/host/*/bin/multiproduct_kati)"
BUILD_NUMBER=sample "$builder" $PRODUCTS_ARG --keep --out "$OUT_DIR_TEMP" || true
echo
}
function diffProduct() {
product="$1"
zip1="$OUT_DIR_OLD/${product}.zip"
unzipped1="$OUT_DIR_OLD/$product"
zip2="$OUT_DIR_NEW/${product}.zip"
unzipped2="$OUT_DIR_NEW/$product"
unzip -qq "$zip1" -d "$unzipped1"
unzip -qq "$zip2" -d "$unzipped2"
#do a diff of the ninja files
diffFile="$WORK_DIR/diff.txt"
diff -r "$unzipped1" "$unzipped2" -x build_date.txt -x build_number.txt -x '\.*' -x '*.log' -x build_fingerprint.txt -x build.ninja.d -x '*.zip' > $diffFile || true
if [[ -s "$diffFile" ]]; then
# outputs are different, so remove the unzipped versions but keep the zipped versions
echo "First few differences (total diff linecount=$(wc -l $diffFile)) for product $product:"
cat "$diffFile" | head -n 10
echo "End of differences for product $product"
rm -rf "$unzipped1" "$unzipped2"
else
# outputs are the same, so remove all of the outputs
rm -rf "$zip1" "$unzipped1" "$zip2" "$unzipped2"
fi
}
function do_builds() {
#reset work dir
rm -rf "$WORK_DIR"
mkdir "$WORK_DIR"
#build new code
checkout "$NEW_VERSIONS"
run_build
mv "$OUT_DIR_TEMP" "$OUT_DIR_NEW"
#build old code
#TODO do we want to cache old results? Maybe by the time we care to cache old results this will
#be running on a remote server somewhere and be completely different
checkout "$OLD_VERSIONS"
run_build
mv "$OUT_DIR_TEMP" "$OUT_DIR_OLD"
#cleanup
echo created "$OUT_DIR_OLD" and "$OUT_DIR_NEW"
}
function main() {
do_builds
checkout "$NEW_VERSIONS"
#find all products
productsFile="$WORK_DIR/all_products.txt"
find $OUT_DIR_OLD $OUT_DIR_NEW -mindepth 1 -maxdepth 1 -name "*.zip" | sed "s|^$OUT_DIR_OLD/||" | sed "s|^$OUT_DIR_NEW/||" | sed "s|\.zip$||" | sort | uniq > "$productsFile"
echo Diffing products
for product in $(cat $productsFile); do
diffProduct "$product"
done
echo Done diffing products
echo "Any differing outputs can be seen at $OUT_DIR_OLD/*.zip and $OUT_DIR_NEW/*.zip"
echo "See $WORK_DIR/diff.txt for the full list of differences for the latest product checked"
}
main