Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2012 The LUCI Authors. All rights reserved. | 2 # Copyright 2012 The LUCI Authors. All rights reserved. |
| 3 # Use of this source code is governed under the Apache License, Version 2.0 | 3 # Use of this source code is governed under the Apache License, Version 2.0 |
| 4 # that can be found in the LICENSE file. | 4 # that can be found in the LICENSE file. |
| 5 | 5 |
| 6 """Runs a command with optional isolated input/output. | 6 """Runs a command with optional isolated input/output. |
| 7 | 7 |
| 8 Despite name "run_isolated", can run a generic non-isolated command specified as | 8 Despite name "run_isolated", can run a generic non-isolated command specified as |
| 9 args. | 9 args. |
| 10 | 10 |
| 11 If input isolated hash is provided, fetches it, creates a tree of hard links, | 11 If input isolated hash is provided, fetches it, creates a tree of hard links, |
| 12 appends args to the command in the fetched isolated and runs it. | 12 appends args to the command in the fetched isolated and runs it. |
| 13 To improve performance, keeps a local cache. | 13 To improve performance, keeps a local cache. |
| 14 The local cache can safely be deleted. | 14 The local cache can safely be deleted. |
| 15 | 15 |
| 16 Any ${EXECUTABLE_SUFFIX} on the command line will be replaced with ".exe" string | 16 Any ${EXECUTABLE_SUFFIX} on the command line will be replaced with ".exe" string |
| 17 on Windows and "" on other platforms. | 17 on Windows and "" on other platforms. |
| 18 | 18 |
| 19 Any ${ISOLATED_OUTDIR} on the command line will be replaced by the location of a | 19 Any ${ISOLATED_OUTDIR} on the command line will be replaced by the location of a |
| 20 temporary directory upon execution of the command specified in the .isolated | 20 temporary directory upon execution of the command specified in the .isolated |
| 21 file. All content written to this directory will be uploaded upon termination | 21 file. All content written to this directory will be uploaded upon termination |
| 22 and the .isolated file describing this directory will be printed to stdout. | 22 and the .isolated file describing this directory will be printed to stdout. |
| 23 | 23 |
| 24 Any ${SWARMING_BOT_FILE} on the command line will be replaced by the value of | 24 Any ${SWARMING_BOT_FILE} on the command line will be replaced by the value of |
| 25 the --bot-file parameter. This file is used by a swarming bot to communicate | 25 the --bot-file parameter. This file is used by a swarming bot to communicate |
| 26 state of the host to tasks. It is written to by the swarming bot's | 26 state of the host to tasks. It is written to by the swarming bot's |
| 27 on_before_task() hook in the swarming server's custom bot_config.py. | 27 on_before_task() hook in the swarming server's custom bot_config.py. |
| 28 """ | 28 """ |
| 29 | 29 |
| 30 __version__ = '0.9' | 30 __version__ = '0.9.1' |
| 31 | 31 |
| 32 import argparse | 32 import argparse |
| 33 import base64 | 33 import base64 |
| 34 import collections | 34 import collections |
| 35 import contextlib | 35 import contextlib |
| 36 import json | 36 import json |
| 37 import logging | 37 import logging |
| 38 import optparse | 38 import optparse |
| 39 import os | 39 import os |
| 40 import sys | 40 import sys |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 396 'duration': time.time() - start, | 396 'duration': time.time() - start, |
| 397 'items_cold': base64.b64encode(large.pack(cold)), | 397 'items_cold': base64.b64encode(large.pack(cold)), |
| 398 'items_hot': base64.b64encode(large.pack(hot)), | 398 'items_hot': base64.b64encode(large.pack(hot)), |
| 399 } | 399 } |
| 400 return outputs_ref, success, stats | 400 return outputs_ref, success, stats |
| 401 | 401 |
| 402 | 402 |
| 403 def map_and_run( | 403 def map_and_run( |
| 404 command, isolated_hash, storage, isolate_cache, outputs, init_named_caches, | 404 command, isolated_hash, storage, isolate_cache, outputs, init_named_caches, |
| 405 leak_temp_dir, root_dir, hard_timeout, grace_period, bot_file, extra_args, | 405 leak_temp_dir, root_dir, hard_timeout, grace_period, bot_file, extra_args, |
| 406 install_packages_fn, use_symlinks): | 406 install_packages_fn, use_symlinks, constant_path): |
|
nodir
2017/04/06 22:58:16
this name is generic and does not necessarily mean
M-A Ruel
2017/04/07 15:36:33
Changed to constant_run_path.
| |
| 407 """Runs a command with optional isolated input/output. | 407 """Runs a command with optional isolated input/output. |
| 408 | 408 |
| 409 See run_tha_test for argument documentation. | 409 See run_tha_test for argument documentation. |
| 410 | 410 |
| 411 Returns metadata about the result. | 411 Returns metadata about the result. |
| 412 """ | 412 """ |
| 413 assert root_dir or root_dir is None | 413 assert root_dir or root_dir is None |
| 414 assert bool(command) ^ bool(isolated_hash) | 414 assert bool(command) ^ bool(isolated_hash) |
| 415 result = { | 415 result = { |
| 416 'duration': None, | 416 'duration': None, |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 446 # }, | 446 # }, |
| 447 'outputs_ref': None, | 447 'outputs_ref': None, |
| 448 'version': 5, | 448 'version': 5, |
| 449 } | 449 } |
| 450 | 450 |
| 451 if root_dir: | 451 if root_dir: |
| 452 file_path.ensure_tree(root_dir, 0700) | 452 file_path.ensure_tree(root_dir, 0700) |
| 453 elif isolate_cache.cache_dir: | 453 elif isolate_cache.cache_dir: |
| 454 root_dir = os.path.dirname(isolate_cache.cache_dir) | 454 root_dir = os.path.dirname(isolate_cache.cache_dir) |
| 455 # See comment for these constants. | 455 # See comment for these constants. |
| 456 run_dir = make_temp_dir(ISOLATED_RUN_DIR, root_dir) | 456 # If root_dir is not specified, it is not constant. |
|
nodir
2017/04/06 22:58:16
maybe return an error if constant_path is True, bu
M-A Ruel
2017/04/07 15:36:33
Not done yet because constant_run_path is hard cod
| |
| 457 if constant_path and root_dir: | |
| 458 run_dir = os.path.join(root_dir, ISOLATED_RUN_DIR) | |
| 459 os.mkdir(run_dir) | |
| 460 else: | |
| 461 run_dir = make_temp_dir(ISOLATED_RUN_DIR, root_dir) | |
| 457 # storage should be normally set but don't crash if it is not. This can happen | 462 # storage should be normally set but don't crash if it is not. This can happen |
| 458 # as Swarming task can run without an isolate server. | 463 # as Swarming task can run without an isolate server. |
| 459 out_dir = make_temp_dir(ISOLATED_OUT_DIR, root_dir) if storage else None | 464 out_dir = make_temp_dir(ISOLATED_OUT_DIR, root_dir) if storage else None |
| 460 tmp_dir = make_temp_dir(ISOLATED_TMP_DIR, root_dir) | 465 tmp_dir = make_temp_dir(ISOLATED_TMP_DIR, root_dir) |
| 461 cwd = run_dir | 466 cwd = run_dir |
| 462 | 467 |
| 463 try: | 468 try: |
| 464 with install_packages_fn(run_dir) as cipd_info: | 469 with install_packages_fn(run_dir) as cipd_info: |
| 465 if cipd_info: | 470 if cipd_info: |
| 466 result['stats']['cipd'] = cipd_info.stats | 471 result['stats']['cipd'] = cipd_info.stats |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 639 'internal_failure': 'Was terminated before completion', | 644 'internal_failure': 'Was terminated before completion', |
| 640 'outputs_ref': None, | 645 'outputs_ref': None, |
| 641 'version': 5, | 646 'version': 5, |
| 642 } | 647 } |
| 643 tools.write_json(result_json, result, dense=True) | 648 tools.write_json(result_json, result, dense=True) |
| 644 | 649 |
| 645 # run_isolated exit code. Depends on if result_json is used or not. | 650 # run_isolated exit code. Depends on if result_json is used or not. |
| 646 result = map_and_run( | 651 result = map_and_run( |
| 647 command, isolated_hash, storage, isolate_cache, outputs, | 652 command, isolated_hash, storage, isolate_cache, outputs, |
| 648 init_named_caches, leak_temp_dir, root_dir, hard_timeout, grace_period, | 653 init_named_caches, leak_temp_dir, root_dir, hard_timeout, grace_period, |
| 649 bot_file, extra_args, install_packages_fn, use_symlinks) | 654 bot_file, extra_args, install_packages_fn, use_symlinks, True) |
| 650 logging.info('Result:\n%s', tools.format_json(result, dense=True)) | 655 logging.info('Result:\n%s', tools.format_json(result, dense=True)) |
| 651 | 656 |
| 652 if result_json: | 657 if result_json: |
| 653 # We've found tests to delete 'work' when quitting, causing an exception | 658 # We've found tests to delete 'work' when quitting, causing an exception |
| 654 # here. Try to recreate the directory if necessary. | 659 # here. Try to recreate the directory if necessary. |
| 655 file_path.ensure_tree(os.path.dirname(result_json)) | 660 file_path.ensure_tree(os.path.dirname(result_json)) |
| 656 tools.write_json(result_json, result, dense=True) | 661 tools.write_json(result_json, result, dense=True) |
| 657 # Only return 1 if there was an internal error. | 662 # Only return 1 if there was an internal error. |
| 658 return int(bool(result['internal_failure'])) | 663 return int(bool(result['internal_failure'])) |
| 659 | 664 |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1053 return 1 | 1058 return 1 |
| 1054 | 1059 |
| 1055 | 1060 |
| 1056 if __name__ == '__main__': | 1061 if __name__ == '__main__': |
| 1057 subprocess42.inhibit_os_error_reporting() | 1062 subprocess42.inhibit_os_error_reporting() |
| 1058 # Ensure that we are always running with the correct encoding. | 1063 # Ensure that we are always running with the correct encoding. |
| 1059 fix_encoding.fix_encoding() | 1064 fix_encoding.fix_encoding() |
| 1060 file_path.enable_symlink() | 1065 file_path.enable_symlink() |
| 1061 | 1066 |
| 1062 sys.exit(main(sys.argv[1:])) | 1067 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |