Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """This module holds utilities which make writing recipes easier.""" | 5 """This module holds utilities which make writing recipes easier.""" |
| 6 | 6 |
| 7 import contextlib as _contextlib | 7 import contextlib as _contextlib |
| 8 import os as _os | 8 import os as _os |
| 9 | 9 |
| 10 # These imports are intended to be passed through to recipes | 10 # These imports are intended to be passed through to recipes |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 56 | 56 |
| 57 The actual checkout root is filled in by annotated_run after the recipe | 57 The actual checkout root is filled in by annotated_run after the recipe |
| 58 completes, and is dependent on the implementation of 'root()' in | 58 completes, and is dependent on the implementation of 'root()' in |
| 59 annotated_checkout for the checkout type that you've selected. | 59 annotated_checkout for the checkout type that you've selected. |
| 60 | 60 |
| 61 NOTE: In order for this function to work, your recipe MUST use the 'checkout' | 61 NOTE: In order for this function to work, your recipe MUST use the 'checkout' |
| 62 functionality provided by annotated_run. | 62 functionality provided by annotated_run. |
| 63 """ # pylint: disable=W0105 | 63 """ # pylint: disable=W0105 |
| 64 checkout_path = _path_method('checkout_path', '%(CheckoutRootPlaceholder)s') | 64 checkout_path = _path_method('checkout_path', '%(CheckoutRootPlaceholder)s') |
| 65 | 65 |
| 66 def path_exists(path): | |
| 67 return _os.path.exists(path) | |
| 66 | 68 |
| 67 @_contextlib.contextmanager | 69 @_contextlib.contextmanager |
| 68 def mock_paths(): | 70 def mock_paths(mock_path_exists=None): |
| 69 """Used by unittest/recipes_test.py to temporarily override the paths | 71 """Used by unittest/recipes_test.py to temporarily override the paths |
| 70 generated by the various path functions in this module. | 72 generated by the various path functions in this module. |
| 71 | 73 |
| 72 This is necessary to give equivalent output when running the tests on any | 74 This is necessary to give equivalent output when running the tests on any |
| 73 checkout configuration. Instead of real paths, recipes which use these | 75 checkout configuration. Instead of real paths, recipes which use these |
| 74 functions will get paths like '[DEPOT_TOOLS_ROOT]'. | 76 functions will get paths like '[DEPOT_TOOLS_ROOT]'. |
| 75 """ | 77 """ |
| 76 path_base_names = ['depot_tools', 'build_internal', 'build', 'slave_build', | 78 path_base_names = ['depot_tools', 'build_internal', 'build', 'slave_build', |
| 77 'root'] | 79 'root'] |
| 78 g = globals() | 80 g = globals() |
| 79 tokens = {} | 81 tokens = {} |
| 80 path_funcs = {} | 82 path_funcs = {} |
| 81 try: | 83 try: |
| 82 for name in path_base_names: | 84 for name in path_base_names: |
| 83 token_name = (name + '_root').upper() | 85 token_name = (name + '_root').upper() |
| 84 token_val = '[%s]' % token_name | 86 token_val = '[%s]' % token_name |
| 85 path_func_name = (name + '_path') | 87 path_func_name = (name + '_path') |
| 86 | 88 |
| 87 if token_name in g: | 89 if token_name in g: |
| 88 tokens[token_name] = g[token_name] | 90 tokens[token_name] = g[token_name] |
| 89 g[token_name] = token_val | 91 g[token_name] = token_val |
| 90 | 92 |
| 91 if path_func_name in g: | 93 if path_func_name in g: |
| 92 path_funcs[path_func_name] = g[path_func_name] | 94 path_funcs[path_func_name] = g[path_func_name] |
| 93 g[path_func_name] = _path_method(path_func_name, token_val) | 95 g[path_func_name] = _path_method(path_func_name, token_val) |
| 96 | |
| 97 if mock_path_exists: | |
|
iannucci
2013/05/20 19:41:38
Let's replace path_exists no matter what. If not m
mkosiba (inactive)
2013/05/21 10:56:07
Done.
| |
| 98 path_funcs['path_exists'] = g['path_exists'] | |
| 99 g['path_exists'] = lambda path: path in mock_path_exists | |
| 94 yield | 100 yield |
| 95 finally: | 101 finally: |
| 96 g.update(tokens) | 102 g.update(tokens) |
| 97 g.update(path_funcs) | 103 g.update(path_funcs) |
| 98 | 104 |
| 99 | 105 |
| 100 def deep_set(obj, key_vals): | 106 def deep_set(obj, key_vals): |
| 101 """Take an object (a dict or list), and a list of key/value pairs to set, | 107 """Take an object (a dict or list), and a list of key/value pairs to set, |
| 102 and transform it by replacing items in obj at the key locations with the | 108 and transform it by replacing items in obj at the key locations with the |
| 103 respective values. | 109 respective values. |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 359 'recursive': recursive, | 365 'recursive': recursive, |
| 360 }, | 366 }, |
| 361 }), | 367 }), |
| 362 self.git('fetch', 'origin', *recursive_args), | 368 self.git('fetch', 'origin', *recursive_args), |
| 363 self.git('update-ref', 'refs/heads/'+branch, 'origin/'+branch), | 369 self.git('update-ref', 'refs/heads/'+branch, 'origin/'+branch), |
| 364 self.git('clean', '-f', '-d', '-X'), | 370 self.git('clean', '-f', '-d', '-X'), |
| 365 self.git('checkout', '-f', branch), | 371 self.git('checkout', '-f', branch), |
| 366 self.git('submodule', 'update', '--init', '--recursive'), | 372 self.git('submodule', 'update', '--init', '--recursive'), |
| 367 ] | 373 ] |
| 368 | 374 |
| 369 def gclient_checkout(self, common_repo_name, git_mode=False): | 375 def gclient_checkout(self, common_repo_name_or_spec, git_mode=False, |
| 376 spec_name=None): | |
| 370 """Returns a step generator function for gclient checkouts.""" | 377 """Returns a step generator function for gclient checkouts.""" |
| 371 spec = GCLIENT_COMMON_SPECS[common_repo_name](self) | 378 if isinstance(common_repo_name_or_spec, basestring): |
| 379 spec = GCLIENT_COMMON_SPECS[common_repo_name_or_spec](self) | |
| 380 else: | |
| 381 spec = common_repo_name_or_spec | |
| 372 spec_string = '' | 382 spec_string = '' |
| 383 if not spec_name: | |
| 384 step_name = lambda n: 'gclient ' + n | |
| 385 else: | |
| 386 step_name = lambda n: '[spec: %s] gclient %s' % (spec_name, n) | |
| 373 for key in spec: | 387 for key in spec: |
| 374 # We should be using json.dumps here, but gclient directly execs the dict | 388 # We should be using json.dumps here, but gclient directly execs the dict |
| 375 # that it receives as the argument to --spec, so we have to have True, | 389 # that it receives as the argument to --spec, so we have to have True, |
| 376 # False, and None instead of JSON's true, false, and null. | 390 # False, and None instead of JSON's true, false, and null. |
| 377 spec_string += '%s = %s\n' % (key, str(spec[key])) | 391 spec_string += '%s = %s\n' % (key, str(spec[key])) |
| 378 gclient = depot_tools_path('gclient') + ('.bat' if IsWindows() else '') | 392 gclient = depot_tools_path('gclient') + ('.bat' if IsWindows() else '') |
| 379 | 393 |
| 380 if not git_mode: | 394 if not git_mode: |
| 381 clean_step = self.step('gclient clean', [gclient, 'revert', '--nohooks']) | 395 clean_step = self.step(step_name('clean'), |
| 382 sync_step = self.step('gclient sync', [gclient, 'sync', '--nohooks']) | 396 [gclient, 'revert', '--nohooks']) |
| 397 sync_step = self.step(step_name('sync'), [gclient, 'sync', '--nohooks']) | |
| 383 else: | 398 else: |
| 384 # clean() isn't used because the gclient sync flags passed in checkout() | 399 # clean() isn't used because the gclient sync flags passed in checkout() |
| 385 # do much the same thing, and they're more correct than doing a separate | 400 # do much the same thing, and they're more correct than doing a separate |
| 386 # 'gclient revert' because it makes sure the other args are correct when | 401 # 'gclient revert' because it makes sure the other args are correct when |
| 387 # a repo was deleted and needs to be re-cloned (notably | 402 # a repo was deleted and needs to be re-cloned (notably |
| 388 # --with_branch_heads), whereas 'revert' uses default args for clone | 403 # --with_branch_heads), whereas 'revert' uses default args for clone |
| 389 # operations. | 404 # operations. |
| 390 # | 405 # |
| 391 # TODO(mmoss): To be like current official builders, this step could just | 406 # TODO(mmoss): To be like current official builders, this step could just |
| 392 # delete the whole <slave_name>/build/ directory and start each build | 407 # delete the whole <slave_name>/build/ directory and start each build |
| 393 # from scratch. That might be the least bad solution, at least until we | 408 # from scratch. That might be the least bad solution, at least until we |
| 394 # have a reliable gclient method to produce a pristine working dir for | 409 # have a reliable gclient method to produce a pristine working dir for |
| 395 # git-based builds (e.g. maybe some combination of 'git reset/clean -fx' | 410 # git-based builds (e.g. maybe some combination of 'git reset/clean -fx' |
| 396 # and removing the 'out' directory). | 411 # and removing the 'out' directory). |
| 397 clean_step = None | 412 clean_step = None |
| 398 sync_step = self.step('gclient sync', [ | 413 sync_step = self.step(step_name('sync'), [ |
| 399 gclient, 'sync', '--verbose', '--with_branch_heads', '--nohooks', | 414 gclient, 'sync', '--verbose', '--with_branch_heads', '--nohooks', |
| 400 '--reset', '--delete_unversioned_trees', '--force']) | 415 '--reset', '--delete_unversioned_trees', '--force']) |
| 401 steps = [ | 416 steps = [ |
| 402 self.step( | 417 self.step( |
| 403 'gclient setup', | 418 step_name('setup'), |
| 404 [gclient, 'config', '--spec', spec_string], | 419 [gclient, 'config', '--spec', spec_string], |
| 405 static_json_data={ | 420 static_json_data={ |
| 406 'CheckoutRoot': slave_build_path(spec['solutions'][0]['name']), | 421 'CheckoutRoot': slave_build_path(spec['solutions'][0]['name']), |
| 407 'CheckoutSCM': 'gclient', | 422 'CheckoutSCM': 'gclient', |
| 408 'CheckoutSpec': spec | 423 'CheckoutSpec': spec |
| 409 } | 424 } |
| 410 ), | 425 ), |
| 411 ] | 426 ] |
| 412 if clean_step: | 427 if clean_step: |
| 413 steps.append(clean_step) | 428 steps.append(clean_step) |
| 414 if sync_step: | 429 if sync_step: |
| 415 steps.append(sync_step) | 430 steps.append(sync_step) |
| 416 | 431 |
| 417 return steps | 432 return steps |
| OLD | NEW |