bisect.py revision bfe9c5300fca09e8790ed25b41028cba8cb0a78f
1#!/usr/bin/python2 2"""The unified package/object bisecting tool.""" 3 4from __future__ import print_function 5 6import abc 7import argparse 8import sys 9from argparse import RawTextHelpFormatter 10 11import common 12 13from utils import command_executer 14from utils import logger 15 16import binary_search_state 17 18 19class Bisector(object): 20 """The abstract base class for Bisectors.""" 21 22 # Make Bisector an abstract class 23 __metaclass__ = abc.ABCMeta 24 25 def __init__(self, options, overrides=None): 26 """Constructor for Bisector abstract base class 27 28 Args: 29 options: positional arguments for specific mode (board, remote, etc.) 30 overrides: optional dict of overrides for argument defaults 31 """ 32 self.options = options 33 self.overrides = overrides 34 if not overrides: 35 self.overrides = {} 36 self.logger = logger.GetLogger() 37 self.ce = command_executer.GetCommandExecuter() 38 39 @abc.abstractmethod 40 def PreRun(self): 41 pass 42 43 @abc.abstractmethod 44 def Run(self): 45 pass 46 47 @abc.abstractmethod 48 def PostRun(self): 49 pass 50 51 52class BisectPackage(Bisector): 53 """The class for package bisection steps.""" 54 55 cros_pkg_setup = 'cros_pkg/setup.sh' 56 cros_pkg_cleanup = 'cros_pkg/%s_cleanup.sh' 57 58 def __init__(self, options, overrides): 59 super(BisectPackage, self).__init__(options, overrides) 60 self.default_kwargs = { 61 'get_initial_items': 'cros_pkg/get_initial_items.sh', 62 'switch_to_good': 'cros_pkg/switch_to_good.sh', 63 'switch_to_bad': 'cros_pkg/switch_to_bad.sh', 64 'install_script': 'cros_pkg/install.sh', 65 'test_script': 'cros_pkg/interactive_test.sh', 66 'noincremental': False, 67 'prune': True, 68 'file_args': True 69 } 70 71 def PreRun(self): 72 cmd = ('%s %s %s' % 73 (self.cros_pkg_setup, self.options.board, self.options.remote)) 74 ret, _, _ = self.ce.RunCommandWExceptionCleanup(cmd, print_to_console=True) 75 if ret: 76 self.logger.LogError('Package bisector setup failed w/ error %d' % ret) 77 return 1 78 return 0 79 80 def Run(self): 81 self.default_kwargs.update(self.overrides) 82 return binary_search_state.Run(**self.default_kwargs) 83 84 def PostRun(self): 85 cmd = self.cros_pkg_cleanup % self.options.board 86 ret, _, _ = self.ce.RunCommandWExceptionCleanup(cmd, print_to_console=True) 87 if ret: 88 self.logger.LogError('Package bisector cleanup failed w/ error %d' % ret) 89 return 1 90 return 0 91 92 93class BisectObject(Bisector): 94 """The class for object bisection steps.""" 95 96 def __init__(self, options, overrides): 97 super(BisectObject, self).__init__(options, overrides) 98 99 def PreRun(self): 100 raise NotImplementedError('Object bisecting still WIP') 101 102 def Run(self): 103 return 1 104 105 def PostRun(self): 106 return 1 107 108 109def Run(bisector): 110 ret = bisector.PreRun() 111 if ret: 112 return ret 113 114 ret = bisector.Run() 115 if ret: 116 return ret 117 118 ret = bisector.PostRun() 119 if ret: 120 return ret 121 122 return 0 123 124 125_HELP_EPILOG = """ 126Run ./bisect.py {method} --help for individual method help/args 127 128------------------ 129 130See README.bisect for examples on argument overriding 131 132See below for full override argument reference: 133""" 134 135 136def Main(argv): 137 override_parser = argparse.ArgumentParser(add_help=False, 138 argument_default=argparse.SUPPRESS, 139 usage='bisect.py {mode} [options]') 140 common.BuildArgParser(override_parser, override=True) 141 142 epilog = _HELP_EPILOG + override_parser.format_help() 143 parser = argparse.ArgumentParser(epilog=epilog, 144 formatter_class=RawTextHelpFormatter) 145 subparsers = parser.add_subparsers(title='Bisect mode', 146 description=('Which bisection method to ' 147 'use. Each method has ' 148 'specific setup and ' 149 'arguments. Please consult ' 150 'the README for more ' 151 'information.')) 152 153 parser_package = subparsers.add_parser('package') 154 parser_package.add_argument('board', help='Board to target') 155 parser_package.add_argument('remote', help='Remote machine to test on') 156 parser_package.set_defaults(handler=BisectPackage) 157 158 parser_object = subparsers.add_parser('object') 159 parser_object.set_defaults(handler=BisectObject) 160 161 options, remaining = parser.parse_known_args(argv) 162 if remaining: 163 overrides = override_parser.parse_args(remaining) 164 overrides = vars(overrides) 165 else: 166 overrides = {} 167 168 subcmd = options.handler 169 del options.handler 170 171 bisector = subcmd(options, overrides) 172 return Run(bisector) 173 174 175if __name__ == '__main__': 176 os.chdir(os.path.dirname(__file__)) 177 sys.exit(Main(sys.argv[1:])) 178