Add all the files and scripts for using the binary search tool to
do binary search triage on ChromeOS packages.

BUG=None
TEST=Tested the scripts on a lumpy build.

Change-ID: I131b4f24d53a32ccec70fe320119ffccb09e73ca
Reviewed-on: https://chrome-internal-review.googlesource.com/194849
Reviewed-by: Luis Lozano <llozano@chromium.org>
Commit-Queue: Caroline Tice <cmtice@google.com>
Tested-by: Caroline Tice <cmtice@google.com>
diff --git a/binary_search_tool/cros_pkg/README.cros_pkg_triage b/binary_search_tool/cros_pkg/README.cros_pkg_triage
new file mode 100644
index 0000000..1530060
--- /dev/null
+++ b/binary_search_tool/cros_pkg/README.cros_pkg_triage
@@ -0,0 +1,185 @@
+
+binary_search_state.py is a general binary search triage tool that
+performs a binary search on a set of things to try to identify which
+thing or thing(s) in the set is 'bad'.  binary_search_state.py assumes
+that the user has two sets, one where everything is known to be good,
+ane one which contains at least one bad item.  binary_search_state.py
+then copies items from the good and bad sets into a working set and
+tests the result (good or bad).  binary_search_state.py requires that
+a set of scripts be supplied to it for any particular job.  For more
+information on binary_search_state.py, see
+
+https://sites.google.com/a/google.com/chromeos-toolchain-team-home2/home/team-tools-and-scripts/binary-searcher-tool-for-triage
+
+This particular set of scripts is designed to work wtih
+binary_search_state.py in order to find the bad package or set of
+packages in a ChromeOS build.
+
+
+QUICKSTART:
+
+After setting up your 3 build trees (see Prerequisites section), do the
+following:
+
+ - Decide which test script to use (cros_pkg_boot_test.sh or
+   cros_pkg_interactive_test.sh)
+ - Get the IP name or address of the chromebook you will use for testing.
+ - Do the following inside your chroot:
+
+   $ cd ~/trunk/src/third_party/toolchain_utils/binary_search_tool/cros_pkg
+   $ ./cros_pkg_setup.sh <board-to-test> \
+                         <IP-name-or-address-of-chromebook>
+
+   If you chose the boot test, then:
+
+   $ python ../binary_search_state.py \
+       --get_initial_items=cros_pkg_get_initial_items.sh \
+       --switch_to_good=cros_pkg_switch_to_good.sh \
+       --switch_to_bad=cros_pkg_switch_to_bad.sh \
+       --test_script=cros_pkg_boot_test.sh \
+       --file_args \
+       --prune
+
+   Otherwise, if you chose the interactive test, then:
+
+   $ python ../binary_search_state.py \
+       --get_initial_items=cros_pkg_get_initial_items.sh \
+       --switch_to_good=cros_pkg_switch_to_good.sh \
+       --switch_to_bad=cros_pkg_switch_to_bad.sh \
+       --test_script=cros_pkg_interactive_test.sh \
+       --file_args \
+       --prune
+
+   Once you have completely finished doing the binary search/triage,
+   run the genereated cleanup script, to restore your chroot to the state
+   it was in before you ran the cros_pkg_setup.sh script:
+
+   $ ./cros_pkg_${BOARD}_cleanup.sh
+
+
+
+FILES AND SCRIPTS:
+
+  cros_pkg_boot_test.sh - One of two possible test scripts used to determine
+                          if the ChromeOS image built from the packages is good
+                          or bad.  This script tests to see if the image
+                          booted, and requires no user intervention.
+
+  cros_pkg_create_cleanup_script.py - This is called by cros_pkg_setup.sh, to
+                                      generate cros_pkg_${BOARD}_cleanup.sh,
+                                      which is supposed to be run by the user
+                                      after the binary search triage process is
+                                      finished, to undo the changes made by
+                                      cros_pkg_setup.sh and return everything
+                                      to its original state.
+
+  cros_pkg_get_initial_items.sh - This script is used to determine the current
+                                  set of ChromeOS packages.
+
+  cros_pkg_interactive_test.sh - One of two possible scripts used to determine
+                                 if the ChromeOS image built from the packages
+                                 is good or bad.  This script requires user
+                                 interaction to determine if the image is
+                                 good or bad.
+
+  cros_pkg_setup.sh - This is the first script the user should call, after
+                      taking care of the prerequisites.  It sets up the
+                      environment appropriately for running the ChromeOS
+                      package binary search triage, and it generates two
+                      necessary scripts (see below).
+
+  cros_pkg_swith_to_bad.sh - This script is used to copy packages from the
+                             'bad' build tree into the work area.
+
+  cros_pkg_swith_to_good.sh - This script is used to copy packages from the
+                              'good' build tree into the work area.
+
+  cros_pkg_undo_eclean.py - Script for modifying build_image script so that it
+                            does not perform any calls to 'eclean', which can
+                            mess up the binary search triage process.
+
+
+GENERATED SCRIPTS:
+
+  cros_pkg_common.sh  - contains basic environment variable definitions for
+                        this binary search triage session.
+
+  cros_pkg_${BOARD}_cleanup.sh - script to undo all the changes made by
+                                 running cros_pkg_setup.sh, and returning
+                                 everything to its original state. The user
+                                 should manually run this script once the
+                                 binary search triage process is over.
+
+ASSUMPTIONS:
+
+- There are two different ChromeOS builds, for the same board, with the
+  same set of ChromeOS packages.  One build creates a good working ChromeOS
+  image and the other does not.
+
+- You have saved the complete build trees for both the good and bad builds.
+
+
+PREREQUISITES FOR USING THESE SCRIPTS (inside the chroot):
+
+- The "good" build tree, for the board, is in /build/${board}.good
+  (e.g. /build/lumpy.good or /build/daisy.good).
+
+- The "bad" build tree is in /build/${board}.bad
+  (e.g. /build/lumpy.bad or /build/daisy.bad).
+
+- You made a complete copy of the "bad" build tree , and put it in
+  /build/${board}.work (e.g. /build/lumpy.work or /build/daisy.work.
+  The easiest way to do this is to use something similar to the
+  following set of commands (this example assumes the board is
+  'lumpy'):
+
+   $ cd /build
+   $ sudo tar -cvf lumpy.bad.tar lumpy.bad
+   $ sudo mv lumpy.bad lumpy.work
+   $ sudo tar -xvf lumpy.bad.tar
+
+
+USING THESE SCRIPTS FOR BINARY TRIAGE OF PACKAGES:
+
+To use these scripts, you must first run cros_pkg_setup.sh, passing it two
+arguments (in order): the board for which you are building the image;
+and the name or ip address of the chromebook you want to use for
+testing your chromeos images.  cros_pkg_setup.sh will do the following:
+
+   - Verify that your build trees are set up correctly (with good, bad
+     and work).
+   - Create a soft link for /build/${board} pointing to the work build
+     tree.
+   - Update build_image, so it will not do 'eclean', which gets in the
+     way of copying packages around for building the image.
+   - Create the cros_pkg_common.sh file that the other scripts passed to the
+     binary triage tool will need.
+   - Create a cleanup script, cros_pkg_${board}_cleanup.sh, for you to
+     run after you are done with the binary triages, to undo all of these
+     various changes that cros_pkg_setup.sh did.
+
+
+This set of scripts comes with two alternate test scripts.  Both test
+scripts build the image and push it onto the Chromebook.  One test
+script, cros_pkg_boot_test.sh, just checks to make sure that the image
+booted (i.e. responds to ping) and assumes that is enough.  The other
+test script, cros_pkg_interactive_test.sh, is interactive and asks YOU
+to tell it whether the image on the chromebook is ok or not (it
+prompts you and waits for a response).
+
+
+Once you have run cros_pkg_setup.sh (and decided which test script you
+want to use) run the binary triage tool using this scripts to
+isolate/identify the bad package:
+
+~/trunk/src/third_party/toolchain_utils/binary_search_tool/binary_search_state.py \
+ --get_initial_items=cros_pkg_get_initial_items.sh \
+ --switch_to_good=cros_pkg_switch_to_good.sh \
+ --switch_to_bad=cros_pkg_switch_to_bad.sh \
+ --test_script=cros_pkg_boots_test.sh \  # could use cros_pkg_interactive_test.sh instead
+ --prune
+
+
+After you have finished running the tool and have identified the bad
+package(s), you will want to run the cleanup script that cros_pkg_setup.sh
+generated (cros_pkg_${BOARD}_cleanup.sh).
diff --git a/binary_search_tool/cros_pkg/cros_pkg_boot_test.sh b/binary_search_tool/cros_pkg/cros_pkg_boot_test.sh
new file mode 100755
index 0000000..382f036
--- /dev/null
+++ b/binary_search_tool/cros_pkg/cros_pkg_boot_test.sh
@@ -0,0 +1,44 @@
+#!/bin/bash -u
+#
+# Copyright 2015 Google Inc. All Rights Reserved.
+#
+# This script calls build_image to generate a new ChromeOS image,
+# using whatever packages are currently in the build tree.  If
+# build_images succeeeds, then it pushes the new ChromeOS image onto a
+# chromebook, then pings the chromebook to determine if it
+# successfully booted.
+#
+# This script is intended to be used by binary_search_state.py, as
+# part of the binary search triage on ChromeOS packages.  It should
+# return '0' if the test succeeds (the image booted); '1' if the test
+# fails (the image did not boot); and '2' if it could not determine
+# (i.e. in this case, the image did not build).
+#
+
+source cros_pkg_common.sh
+
+pushd ~/trunk/src/scripts
+./build_image test --board=${BOARD} --noenable_rootfs_verification
+build_status=$?
+popd
+
+if [[ ${build_status} -eq 0 ]] ; then
+    echo "Pushing built image onto device."
+    echo "cros flash --board=${BOARD} --clobber-stateful ${REMOTE} ~/trunk/src/build/images/${BOARD}/latest/chromiumos_test_image.bin"
+    cros flash --board=${BOARD} --clobber-stateful ${REMOTE} ../build/images/${BOARD}/latest/chromiumos_test_image.bin
+    cros_flash_status=$?
+    if [[ ${cros_flash_status} -ne 0 ]] ; then
+	echo "cros flash failed!!"
+	exit 2
+    fi
+else
+    echo "build_image returned a non-zero status: ${build_status}"
+    exit 2
+fi
+
+# Send 3 pings and wait 3 seconds for any responsed (then timeout).
+ping -c 3 -W 3 ${REMOTE}
+retval=$?
+
+
+exit $retval
diff --git a/binary_search_tool/cros_pkg/cros_pkg_create_cleanup_script.py b/binary_search_tool/cros_pkg/cros_pkg_create_cleanup_script.py
new file mode 100755
index 0000000..bed7106
--- /dev/null
+++ b/binary_search_tool/cros_pkg/cros_pkg_create_cleanup_script.py
@@ -0,0 +1,104 @@
+#!/usr/bin/python
+#
+#  Copyright 2015 Google Inc. All Rights Reserved
+#
+#  This script takes a set of flags, telling it what cros_pkg_setup.sh changed
+#  during the set up process.  Based on the values of the input flags, it
+#  generates a cleanup script, named cros_pkg_${BOARD}_cleanup.sh, which will
+#  undo the changes made by cros_pkg_setup.sh, returning everything to its
+#  original state.
+#
+
+import argparse
+import os
+import sys
+
+
+def Usage(parser, msg):
+    print "ERROR: " + msg
+    parser.print_help()
+    sys.exit(1)
+
+def Main(argv):
+    """
+    The script cros_pkg_setup.sh make two main changes that need to be
+    undone: 1).  It creates a soft link making /build/${board} point to
+    /build/${board}.work, and 2). It saves a copy of the build_image
+    script, then updates build_image to not execute 'eclean'.  For the first
+    change, it had to see if /build/${board} already existed, and if so, whether
+    it was a real tree or a soft link.  If it was soft link, it saved the old
+    value of the link, then deleted it and created the new link.  If it was a
+    real tree, it renamed the tree to /build/${board}.save, and then created the
+    new soft link.  If the /build/${board} did not previously exist, then it just
+    created the new soft link.
+
+    This function takes arguments that tell it exactly what cros_pkg_setup.sh
+    actually did, then generates a script to undo those exact changes.
+    """
+
+    parser = argparse.ArgumentParser()
+    parser.add_argument("--board", dest="board", required=True,
+                        help="Chromeos board for packages/image.")
+
+    parser.add_argument("--old_tree_missing", dest="tree_existed",
+                        action="store_false",
+                        help="Did /build/${BOARD} exist.", default=True)
+
+    parser.add_argument("--renamed_tree", dest="renamed_tree",
+                        action="store_true",
+                        help="Was /build/${BOARD} saved & renamed.",
+                        default=False)
+
+    parser.add_argument("--old_link", dest="old_link",
+                        help=("The original build tree soft link."))
+
+    options = parser.parse_args(argv[1:])
+
+    if options.old_link or options.renamed_tree:
+        if not options.tree_existed:
+            Usage(parser, "If --tree_existed is False, cannot have "
+                  "--renamed_tree or --old_link")
+
+    if options.old_link and options.renamed_tree:
+        Usage(parser, "--old_link and --renamed_tree are incompatible options.")
+
+    if options.tree_existed:
+        if not options.old_link and not options.renamed_tree:
+            Usage(parser, "If --tree_existed is True, then must have either "
+                  "--old_link or --renamed_tree")
+
+    out_filename = "cros_pkg_" + options.board + "_cleanup.sh"
+
+    with open(out_filename, "w") as out_file:
+        out_file.write("#!/bin/bash\n\n")
+        # First, remove the 'new' soft link.
+        out_file.write("sudo rm /build/%s\n" % options.board)
+        if options.tree_existed:
+            if options.renamed_tree:
+                # Old build tree existed and was a real tree, so it got
+                # renamed.  Move the renamed tree back to the original tree.
+                out_file.write("sudo mv /build/%s.save /build/%s\n"
+                               % (options.board, options.board))
+            else:
+                # Old tree existed and was already a soft link.  Re-create the
+                # original soft link.
+                original_link = options.old_link
+                if original_link[0] == "'":
+                    original_link = original_link[1:]
+                if original_link[-1] == "'":
+                    original_link = original_link[:-1]
+                out_file.write("sudo ln -s %s /build/%s\n" % (original_link,
+                                                              options.board))
+        out_file.write("\n")
+        # Restore the original saved version of build_image script.
+        out_file.write("mv ~/trunk/src/scripts/build_image.save "
+                       "~/trunk/src/scripts/build_image\n\n")
+        # Remove cros_pkg_common.sh file
+        out_file.write("rm cros_pkg_common.sh\n")
+
+    return 0
+
+
+if __name__ == "__main__":
+    retval = Main(sys.argv)
+    sys.exit(retval)
diff --git a/binary_search_tool/cros_pkg/cros_pkg_get_initial_items.sh b/binary_search_tool/cros_pkg/cros_pkg_get_initial_items.sh
new file mode 100755
index 0000000..c1ca033
--- /dev/null
+++ b/binary_search_tool/cros_pkg/cros_pkg_get_initial_items.sh
@@ -0,0 +1,16 @@
+#!/bin/bash -u
+#
+# Copyright 2015 Google Inc. All Rights Reserved.
+#
+# This script is intended to be used by binary_search_state.py, as
+# part of the binary search triage on ChromeOS packages.  This script
+# generates the list of current ChromeOS packages, that is then used
+# for doing the binary search.
+#
+
+source cros_pkg_common.sh
+
+cd ${GOOD_BUILD}/packages
+find . -name "*.tbz2"
+
+
diff --git a/binary_search_tool/cros_pkg/cros_pkg_interactive_test.sh b/binary_search_tool/cros_pkg/cros_pkg_interactive_test.sh
new file mode 100755
index 0000000..e79b044
--- /dev/null
+++ b/binary_search_tool/cros_pkg/cros_pkg_interactive_test.sh
@@ -0,0 +1,61 @@
+#!/bin/bash -u
+#
+# Copyright 2015 Google Inc. All Rights Reserved.
+#
+# This script calls build_image to generate a new ChromeOS image,
+# using whatever packages are currently in the build tree.  If
+# build_images succeeeds, then it pushes the new ChromeOS image onto a
+# chromebook, then pings the chromebook to determine if it
+# successfully booted.  It then asks the user if the image is good or not,
+# allowing the user to conduct whatever tests the user wishes, and waiting
+# for a response.
+#
+# This script is intended to be used by binary_search_state.py, as
+# part of the binary search triage on ChromeOS packages.  It should
+# return '0' if the test succeeds (the image is 'good'); '1' if the test
+# fails (the image is 'bad'); and '2' if it could not determine
+# (i.e. in this case, the image did not build).
+#
+
+source cros_pkg_common.sh
+
+pushd ~/trunk/src/scripts
+./build_image test --board=${BOARD} --noenable_rootfs_verification
+build_status=$?
+popd
+
+
+if [[ ${build_status} -eq 0 ]] ; then
+    echo "Pushing built image onto device."
+    echo "cros flash --board=${BOARD} --clobber-stateful ${REMOTE} ~/trunk/src/build/images/${BOARD}/latest/chromiumos_test_image.bin"
+    cros flash --board=${BOARD} --clobber-stateful ${REMOTE} ~/trunk/src/build/images/${BOARD}/latest/chromiumos_test_image.bin
+    cros_flash_status=$?
+    if [[ ${cros_flash_status} -ne 0 ]] ; then
+	echo "cros flash failed!!"
+	exit 2
+    fi
+else
+    echo "build_image returned a non-zero status: ${build_status}"
+    exit 2
+fi
+
+# Send 3 pings and wait 3 seconds for any responsed (then timeout).
+ping -c 3 -W 3 ${REMOTE}
+retval=$?
+
+if [[ ${retval} -eq 0 ]]; then
+    echo "ChromeOS image has been built and installed on ${REMOTE}."
+else
+    exit 1
+fi
+
+while true; do
+    read -p "Is this a good ChromeOS image?" yn
+    case $yn in
+        [Yy]* ) exit 0;;
+        [Nn]* ) exit 1;;
+        * ) echo "Please answer yes or no.";;
+    esac
+done
+
+exit 2
diff --git a/binary_search_tool/cros_pkg/cros_pkg_setup.sh b/binary_search_tool/cros_pkg/cros_pkg_setup.sh
new file mode 100755
index 0000000..b84172f
--- /dev/null
+++ b/binary_search_tool/cros_pkg/cros_pkg_setup.sh
@@ -0,0 +1,139 @@
+#!/bin/bash -u
+#
+# Copyright 2015 Google Inc. All Rights Reserved.
+#
+# This script is part of the ChromeOS package binary search triage process.
+# It should be the first script called by the user, after the user has set up
+# the three necessary build tree directories (see the prerequisites section of
+# README.cros_pkg_triage).
+#
+# This script requires two arguments.  The first argument must be the name of
+# the board for which this work is being done (e.g. 'daisy', 'lumpy','parrot',
+# etc.).  The second argument must be the name or IP address of the chromebook
+# on which the ChromeOS images will be pushed and tested.
+#
+# This script sets up a soft link definining /build/${board} to point to the
+# working build tree, for the binary search triags process.  It also modifies
+# the build_image script, to prevent that script from undoing the package
+# copying that the binary triage process must do.  In addition, this script
+# generates two other scripts, cros_pkg_common.sh, which generates enviroment
+# variables used by the other scripts in the package binary search triage
+# process; and cros_pkg_${board}_cleanup.sh, which undoes the various changes
+# that this script performs, returning the user's environment to its original
+# state.
+#
+
+# Set up basic variables.
+
+BOARD=$1
+REMOTE=$2
+
+GOOD_BUILD=/build/${BOARD}.good
+BAD_BUILD=/build/${BOARD}.bad
+WORK_BUILD=/build/${BOARD}.work
+
+#
+# Verify that the necessary directories exist.
+#
+
+if [[ ! -d ${GOOD_BUILD} ]] ; then
+    echo "Error:  ${GOOD_BUILD} does not exist."
+    exit 1
+fi
+
+if [[ ! -d ${BAD_BUILD} ]] ; then
+    echo "Error:  ${BAD_BUILD} does not exist."
+    exit 1
+fi
+
+if [[ ! -d ${WORK_BUILD} ]] ; then
+    echo "Error:  ${WORK_BUILD} does not exist."
+    exit 1
+fi
+
+#
+# Check to see if /build/${BOARD} already exists and if so, in what state.
+# Set appropriate flags & values, in order to be able to undo these changes
+# in cros_pkg_${board_cleanup.sh.  If it's a soft link, remove it; if it's a
+# read tree, rename it.
+#
+
+build_tree_existed=0
+build_tree_was_soft_link=0
+build_tree_renamed=0
+build_tree_link=""
+
+if [[ -d "/build/${BOARD}" ]] ; then
+    build_tree_existed=1
+    if [[ -L "/build/${BOARD}" ]] ; then
+        build_tree_was_soft_link=1
+        build_tree_link=`readlink /build/${BOARD}`
+        sudo rm /build/${BOARD}
+    else
+        build_tree_renamed=1
+        sudo mv /build/${BOARD} /build/${BOARD}.save
+    fi
+fi
+
+# Make "working' tree the default board tree (set up soft link)
+
+sudo ln -s /build/${BOARD}.work /build/${BOARD}
+
+#
+# Create cros_pkg_common.sh file, containing appropriate environment variables.
+#
+
+COMMON_FILE="cros_pkg_common.sh"
+
+cat <<-EOF > ${COMMON_FILE}
+
+BOARD=${BOARD}
+REMOTE=${REMOTE}
+
+GOOD_BUILD=/build/${BOARD}.good
+BAD_BUILD=/build/${BOARD}.bad
+WORK_BUILD=/build/${BOARD}.work
+
+EOF
+
+chmod 755 ${COMMON_FILE}
+
+#
+# Fix ~/trunk/src/scripts/build_image script to NOT delete/update the packages
+# after we have put them in place.  First save a copy of the original file,
+# then call cros_pkg_undo_eclean.py to edit the script (it creates
+# 'build_image.edited').
+#
+
+cp ~/trunk/src/scripts/build_image .
+python cros_pkg_undo_eclean.py build_image
+if [[ $? -eq 0 ]] ; then
+    chmod 755 build_image.edited
+    mv build_image ~/trunk/src/scripts/build_image.save
+    mv build_image.edited ~/trunk/src/scripts/build_image
+fi
+
+#
+# Create clean-up script, calling cros_pkg_create_cleanup_script.py with
+# the appropriate flags.
+#
+
+if [[ ${build_tree_existed} -eq 0 ]] ; then
+
+    python cros_pkg_create_cleanup_script.py --board=${BOARD} \
+        --old_tree_missing
+
+elif [[ ${build_tree_was_soft_link} -eq 0 ]] ; then
+
+    python cros_pkg_create_cleanup_script.py --board=${BOARD} \
+        --renamed_tree
+
+else
+
+    python cros_pkg_create_cleanup_script.py --board=${BOARD} \
+        --old_link="'${build_tree_link}'"
+fi
+
+chmod 755 cros_pkg_${BOARD}_cleanup.sh
+
+exit 0
diff --git a/binary_search_tool/cros_pkg/cros_pkg_switch_to_bad.sh b/binary_search_tool/cros_pkg/cros_pkg_switch_to_bad.sh
new file mode 100755
index 0000000..f206cb8
--- /dev/null
+++ b/binary_search_tool/cros_pkg/cros_pkg_switch_to_bad.sh
@@ -0,0 +1,45 @@
+#!/bin/bash -u
+#
+# Copyright 2015 Google Inc. All Rights Reserved.
+#
+# This script is intended to be used by binary_search_state.py, as
+# part of the binary search triage on ChromeOS packages.  This script
+# copies a list of packages from the 'bad' build tree into the working
+# build tree, for testing.
+#
+
+source cros_pkg_common.sh
+
+pushd ${WORK_BUILD}
+
+PKG_LIST_FILE=$1
+
+overall_status=0
+
+if [[ -f ${PKG_LIST_FILE} ]] ; then
+
+  while read pkg
+  do
+    sudo cp ${BAD_BUILD}/packages/$pkg ${WORK_BUILD}/packages/$pkg
+    status=$?
+    if [[ ${status} -ne 0 ]] ; then
+      echo "Failed to copy ${pkg} to work build tree."
+      overall_status=2
+    fi
+  done < ${PKG_LIST_FILE}
+else
+
+  for o in "$@"
+  do
+    sudo cp ${BAD_BUILD}/packages/$o  ${WORK_BUILD}/packages/$o
+    status=$?
+    if [[ ${status} -ne 0 ]] ; then
+      echo "Failed to copy ${pkg} to work build tree."
+      overall_status=2
+    fi
+  done
+fi
+
+popd
+
+exit ${overall_status}
diff --git a/binary_search_tool/cros_pkg/cros_pkg_switch_to_good.sh b/binary_search_tool/cros_pkg/cros_pkg_switch_to_good.sh
new file mode 100755
index 0000000..b0d07a3
--- /dev/null
+++ b/binary_search_tool/cros_pkg/cros_pkg_switch_to_good.sh
@@ -0,0 +1,45 @@
+#!/bin/bash -u
+#
+# Copyright 2015 Google Inc. All Rights Reserved.
+#
+# This script is intended to be used by binary_search_state.py, as
+# part of the binary search triage on ChromeOS packages.  This script
+# copies a list of packages from the 'good' build tree into the working
+# build tree, for testing.
+#
+
+source cros_pkg_common.sh
+
+pushd ${WORK_BUILD}
+
+PKG_LIST_FILE=$1
+
+overall_status=0
+
+if [[ -f ${PKG_LIST_FILE} ]] ; then
+
+  while read pkg
+  do
+    sudo cp ${BAD_BUILD}/packages/$pkg ${WORK_BUILD}/packages/$pkg
+    status=$?
+    if [[ ${status} -ne 0 ]] ; then
+      echo "Failed to copy ${pkg} to work build tree."
+      overall_status=2
+    fi
+  done < ${PKG_LIST_FILE}
+else
+
+  for o in "$@"
+  do
+    sudo cp ${GOOD_BUILD}/packages/$o  ${WORK_BUILD}/packages/$o
+    status=$?
+    if [[ ${status} -ne 0 ]] ; then
+      echo "Failed to copy ${pkg} to work build tree."
+      overall_status=2
+    fi
+  done
+fi
+
+popd
+
+exit ${overall_status}
diff --git a/binary_search_tool/cros_pkg/cros_pkg_undo_eclean.py b/binary_search_tool/cros_pkg/cros_pkg_undo_eclean.py
new file mode 100755
index 0000000..a5c612c
--- /dev/null
+++ b/binary_search_tool/cros_pkg/cros_pkg_undo_eclean.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+#
+# Copyright 2015 Google Inc. All Rights Reserved.
+#
+# This script takes a single argument, the name of a file (normally expected to
+# be 'build_image'), which should be a shell script.  It then creates a new
+# output file, named <input_file>.edited, and it copies each line from the
+# input file to the output file.  If the line from the input file contains the
+# string 'eclean', it prepends a '#' to the line before copying it to the
+# output file, in effect commenting out any lines that contain 'eclean'.
+#
+
+import sys
+import os
+
+def Main(args):
+
+    if args:
+        filename = args[0]
+        if not os.path.exists(filename):
+            return 1
+    else:
+        return 1
+
+    outname = filename + ".edited"
+    with open(filename, "r") as input_file:
+        lines = input_file.readlines()
+        with open(outname, "w") as out_file:
+            for line in lines:
+                if line.find("eclean") >= 0:
+                    out_line = "# " + line
+                else:
+                    out_line = line
+                out_file.write(out_line)
+
+    return 0
+
+if __name__ == "__main__":
+    retval = Main(sys.argv[1:])
+    sys.exit(retval)