1#!/usr/bin/env python2
2"""Run full bisection test."""
3
4from __future__ import print_function
5
6import argparse
7import os
8import sys
9
10from cros_utils import command_executer
11
12TEST_DIR = 'full_bisect_test'
13DEFAULT_BISECT_DIR = '/tmp/sysroot_bisect'
14
15
16def populate_good_files(top_dir, ce, bisect_dir=DEFAULT_BISECT_DIR):
17  # 'make clean'
18  work_dir = os.path.join(top_dir, TEST_DIR, 'work')
19  cmd = 'rm -f %s/*.o' % work_dir
20  status = ce.RunCommand(cmd)
21  if status != 0:
22    print('Error trying to clean out work directory: %s' % cmd)
23    return status
24
25  # set up the 'good' source files
26  script = os.path.join(top_dir, TEST_DIR, 'make_sources_good.sh')
27  status = ce.RunCommand(script)
28  if status != 0:
29    print('Error setting up "good" source files: %s' % script)
30    return status
31
32  export_bisect = 'export BISECT_DIR=%s; ' % bisect_dir
33  # build the good source files
34  script_path = os.path.join(top_dir, TEST_DIR)
35  if os.path.exists('/usr/bin/x86_64-cros-linux-gnu-gcc'):
36    build_script = 'chromeos_build.sh'
37  else:
38    build_script = 'build.sh'
39  cmd = ('%s export BISECT_STAGE=POPULATE_GOOD; pushd %s; ./%s; popd' %
40         (export_bisect, script_path, build_script))
41  status = ce.RunCommand(cmd)
42  return status
43
44
45def populate_bad_files(top_dir, ce, bisect_dir=DEFAULT_BISECT_DIR):
46  # 'make clean'
47  work_dir = os.path.join(top_dir, TEST_DIR, 'work')
48  cmd = 'rm -f %s/*.o' % work_dir
49  status = ce.RunCommand(cmd)
50  if status != 0:
51    print('Error trying to clean out work directory: %s' % cmd)
52    return status
53
54  # set up the 'bad' source files
55  script = os.path.join(top_dir, TEST_DIR, 'make_sources_bad.sh')
56  status = ce.RunCommand(script)
57  if status != 0:
58    print('Error setting up "bad" source files: %s' % script)
59    return status
60
61  export_bisect = 'export BISECT_DIR=%s; ' % bisect_dir
62  # build the bad source files
63  script_path = os.path.join(top_dir, TEST_DIR)
64  if os.path.exists('/usr/bin/x86_64-cros-linux-gnu-gcc'):
65    build_script = 'chromeos_build.sh'
66  else:
67    build_script = 'build.sh'
68  cmd = ('%s export BISECT_STAGE=POPULATE_BAD; pushd %s; ./%s ; popd' %
69         (export_bisect, script_path, build_script))
70  status = ce.RunCommand(cmd)
71  return status
72
73
74def run_main_bisection_test(top_dir, ce):
75  test_script = os.path.join(top_dir, TEST_DIR, 'main-bisect-test.sh')
76  status = ce.RunCommand(test_script)
77  return status
78
79
80def verify_compiler_and_wrapper():
81  # We don't need to do any special setup if running inside a ChromeOS
82  # chroot.
83  if os.path.exists('/usr/bin/x86_64-cros-linux-gnu-gcc'):
84    return
85
86  message = """
87*** IMPORTANT --- READ THIS CAREFULLY!! ***
88
89This test uses the command 'gcc' to compile the good/bad versions of the
90source program.  BEFORE you can run this script you must make sure that
91your compiler wrapper is in the right place, with the right name, so that
92a call to 'gcc' will go through your compiler wrapper and "do the right
93thing".
94
95Is your compiler wrapper properly set up? [Y/n]
96"""
97
98  print(message)
99  inp = sys.stdin.readline()
100  inp = inp.strip()
101  inp = inp.lower()
102  return not inp or inp == 'y' or inp == 'yes'
103
104
105def Main(argv):
106  parser = argparse.ArgumentParser()
107  parser.add_argument(
108      '--dir',
109      dest='directory',
110      help='Bisection work tree, where good  & bad object '
111      'files go.  Default is /tmp/sysroot_bisect')
112
113  options = parser.parse_args(argv)
114
115  # Make sure the compiler wrapper & soft links are properly set up.
116  wrapper_is_setup = verify_compiler_and_wrapper()
117  if not wrapper_is_setup:
118    print('Exiting now.  Please re-run after you have set up the compiler '
119          'wrapper.')
120    return 0
121
122  # Make sure we're in the correct directory for running this test.
123  cwd = os.getcwd()
124  if not os.path.exists(os.path.join(cwd, 'full_bisect_test')):
125    print('Error:  Wrong directory.  This script must be run from the top level'
126          ' of the binary_search_tool tree (under toolchain_utils).')
127    return 1
128
129  ce = command_executer.GetCommandExecuter()
130  bisect_dir = options.directory
131  if not bisect_dir:
132    bisect_dir = DEFAULT_BISECT_DIR
133
134  # Make sure BISECT_DIR is clean
135  if os.path.exists(bisect_dir):
136    cmd = 'rm -Rf %s/*' % bisect_dir
137    retv = ce.RunCommand(cmd)
138    if retv != 0:
139      return retv
140
141  retv = populate_good_files(cwd, ce, bisect_dir)
142  if retv != 0:
143    return retv
144
145  retv = populate_bad_files(cwd, ce, bisect_dir)
146  if retv != 0:
147    return retv
148
149  # Set up good/bad work soft links
150  cmd = ('rm -f %s/%s/good-objects; ln -s %s/good %s/%s/good-objects' %
151         (cwd, TEST_DIR, bisect_dir, cwd, TEST_DIR))
152
153  status = ce.RunCommand(cmd)
154  if status != 0:
155    print('Error executing: %s; exiting now.' % cmd)
156    return status
157
158  cmd = ('rm -f %s/%s/bad-objects; ln -s %s/bad %s/%s/bad-objects' %
159         (cwd, TEST_DIR, bisect_dir, cwd, TEST_DIR))
160
161  status = ce.RunCommand(cmd)
162  if status != 0:
163    print('Error executing: %s; exiting now.' % cmd)
164    return status
165
166  retv = run_main_bisection_test(cwd, ce)
167  return retv
168
169
170if __name__ == '__main__':
171  retval = Main(sys.argv[1:])
172  sys.exit(retval)
173