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