Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(193)

Side by Side Diff: client/run_isolated.py

Issue 2847153002: Cache/retrieve extracted CIPD packages in local isolate cache (Closed)
Patch Set: Fix unicode glitch and make assertions less terrible to find Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 RUN_ISOLATED_LOG_FILE = 'run_isolated.log' 86 RUN_ISOLATED_LOG_FILE = 'run_isolated.log'
87 87
88 88
89 # The name of the log to use for the run_test_cases.py command 89 # The name of the log to use for the run_test_cases.py command
90 RUN_TEST_CASES_LOG = 'run_test_cases.log' 90 RUN_TEST_CASES_LOG = 'run_test_cases.log'
91 91
92 92
93 # Use short names for temporary directories. This is driven by Windows, which 93 # Use short names for temporary directories. This is driven by Windows, which
94 # imposes a relatively short maximum path length of 260 characters, often 94 # imposes a relatively short maximum path length of 260 characters, often
95 # referred to as MAX_PATH. It is relatively easy to create files with longer 95 # referred to as MAX_PATH. It is relatively easy to create files with longer
96 # path length. A use case is with recursive depedency treesV like npm packages. 96 # path length. A use case is with recursive dependency trees like npm packages.
97 # 97 #
98 # It is recommended to start the script with a `root_dir` as short as 98 # It is recommended to start the script with a `root_dir` as short as
99 # possible. 99 # possible.
100 # - ir stands for isolated_run 100 # - ir stands for isolated_run
101 # - io stands for isolated_out 101 # - io stands for isolated_out
102 # - it stands for isolated_tmp 102 # - it stands for isolated_tmp
103 ISOLATED_RUN_DIR = u'ir' 103 ISOLATED_RUN_DIR = u'ir'
104 ISOLATED_OUT_DIR = u'io' 104 ISOLATED_OUT_DIR = u'io'
105 ISOLATED_TMP_DIR = u'it' 105 ISOLATED_TMP_DIR = u'it'
106 106
107 107
108 def get_as_zip_package(executable=True): 108 def get_as_zip_package(executable=True):
109 """Returns ZipPackage with this module and all its dependencies. 109 """Returns ZipPackage with this module and all its dependencies.
110 110
111 If |executable| is True will store run_isolated.py as __main__.py so that 111 If |executable| is True will store run_isolated.py as __main__.py so that
112 zip package is directly executable be python. 112 zip package is directly executable be python.
113 """ 113 """
114 # Building a zip package when running from another zip package is 114 # Building a zip package when running from another zip package is
115 # unsupported and probably unneeded. 115 # unsupported and probably unneeded.
116 assert not zip_package.is_zipped_module(sys.modules[__name__]) 116 assert not zip_package.is_zipped_module(sys.modules[__name__])
117 assert THIS_FILE_PATH 117 assert THIS_FILE_PATH
118 assert BASE_DIR 118 assert BASE_DIR
119 package = zip_package.ZipPackage(root=BASE_DIR) 119 package = zip_package.ZipPackage(root=BASE_DIR)
120 package.add_python_file(THIS_FILE_PATH, '__main__.py' if executable else None) 120 package.add_python_file(THIS_FILE_PATH, '__main__.py' if executable else None)
121 package.add_python_file(os.path.join(BASE_DIR, 'isolate_storage.py')) 121 package.add_python_file(os.path.join(BASE_DIR, 'isolate_storage.py'))
122 package.add_python_file(os.path.join(BASE_DIR, 'isolated_format.py')) 122 package.add_python_file(os.path.join(BASE_DIR, 'isolated_format.py'))
123 package.add_python_file(os.path.join(BASE_DIR, 'isolateserver.py')) 123 package.add_python_file(os.path.join(BASE_DIR, 'isolateserver.py'))
124 package.add_python_file(os.path.join(BASE_DIR, 'isolate.py'))
125 package.add_python_file(os.path.join(BASE_DIR, 'isolate_format.py'))
124 package.add_python_file(os.path.join(BASE_DIR, 'auth.py')) 126 package.add_python_file(os.path.join(BASE_DIR, 'auth.py'))
125 package.add_python_file(os.path.join(BASE_DIR, 'cipd.py')) 127 package.add_python_file(os.path.join(BASE_DIR, 'cipd.py'))
126 package.add_python_file(os.path.join(BASE_DIR, 'named_cache.py')) 128 package.add_python_file(os.path.join(BASE_DIR, 'named_cache.py'))
129 package.add_python_file(os.path.join(BASE_DIR, 'run_isolated.py'))
127 package.add_directory(os.path.join(BASE_DIR, 'libs')) 130 package.add_directory(os.path.join(BASE_DIR, 'libs'))
128 package.add_directory(os.path.join(BASE_DIR, 'third_party')) 131 package.add_directory(os.path.join(BASE_DIR, 'third_party'))
129 package.add_directory(os.path.join(BASE_DIR, 'utils')) 132 package.add_directory(os.path.join(BASE_DIR, 'utils'))
130 return package 133 return package
131 134
132 135
133 def make_temp_dir(prefix, root_dir): 136 def make_temp_dir(prefix, root_dir):
134 """Returns a new unique temporary directory.""" 137 """Returns a new unique temporary directory."""
135 return unicode(tempfile.mkdtemp(prefix=prefix, dir=root_dir)) 138 return unicode(tempfile.mkdtemp(prefix=prefix, dir=root_dir))
136 139
(...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after
679 'pins', # dict with installed cipd pins to return to the server 682 'pins', # dict with installed cipd pins to return to the server
680 ]) 683 ])
681 684
682 685
683 @contextlib.contextmanager 686 @contextlib.contextmanager
684 def noop_install_packages(_run_dir): 687 def noop_install_packages(_run_dir):
685 """Placeholder for 'install_client_and_packages' if cipd is disabled.""" 688 """Placeholder for 'install_client_and_packages' if cipd is disabled."""
686 yield None 689 yield None
687 690
688 691
689 def _install_packages(run_dir, cipd_cache_dir, client, packages, timeout): 692 def _install_packages(run_dir, cipd_cache_dir, client, packages, timeout,
693 isolate_cache=None):
690 """Calls 'cipd ensure' for packages. 694 """Calls 'cipd ensure' for packages.
691 695
692 Args: 696 Args:
693 run_dir (str): root of installation. 697 run_dir (str): root of installation.
694 cipd_cache_dir (str): the directory to use for the cipd package cache. 698 cipd_cache_dir (str): the directory to use for the cipd package cache.
695 client (CipdClient): the cipd client to use 699 client (CipdClient): the cipd client to use
696 packages: packages to install, list [(path, package_name, version), ...]. 700 packages: packages to install, list [(path, package_name, version), ...].
697 timeout: max duration in seconds that this function can take. 701 timeout: max duration in seconds that this function can take.
698 702
699 Returns: list of pinned packages. Looks like [ 703 Returns: list of pinned packages. Looks like [
(...skipping 22 matching lines...) Expand all
722 by_path[path].append((name, version, i)) 726 by_path[path].append((name, version, i))
723 727
724 pins = client.ensure( 728 pins = client.ensure(
725 run_dir, 729 run_dir,
726 { 730 {
727 subdir: [(name, vers) for name, vers, _ in pkgs] 731 subdir: [(name, vers) for name, vers, _ in pkgs]
728 for subdir, pkgs in by_path.iteritems() 732 for subdir, pkgs in by_path.iteritems()
729 }, 733 },
730 cache_dir=cipd_cache_dir, 734 cache_dir=cipd_cache_dir,
731 timeout=timeout, 735 timeout=timeout,
736 isolate_cache=isolate_cache,
732 ) 737 )
733 738
734 for subdir, pin_list in sorted(pins.iteritems()): 739 for subdir, pin_list in sorted(pins.iteritems()):
735 this_subdir = by_path[subdir] 740 this_subdir = by_path[subdir]
736 for i, (name, version) in enumerate(pin_list): 741 for i, (name, version) in enumerate(pin_list):
737 insert_pin(subdir, name, version, this_subdir[i][2]) 742 insert_pin(subdir, name, version, this_subdir[i][2])
738 743
739 assert None not in package_pins 744 assert None not in package_pins
740 745
741 return package_pins 746 return package_pins
742 747
743 748
744 @contextlib.contextmanager 749 @contextlib.contextmanager
745 def install_client_and_packages( 750 def install_client_and_packages(
746 run_dir, packages, service_url, client_package_name, 751 run_dir, packages, service_url, client_package_name,
747 client_version, cache_dir, timeout=None): 752 client_version, cache_dir, timeout=None, isolate_cache=None):
748 """Bootstraps CIPD client and installs CIPD packages. 753 """Bootstraps CIPD client and installs CIPD packages.
749 754
750 Yields CipdClient, stats, client info and pins (as single CipdInfo object). 755 Yields CipdClient, stats, client info and pins (as single CipdInfo object).
751 756
752 Pins and the CIPD client info are in the form of: 757 Pins and the CIPD client info are in the form of:
753 [ 758 [
754 { 759 {
755 "path": path, "package_name": package_name, "version": version, 760 "path": path, "package_name": package_name, "version": version,
756 }, 761 },
757 ... 762 ...
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
792 client_manager = cipd.get_client( 797 client_manager = cipd.get_client(
793 service_url, client_package_name, client_version, cache_dir, 798 service_url, client_package_name, client_version, cache_dir,
794 timeout=timeoutfn()) 799 timeout=timeoutfn())
795 800
796 with client_manager as client: 801 with client_manager as client:
797 get_client_duration = time.time() - get_client_start 802 get_client_duration = time.time() - get_client_start
798 803
799 package_pins = [] 804 package_pins = []
800 if packages: 805 if packages:
801 package_pins = _install_packages( 806 package_pins = _install_packages(
802 run_dir, cipd_cache_dir, client, packages, timeoutfn()) 807 run_dir, cipd_cache_dir, client, packages, timeoutfn(), isolate_cache)
803 808
804 file_path.make_tree_files_read_only(run_dir) 809 file_path.make_tree_files_read_only(run_dir)
805 810
806 total_duration = time.time() - start 811 total_duration = time.time() - start
807 logging.info( 812 logging.info(
808 'Installing CIPD client and packages took %d seconds', total_duration) 813 'Installing CIPD client and packages took %d seconds', total_duration)
809 814
810 yield CipdInfo( 815 yield CipdInfo(
811 client=client, 816 client=client,
812 cache_dir=cipd_cache_dir, 817 cache_dir=cipd_cache_dir,
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
989 if options.json: 994 if options.json:
990 options.json = unicode(os.path.abspath(options.json)) 995 options.json = unicode(os.path.abspath(options.json))
991 996
992 cipd.validate_cipd_options(parser, options) 997 cipd.validate_cipd_options(parser, options)
993 998
994 install_packages_fn = noop_install_packages 999 install_packages_fn = noop_install_packages
995 if options.cipd_enabled: 1000 if options.cipd_enabled:
996 install_packages_fn = lambda run_dir: install_client_and_packages( 1001 install_packages_fn = lambda run_dir: install_client_and_packages(
997 run_dir, cipd.parse_package_args(options.cipd_packages), 1002 run_dir, cipd.parse_package_args(options.cipd_packages),
998 options.cipd_server, options.cipd_client_package, 1003 options.cipd_server, options.cipd_client_package,
999 options.cipd_client_version, cache_dir=options.cipd_cache) 1004 options.cipd_client_version, cache_dir=options.cipd_cache,
1005 isolate_cache=isolate_cache)
1000 1006
1001 @contextlib.contextmanager 1007 @contextlib.contextmanager
1002 def init_named_caches(run_dir): 1008 def init_named_caches(run_dir):
1003 # WARNING: this function depends on "options" variable defined in the outer 1009 # WARNING: this function depends on "options" variable defined in the outer
1004 # function. 1010 # function.
1005 with named_cache_manager.open(): 1011 with named_cache_manager.open():
1006 named_cache_manager.create_symlinks(run_dir, options.named_caches) 1012 named_cache_manager.create_symlinks(run_dir, options.named_caches)
1007 try: 1013 try:
1008 yield 1014 yield
1009 finally: 1015 finally:
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1051 return 1 1057 return 1
1052 1058
1053 1059
1054 if __name__ == '__main__': 1060 if __name__ == '__main__':
1055 subprocess42.inhibit_os_error_reporting() 1061 subprocess42.inhibit_os_error_reporting()
1056 # Ensure that we are always running with the correct encoding. 1062 # Ensure that we are always running with the correct encoding.
1057 fix_encoding.fix_encoding() 1063 fix_encoding.fix_encoding()
1058 file_path.enable_symlink() 1064 file_path.enable_symlink()
1059 1065
1060 sys.exit(main(sys.argv[1:])) 1066 sys.exit(main(sys.argv[1:]))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698