| #!/bin/bash |
| # Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| # Call this script as follows: |
| # ./build-mapper.sh /path/to/git/repo \ |
| # /path/to/output/dir \ |
| # [Number of commits before the current one to test] |
| |
| export GIT_REPOSITORY=$(realpath $1) |
| export RESULT_DIRECTORY=$(realpath $2) |
| export NUMBER_OF_CLS=${3:-50} |
| |
| FEATURE_DIR=$(realpath "$(dirname $0)/features/") |
| |
| cd $GIT_REPOSITORY |
| |
| # Store our previous state so that we can store it later. |
| previous_state=$(git rev-parse --abbrev-ref HEAD) |
| |
| for ct in $(seq 1 $(($NUMBER_OF_CLS + 1))); do |
| |
| prev=$commit; |
| commit=$(git log -1 --format='%h') |
| echo "Working on $commit" |
| if ! gclient sync -r $commit &> /dev/null; then |
| echo 'gclient failed' |
| fi |
| |
| echo '"'$commit'"' >> "$RESULT_DIRECTORY/config.feature" |
| |
| if [[ $ct != $(($NUMBER_OF_CLS + 1)) ]]; then |
| for feature in $FEATURE_DIR/source/*; do |
| feature_name=$(basename $feature) |
| [ -x $feature ] && $feature \ |
| >> "${RESULT_DIRECTORY}/${feature_name}.feature" & |
| done |
| fi |
| |
| wait |
| |
| # Make directory and set args |
| # Currently using release builds that are component builds. |
| # Release builds use /much/ less storage (making it feasible to have a |
| # large number of builds). |
| # Component builds build somewhat faster, making it nice to have enabled. |
| mkdir -p .out/Default |
| echo 'is_debug=false' > .out/Default/args.gn |
| echo 'is_component_build=true' >> .out/Default/args.gn |
| gn gen .out/Default |
| |
| # Build, extract features, and copy out |
| $(which time) -f '%e' -o $RESULT_DIRECTORY/build-time.feature -a \ |
| ninja -C .out/Default -j$(($(nproc) - 4)) |
| |
| if [[ $ct == "1" ]]; then |
| rm $RESULT_DIRECTORY/build-time.feature |
| fi |
| |
| echo "copying $commit" |
| cp -r .out "$RESULT_DIRECTORY/$commit.build" |
| |
| if [[ $ct != "1" ]]; then |
| for feature in $FEATURE_DIR/unary/*; do |
| feature_name=$(basename $feature) |
| [ -x $feature ] && $feature $RESULT_DIRECTORY/$prev.build \ |
| >> "${RESULT_DIRECTORY}/${feature_name}.feature" & |
| done |
| for feature in $FEATURE_DIR/unary/*; do |
| feature_name=$(basename $feature) |
| [ -x $feature ] || continue |
| x=$($feature $RESULT_DIRECTORY/$prev.build) |
| y=$($feature $RESULT_DIRECTORY/$commit.build) |
| echo $(($x - $y)) \ |
| >> "${RESULT_DIRECTORY}/${feature_name}-change.feature" & |
| done |
| for feature in $FEATURE_DIR/binary/*; do |
| feature_name=$(basename $feature) |
| [ -x $feature ] && $feature $RESULT_DIRECTORY/$commit.build \ |
| $RESULT_DIRECTORY/$prev.build \ |
| >> "${RESULT_DIRECTORY}/${feature_name}.feature" & |
| done |
| wait |
| fi |
| |
| # Go back a revision. |
| if ! git checkout HEAD~1; then |
| exit 1 |
| fi |
| |
| rm -rf $RESULT_DIRECTORY/$prev.build |
| done |
| |
| # Restore us back to our start state |
| mv .out "$RESULT_DIRECTORY/$commit.build" |
| git checkout $previous_state |
| |
| # Order the commits in time order. |
| for file in "$RESULT_DIRECTORY"/*.feature; do |
| echo "Reversing $file" |
| tac $file > "$RESULT_DIRECTORY/.tmp" |
| echo "Moving $file" |
| mv "$RESULT_DIRECTORY/.tmp" "$file" |
| done |
| |
| exit 0 |