bisect.py revision 2e37b144ecd1476964e2dc72ac6b5b2a81a32018
1#!/usr/bin/python2
2"""The unified package/object bisecting tool."""
3
4from __future__ import print_function
5
6import abc
7import argparse
8import sys
9import common
10
11from utils import command_executer
12from utils import logger
13
14import binary_search_state
15
16
17class Bisector(object):
18  """The abstract base class for Bisectors."""
19
20  # Make Bisector an abstract class
21  __metaclass__ = abc.ABCMeta
22
23  def __init__(self, options):
24    self.options = options
25    self.logger = logger.GetLogger()
26    self.ce = command_executer.GetCommandExecuter()
27
28  @abc.abstractmethod
29  def PreRun(self):
30    pass
31
32  @abc.abstractmethod
33  def Run(self):
34    pass
35
36  @abc.abstractmethod
37  def PostRun(self):
38    pass
39
40
41class BisectPackage(Bisector):
42  """The class for package bisection steps."""
43
44  cros_pkg_setup = 'cros_pkg/setup.sh'
45  cros_pkg_cleanup = 'cros_pkg/%s_cleanup.sh'
46  default_kwargs = {
47      'get_initial_items': 'cros_pkg/get_initial_items.sh',
48      'switch_to_good': 'cros_pkg/switch_to_good.sh',
49      'switch_to_bad': 'cros_pkg/switch_to_bad.sh',
50      'install_script': 'cros_pkg/install.sh',
51      'test_script': 'cros_pkg/interactive_test.sh',
52      'noincremental': False,
53      'prune': True,
54      'file_args': True
55  }
56
57  def __init__(self, options):
58    super(BisectPackage, self).__init__(options)
59
60  def PreRun(self):
61    cmd = ('%s %s %s' %
62           (self.cros_pkg_setup, self.options.board, self.options.remote))
63    ret, _, _ = self.ce.RunCommandWExceptionCleanup(cmd, print_to_console=True)
64    if ret:
65      self.logger.LogError('Package bisector setup failed w/ error %d' % ret)
66      return 1
67    return 0
68
69  def Run(self):
70    return binary_search_state.Run(**self.default_kwargs)
71
72  def PostRun(self):
73    cmd = self.cros_pkg_cleanup % self.options.board
74    ret, _, _ = self.ce.RunCommandWExceptionCleanup(cmd, print_to_console=True)
75    if ret:
76      self.logger.LogError('Package bisector cleanup failed w/ error %d' % ret)
77      return 1
78    return 0
79
80
81class BisectObject(Bisector):
82  """The class for object bisection steps."""
83
84  def __init__(self, options):
85    super(BisectObject, self).__init__(options)
86
87  def PreRun(self):
88    raise NotImplementedError('Object bisecting still WIP')
89
90  def Run(self):
91    return 1
92
93  def PostRun(self):
94    return 1
95
96
97def Run(bisector):
98  ret = bisector.PreRun()
99  if ret:
100    return ret
101
102  ret = bisector.Run()
103  if ret:
104    return ret
105
106  ret = bisector.PostRun()
107  if ret:
108    return ret
109
110  return 0
111
112
113def Main(argv):
114  parser = argparse.ArgumentParser(epilog=('Run ./bisect.py {command} --help '
115                                           'for individual subcommand '
116                                           'help/args.'))
117  subparsers = parser.add_subparsers(title='Bisect mode',
118                                     description=('Whether to package or object'
119                                                  'bisect'))
120
121  parser_package = subparsers.add_parser('package')
122  parser_package.add_argument('board', help='Board to target')
123  parser_package.add_argument('remote', help='Remote machine to test on')
124  parser_package.set_defaults(handler=BisectPackage)
125
126  parser_object = subparsers.add_parser('object')
127  parser_object.set_defaults(handler=BisectObject)
128
129  options = parser.parse_args(argv)
130
131  subcmd = options.handler
132  del options.handler
133
134  bisector = subcmd(options)
135  return Run(bisector)
136
137
138if __name__ == '__main__':
139  os.chdir(os.path.dirname(__file__))
140  sys.exit(Main(sys.argv[1:]))
141