Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Helper script for fully-annotated builds. Performs checkouts of various | 6 """Helper script for fully-annotated builds. Performs checkouts of various |
| 7 kinds. | 7 kinds. |
| 8 | 8 |
| 9 This script is part of the effort to move all builds to annotator-based systems. | 9 This script is part of the effort to move all builds to annotator-based systems. |
| 10 Any builder configured to use the AnnotatorFactory uses run.py as its entry | 10 Any builder configured to use the AnnotatorFactory uses run.py as its entry |
| 11 point. If that builder's factory_properties include a spec for a checkout, then | 11 point. If that builder's factory_properties include a spec for a checkout, then |
| 12 the work of actually performing that checkout is done here. | 12 the work of actually performing that checkout is done here. |
| 13 """ | 13 """ |
| 14 | 14 |
| 15 import cStringIO as StringIO | |
| 15 import optparse | 16 import optparse |
| 16 import os | 17 import os |
| 18 import pipes | |
| 17 import subprocess | 19 import subprocess |
| 18 import sys | 20 import sys |
| 19 import pipes | |
| 20 | 21 |
| 21 from common import annotator | 22 from common import annotator |
| 22 from common import chromium_utils | 23 from common import chromium_utils |
| 23 | 24 |
| 24 | 25 |
| 25 SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__)) | 26 SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__)) |
| 26 | 27 |
| 27 | 28 |
| 28 def get_args(): | 29 def get_args(): |
| 29 """Process command-line arguments.""" | 30 """Process command-line arguments.""" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 Attributes: | 69 Attributes: |
| 69 CHECKOUT_TYPE: String identifier used when selecting the type of checkout to | 70 CHECKOUT_TYPE: String identifier used when selecting the type of checkout to |
| 70 perform. All subclasses must specify a unique CHECKOUT_TYPE value. | 71 perform. All subclasses must specify a unique CHECKOUT_TYPE value. |
| 71 """ | 72 """ |
| 72 __metaclass__ = _CheckoutMetaclass | 73 __metaclass__ = _CheckoutMetaclass |
| 73 CHECKOUT_TYPE = None | 74 CHECKOUT_TYPE = None |
| 74 | 75 |
| 75 def __init__(self, spec): | 76 def __init__(self, spec): |
| 76 self.spec = spec | 77 self.spec = spec |
| 77 | 78 |
| 79 def setup(self): | |
| 80 pass | |
| 81 | |
| 78 def clean(self): | 82 def clean(self): |
| 79 pass | 83 pass |
| 80 | 84 |
| 81 def checkout(self): | 85 def checkout(self): |
| 82 pass | 86 pass |
| 83 | 87 |
| 84 def root(self): | 88 def root(self): |
| 85 pass | 89 pass |
| 86 | 90 |
| 87 | 91 |
| 88 def CheckoutFactory(type_name, spec): | 92 def CheckoutFactory(type_name, spec): |
| 89 """Factory to build Checkout class instances.""" | 93 """Factory to build Checkout class instances.""" |
| 90 class_ = _CheckoutMetaclass.checkout_registry.get(type_name) | 94 class_ = _CheckoutMetaclass.checkout_registry.get(type_name) |
| 91 if not class_ or not issubclass(class_, Checkout): | 95 if not class_ or not issubclass(class_, Checkout): |
| 92 raise KeyError('unrecognized checkout type: %s' % type_name) | 96 raise KeyError('unrecognized checkout type: %s' % type_name) |
| 93 return class_(spec) | 97 return class_(spec) |
| 94 | 98 |
| 95 | 99 |
| 96 class GclientCheckout(Checkout): | 100 class GclientCheckout(Checkout): |
| 97 CHECKOUT_TYPE = 'gclient' | 101 CHECKOUT_TYPE = 'gclient' |
| 98 | 102 |
| 99 gclient_path = os.path.abspath( | 103 gclient_path = os.path.abspath( |
| 100 os.path.join(SCRIPT_PATH, '..', '..', '..', 'depot_tools', 'gclient')) | 104 os.path.join(SCRIPT_PATH, '..', '..', '..', 'depot_tools', 'gclient')) |
| 101 if sys.platform.startswith('win'): | 105 if sys.platform.startswith('win'): |
| 102 gclient_path += '.bat' | 106 gclient_path += '.bat' |
| 103 | 107 |
| 104 def __init__(self, *args, **kwargs): | 108 def __init__(self, *args, **kwargs): |
| 105 super(GclientCheckout, self).__init__(*args, **kwargs) | 109 super(GclientCheckout, self).__init__(*args, **kwargs) |
| 106 assert 'solutions' in self.spec | 110 assert 'solutions' in self.spec |
| 111 | |
| 112 @classmethod | |
| 113 def run_gclient(cls, *cmd): | |
| 114 print 'Running: gclient %s' % ' '.join(pipes.quote(x) for x in cmd) | |
| 115 subprocess.check_call((cls.gclient_path,)+cmd) | |
| 116 | |
| 117 def setup(self): | |
| 107 spec_string = '' | 118 spec_string = '' |
| 108 for key in self.spec: | 119 for key in self.spec: |
| 109 # We should be using json.dumps here, but gclient directly execs the dict | 120 # We should be using json.dumps here, but gclient directly execs the dict |
| 110 # that it receives as the argument to --spec, so we have to have True, | 121 # that it receives as the argument to --spec, so we have to have True, |
| 111 # False, and None instead of JSON's true, false, and null. | 122 # False, and None instead of JSON's true, false, and null. |
| 112 spec_string += '%s = %s\n' % (key, str(self.spec[key])) | 123 spec_string += '%s = %s\n' % (key, str(self.spec[key])) |
| 113 self.run_gclient('config', '--spec', spec_string) | 124 self.run_gclient('config', '--spec', spec_string) |
| 114 | 125 |
| 115 @classmethod | |
| 116 def run_gclient(cls, *cmd): | |
| 117 print 'Running: gclient %s' % ' '.join(pipes.quote(x) for x in cmd) | |
| 118 subprocess.check_call((cls.gclient_path,)+cmd) | |
| 119 | |
| 120 def clean(self): | 126 def clean(self): |
| 121 self.run_gclient('revert', '--nohooks') | 127 self.run_gclient('revert', '--nohooks') |
| 122 | 128 |
| 123 def checkout(self): | 129 def checkout(self): |
| 124 self.run_gclient('sync', '--nohooks') | 130 self.run_gclient('sync', '--nohooks') |
| 125 | 131 |
| 126 def root(self): | 132 def root(self): |
| 127 return os.path.abspath(self.spec['solutions'][0]['name']) | 133 return os.path.abspath(self.spec['solutions'][0]['name']) |
| 128 | 134 |
| 129 | 135 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 assert os.pardir not in self.spec.get('directory', '') | 171 assert os.pardir not in self.spec.get('directory', '') |
| 166 | 172 |
| 167 dir_path = self.spec.get('directory') | 173 dir_path = self.spec.get('directory') |
| 168 if not dir_path: | 174 if not dir_path: |
| 169 dir_path = self.spec['url'].rsplit('/', 1)[-1] | 175 dir_path = self.spec['url'].rsplit('/', 1)[-1] |
| 170 if dir_path.endswith('.git'): # ex: https://host/foobar.git | 176 if dir_path.endswith('.git'): # ex: https://host/foobar.git |
| 171 dir_path = dir_path[:-len('.git')] | 177 dir_path = dir_path[:-len('.git')] |
| 172 if not dir_path: # ex: ssh://host:repo/foobar/.git | 178 if not dir_path: # ex: ssh://host:repo/foobar/.git |
| 173 dir_path = dir_path.rsplit('/', 1)[-1] | 179 dir_path = dir_path.rsplit('/', 1)[-1] |
| 174 self.cwd = os.path.abspath(os.path.join(os.curdir, dir_path)) | 180 self.cwd = os.path.abspath(os.path.join(os.curdir, dir_path)) |
| 181 | |
| 182 def setup(self): | |
| 175 if not os.path.exists(self.cwd): | 183 if not os.path.exists(self.cwd): |
| 176 os.makedirs(self.cwd) | 184 os.makedirs(self.cwd) |
| 177 | 185 |
| 178 try: | 186 try: |
| 179 self.run_git('branch') | 187 self.run_git('branch') |
| 180 exists = True | 188 exists = True |
| 181 except subprocess.CalledProcessError: | 189 except subprocess.CalledProcessError: |
| 182 exists = False | 190 exists = False |
| 183 if exists: | 191 if exists: |
| 184 self.run_git('remote', 'rm', 'origin') | 192 self.run_git('remote', 'rm', 'origin') |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 206 self.run_git('submodule', 'update', '--init', '--recursive') | 214 self.run_git('submodule', 'update', '--init', '--recursive') |
| 207 | 215 |
| 208 def root(self): | 216 def root(self): |
| 209 return self.cwd | 217 return self.cwd |
| 210 | 218 |
| 211 | 219 |
| 212 class SvnCheckout(Checkout): | 220 class SvnCheckout(Checkout): |
| 213 CHECKOUT_TYPE = 'svn' | 221 CHECKOUT_TYPE = 'svn' |
| 214 | 222 |
| 215 | 223 |
| 216 def run(checkout_type, checkout_spec): | 224 def run(checkout_type, checkout_spec, test_mode=False): |
| 217 """Perform a checkout with the given type and configuration. | 225 """Perform a checkout with the given type and configuration. |
| 218 | 226 |
| 219 Args: | 227 Args: |
| 220 checkout_type: Type of checkout to perform (matching a Checkout subclass | 228 checkout_type: Type of checkout to perform (matching a Checkout subclass |
| 221 CHECKOUT_TYPE attribute). | 229 CHECKOUT_TYPE attribute). |
| 222 checkout_spec: Configuration values needed for the type of checkout | 230 checkout_spec: Configuration values needed for the type of checkout |
| 223 (repository url, etc.). | 231 (repository url, etc.). |
| 232 test_mode: If we're in test_mode, just return error code and root without | |
| 233 actually doing anything. | |
| 224 | 234 |
| 225 Returns: | 235 Returns: |
| 226 Tuple of (<retcode>, <root_path>) where root_path is the absolute path | 236 Tuple of (<retcode>, <root_path>) where root_path is the absolute path |
| 227 to the 'root' of the checkout (as defined by |checkout_type|). | 237 to the 'root' of the checkout (as defined by |checkout_type|). |
| 228 """ | 238 """ |
| 239 stream = sys.stdout | |
| 240 if test_mode: | |
| 241 stream = StringIO.StringIO() | |
| 229 stream = annotator.StructuredAnnotationStream( | 242 stream = annotator.StructuredAnnotationStream( |
| 230 seed_steps=['checkout_setup', 'checkout_clean', 'checkout']) | 243 seed_steps=['checkout_setup', 'checkout_clean', 'checkout'], |
| 244 stream=stream) | |
| 245 | |
| 231 with stream.step('checkout_setup') as s: | 246 with stream.step('checkout_setup') as s: |
| 232 try: | 247 try: |
| 233 checkout = CheckoutFactory(checkout_type, checkout_spec) | 248 checkout = CheckoutFactory(checkout_type, checkout_spec) |
| 234 except KeyError as e: | 249 except KeyError as e: |
| 235 s.step_text(e) | 250 s.step_text(e) |
| 236 s.step_failure() | 251 s.step_failure() |
| 237 return (1, None) | 252 return (1, None) |
| 253 if test_mode: | |
| 254 return (0, checkout.root()) | |
|
agable
2013/05/14 20:47:23
And sometimes I wish GOTOs were socially acceptabl
iannucci
2013/05/14 21:32:08
Or part of the language...
| |
| 255 checkout.setup() | |
| 238 with stream.step('checkout_clean') as s: | 256 with stream.step('checkout_clean') as s: |
| 239 checkout.clean() | 257 checkout.clean() |
| 240 with stream.step('checkout') as s: | 258 with stream.step('checkout') as s: |
| 241 checkout.checkout() | 259 checkout.checkout() |
| 242 return (0, checkout.root()) | 260 return (0, checkout.root()) |
| 243 | 261 |
| 244 | 262 |
| 245 def main(): | 263 def main(): |
| 246 opts, _ = get_args() | 264 opts, _ = get_args() |
| 247 return run(opts.type, opts.spec)[0] | 265 return run(opts.type, opts.spec)[0] |
| 248 | 266 |
| 249 | 267 |
| 250 if __name__ == '__main__': | 268 if __name__ == '__main__': |
| 251 sys.exit(main()) | 269 sys.exit(main()) |
| OLD | NEW |