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)