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