Home | History | Annotate | Download | only in scripts
      1 #!/bin/bash -eu
      2 #
      3 # Copyright 2017 Google Inc. All rights reserved.
      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 
     17 set -e
     18 
     19 # This file makes it easy to confirm that a set of changes in source code don't result in any
     20 # changes to the generated ninja files. This is to reduce the effort required to be confident
     21 # in the correctness of refactorings
     22 
     23 function die() {
     24   echo "$@" >&2
     25   exit 1
     26 }
     27 
     28 function usage() {
     29   violation="$1"
     30   die "$violation
     31 
     32   Usage: diff_build_graphs.sh [--products=product1,product2...] <OLD_VERSIONS> <NEW_VERSIONS>
     33 
     34   This file builds and parses the build files (Android.mk, Android.bp, etc) for each requested
     35   product and for both sets of versions, and checks whether the ninja files (which implement
     36   the build graph) changed between the two versions.
     37 
     38   Example: diff_build_graphs.sh 'build/soong:work^ build/blueprint:work^' 'build/soong:work build/blueprint:work'
     39 
     40   Options:
     41     --products=PRODUCTS  comma-separated list of products to check"
     42 }
     43 
     44 PRODUCTS_ARG=""
     45 OLD_VERSIONS=""
     46 NEW_VERSIONS=""
     47 function parse_args() {
     48   # parse optional arguments
     49   while true; do
     50     arg="${1-}"
     51     case "$arg" in
     52       --products=*) PRODUCTS_ARG="$arg";;
     53       *) break;;
     54     esac
     55     shift
     56   done
     57   # parse required arguments
     58   if [ "$#" != "2" ]; then
     59     usage ""
     60   fi
     61   #argument validation
     62   OLD_VERSIONS="$1"
     63   NEW_VERSIONS="$2"
     64 
     65 }
     66 parse_args "$@"
     67 
     68 
     69 # find some file paths
     70 cd "$(dirname $0)"
     71 SCRIPT_DIR="$PWD"
     72 cd ../../..
     73 CHECKOUT_ROOT="$PWD"
     74 OUT_DIR="${OUT_DIR-}"
     75 if [ -z "$OUT_DIR" ]; then
     76   OUT_DIR=out
     77 fi
     78 WORK_DIR="$OUT_DIR/diff"
     79 OUT_DIR_OLD="$WORK_DIR/out_old"
     80 OUT_DIR_NEW="$WORK_DIR/out_new"
     81 OUT_DIR_TEMP="$WORK_DIR/out_temp"
     82 
     83 
     84 function checkout() {
     85   versionSpecs="$1"
     86   for versionSpec in $versionSpecs; do
     87     project="$(echo $versionSpec | sed 's|\([^:]*\):\([^:]*\)|\1|')"
     88     ref="$(echo     $versionSpec | sed 's|\([^:]*\):\([^:]*\)|\2|')"
     89     echo "checking out ref $ref in project $project"
     90     git -C "$project" checkout "$ref"
     91   done
     92 }
     93 
     94 function run_build() {
     95   echo
     96   echo "Starting build"
     97   # rebuild multiproduct_kati, in case it was missing before,
     98   # or in case it is affected by some of the changes we're testing
     99   make blueprint_tools
    100   # find multiproduct_kati and have it build the ninja files for each product
    101   builder="$(echo $OUT_DIR/soong/host/*/bin/multiproduct_kati)"
    102   BUILD_NUMBER=sample "$builder" $PRODUCTS_ARG --keep --out "$OUT_DIR_TEMP" || true
    103   echo
    104 }
    105 
    106 function diffProduct() {
    107   product="$1"
    108 
    109   zip1="$OUT_DIR_OLD/${product}.zip"
    110   unzipped1="$OUT_DIR_OLD/$product"
    111 
    112   zip2="$OUT_DIR_NEW/${product}.zip"
    113   unzipped2="$OUT_DIR_NEW/$product"
    114 
    115   unzip -qq "$zip1" -d "$unzipped1"
    116   unzip -qq "$zip2" -d "$unzipped2"
    117 
    118   #do a diff of the ninja files
    119   diffFile="$WORK_DIR/diff.txt"
    120   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
    121   if [[ -s "$diffFile" ]]; then
    122     # outputs are different, so remove the unzipped versions but keep the zipped versions
    123     echo "First few differences (total diff linecount=$(wc -l $diffFile)) for product $product:"
    124     cat "$diffFile" | head -n 10
    125     echo "End of differences for product $product"
    126     rm -rf "$unzipped1" "$unzipped2"
    127   else
    128     # outputs are the same, so remove all of the outputs
    129     rm -rf "$zip1" "$unzipped1" "$zip2" "$unzipped2"
    130   fi
    131 }
    132 
    133 function do_builds() {
    134   #reset work dir
    135   rm -rf "$WORK_DIR"
    136   mkdir "$WORK_DIR"
    137 
    138   #build new code
    139   checkout "$NEW_VERSIONS"
    140   run_build
    141   mv "$OUT_DIR_TEMP" "$OUT_DIR_NEW"
    142 
    143   #build old code
    144   #TODO do we want to cache old results? Maybe by the time we care to cache old results this will
    145   #be running on a remote server somewhere and be completely different
    146   checkout "$OLD_VERSIONS"
    147   run_build
    148   mv "$OUT_DIR_TEMP" "$OUT_DIR_OLD"
    149 
    150   #cleanup
    151   echo created "$OUT_DIR_OLD" and "$OUT_DIR_NEW"
    152 }
    153 
    154 function main() {
    155   do_builds
    156   checkout "$NEW_VERSIONS"
    157 
    158   #find all products
    159   productsFile="$WORK_DIR/all_products.txt"
    160   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"
    161   echo Diffing products
    162   for product in $(cat $productsFile); do
    163     diffProduct "$product"
    164   done
    165   echo Done diffing products
    166   echo "Any differing outputs can be seen at $OUT_DIR_OLD/*.zip and $OUT_DIR_NEW/*.zip"
    167   echo "See $WORK_DIR/diff.txt for the full list of differences for the latest product checked"
    168 }
    169 
    170 main
    171