| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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 """Front end tool to manage .isolate files and corresponding tests. | 6 """Front end tool to operate on .isolate files. |
| 7 | 7 |
| 8 Run ./isolate.py --help for more detailed information. | 8 This includes creating, merging or compiling them to generate a .isolated file. |
| 9 | 9 |
| 10 See more information at | 10 See more information at |
| 11 https://code.google.com/p/swarming/wiki/IsolateDesign | 11 https://code.google.com/p/swarming/wiki/IsolateDesign |
| 12 https://code.google.com/p/swarming/wiki/IsolateUserGuide | 12 https://code.google.com/p/swarming/wiki/IsolateUserGuide |
| 13 """ | 13 """ |
| 14 # Run ./isolate.py --help for more detailed information. |
| 14 | 15 |
| 15 import ast | 16 import ast |
| 16 import copy | 17 import copy |
| 17 import hashlib | 18 import hashlib |
| 18 import itertools | 19 import itertools |
| 19 import logging | 20 import logging |
| 20 import optparse | 21 import optparse |
| 21 import os | 22 import os |
| 22 import posixpath | 23 import posixpath |
| 23 import re | 24 import re |
| 24 import stat | 25 import stat |
| 25 import subprocess | 26 import subprocess |
| 26 import sys | 27 import sys |
| 27 | 28 |
| 28 import isolateserver_archive | 29 import isolateserver_archive |
| 29 import run_isolated | 30 import run_isolated |
| 30 import short_expression_finder | 31 import short_expression_finder |
| 31 import trace_inputs | 32 import trace_inputs |
| 32 | 33 |
| 33 # Import here directly so isolate is easier to use as a library. | 34 # Import here directly so isolate is easier to use as a library. |
| 34 from run_isolated import get_flavor | 35 from run_isolated import get_flavor |
| 35 | 36 |
| 37 from third_party import colorama |
| 38 from third_party.depot_tools import fix_encoding |
| 39 from third_party.depot_tools import subcommand |
| 40 |
| 36 | 41 |
| 37 PATH_VARIABLES = ('DEPTH', 'PRODUCT_DIR') | 42 PATH_VARIABLES = ('DEPTH', 'PRODUCT_DIR') |
| 38 | 43 |
| 39 # Files that should be 0-length when mapped. | 44 # Files that should be 0-length when mapped. |
| 40 KEY_TOUCHED = 'isolate_dependency_touched' | 45 KEY_TOUCHED = 'isolate_dependency_touched' |
| 41 # Files that should be tracked by the build tool. | 46 # Files that should be tracked by the build tool. |
| 42 KEY_TRACKED = 'isolate_dependency_tracked' | 47 KEY_TRACKED = 'isolate_dependency_tracked' |
| 43 # Files that should not be tracked by the build tool. | 48 # Files that should not be tracked by the build tool. |
| 44 KEY_UNTRACKED = 'isolate_dependency_untracked' | 49 KEY_UNTRACKED = 'isolate_dependency_untracked' |
| 45 | 50 |
| (...skipping 1859 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1905 with open(complete_state.saved_state.isolate_filepath, 'wb') as f: | 1910 with open(complete_state.saved_state.isolate_filepath, 'wb') as f: |
| 1906 print_all(config.file_comment, data, f) | 1911 print_all(config.file_comment, data, f) |
| 1907 if exceptions: | 1912 if exceptions: |
| 1908 # It got an exception, raise the first one. | 1913 # It got an exception, raise the first one. |
| 1909 raise \ | 1914 raise \ |
| 1910 exceptions[0][0], \ | 1915 exceptions[0][0], \ |
| 1911 exceptions[0][1], \ | 1916 exceptions[0][1], \ |
| 1912 exceptions[0][2] | 1917 exceptions[0][2] |
| 1913 | 1918 |
| 1914 | 1919 |
| 1915 def CMDcheck(args): | 1920 def CMDcheck(parser, args): |
| 1916 """Checks that all the inputs are present and generates .isolated.""" | 1921 """Checks that all the inputs are present and generates .isolated.""" |
| 1917 parser = OptionParserIsolate(command='check') | |
| 1918 parser.add_option('--subdir', help='Filters to a subdirectory') | 1922 parser.add_option('--subdir', help='Filters to a subdirectory') |
| 1919 options, args = parser.parse_args(args) | 1923 options, args = parser.parse_args(args) |
| 1920 if args: | 1924 if args: |
| 1921 parser.error('Unsupported argument: %s' % args) | 1925 parser.error('Unsupported argument: %s' % args) |
| 1922 complete_state = load_complete_state( | 1926 complete_state = load_complete_state( |
| 1923 options, os.getcwd(), options.subdir, False) | 1927 options, os.getcwd(), options.subdir, False) |
| 1924 | 1928 |
| 1925 # Nothing is done specifically. Just store the result and state. | 1929 # Nothing is done specifically. Just store the result and state. |
| 1926 complete_state.save_files() | 1930 complete_state.save_files() |
| 1927 return 0 | 1931 return 0 |
| 1928 | 1932 |
| 1929 | 1933 |
| 1930 def CMDhashtable(args): | 1934 def CMDhashtable(parser, args): |
| 1931 """Creates a hash table content addressed object store. | 1935 """Creates a hash table content addressed object store. |
| 1932 | 1936 |
| 1933 All the files listed in the .isolated file are put in the output directory | 1937 All the files listed in the .isolated file are put in the output directory |
| 1934 with the file name being the sha-1 of the file's content. | 1938 with the file name being the sha-1 of the file's content. |
| 1935 """ | 1939 """ |
| 1936 parser = OptionParserIsolate(command='hashtable') | |
| 1937 parser.add_option('--subdir', help='Filters to a subdirectory') | 1940 parser.add_option('--subdir', help='Filters to a subdirectory') |
| 1938 options, args = parser.parse_args(args) | 1941 options, args = parser.parse_args(args) |
| 1939 if args: | 1942 if args: |
| 1940 parser.error('Unsupported argument: %s' % args) | 1943 parser.error('Unsupported argument: %s' % args) |
| 1941 | 1944 |
| 1942 with run_isolated.Profiler('GenerateHashtable'): | 1945 with run_isolated.Profiler('GenerateHashtable'): |
| 1943 success = False | 1946 success = False |
| 1944 try: | 1947 try: |
| 1945 complete_state = load_complete_state( | 1948 complete_state = load_complete_state( |
| 1946 options, os.getcwd(), options.subdir, False) | 1949 options, os.getcwd(), options.subdir, False) |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1992 success = True | 1995 success = True |
| 1993 print('%s %s' % (isolated_hash[0], os.path.basename(options.isolated))) | 1996 print('%s %s' % (isolated_hash[0], os.path.basename(options.isolated))) |
| 1994 finally: | 1997 finally: |
| 1995 # If the command failed, delete the .isolated file if it exists. This is | 1998 # If the command failed, delete the .isolated file if it exists. This is |
| 1996 # important so no stale swarm job is executed. | 1999 # important so no stale swarm job is executed. |
| 1997 if not success and os.path.isfile(options.isolated): | 2000 if not success and os.path.isfile(options.isolated): |
| 1998 os.remove(options.isolated) | 2001 os.remove(options.isolated) |
| 1999 return not success | 2002 return not success |
| 2000 | 2003 |
| 2001 | 2004 |
| 2002 def CMDmerge(args): | 2005 def CMDmerge(parser, args): |
| 2003 """Reads and merges the data from the trace back into the original .isolate. | 2006 """Reads and merges the data from the trace back into the original .isolate. |
| 2004 | 2007 |
| 2005 Ignores --outdir. | 2008 Ignores --outdir. |
| 2006 """ | 2009 """ |
| 2007 parser = OptionParserIsolate(command='merge', require_isolated=False) | 2010 parser.require_isolated = False |
| 2008 add_trace_option(parser) | 2011 add_trace_option(parser) |
| 2009 options, args = parser.parse_args(args) | 2012 options, args = parser.parse_args(args) |
| 2010 if args: | 2013 if args: |
| 2011 parser.error('Unsupported argument: %s' % args) | 2014 parser.error('Unsupported argument: %s' % args) |
| 2012 complete_state = load_complete_state(options, os.getcwd(), None, False) | 2015 complete_state = load_complete_state(options, os.getcwd(), None, False) |
| 2013 blacklist = trace_inputs.gen_blacklist(options.trace_blacklist) | 2016 blacklist = trace_inputs.gen_blacklist(options.trace_blacklist) |
| 2014 merge(complete_state, blacklist) | 2017 merge(complete_state, blacklist) |
| 2015 return 0 | 2018 return 0 |
| 2016 | 2019 |
| 2017 | 2020 |
| 2018 def CMDread(args): | 2021 def CMDread(parser, args): |
| 2019 """Reads the trace file generated with command 'trace'. | 2022 """Reads the trace file generated with command 'trace'. |
| 2020 | 2023 |
| 2021 Ignores --outdir. | 2024 Ignores --outdir. |
| 2022 """ | 2025 """ |
| 2023 parser = OptionParserIsolate(command='read', require_isolated=False) | 2026 parser.require_isolated = False |
| 2024 add_trace_option(parser) | 2027 add_trace_option(parser) |
| 2025 parser.add_option( | 2028 parser.add_option( |
| 2026 '--skip-refresh', action='store_true', | 2029 '--skip-refresh', action='store_true', |
| 2027 help='Skip reading .isolate file and do not refresh the sha1 of ' | 2030 help='Skip reading .isolate file and do not refresh the sha1 of ' |
| 2028 'dependencies') | 2031 'dependencies') |
| 2029 options, args = parser.parse_args(args) | 2032 options, args = parser.parse_args(args) |
| 2030 if args: | 2033 if args: |
| 2031 parser.error('Unsupported argument: %s' % args) | 2034 parser.error('Unsupported argument: %s' % args) |
| 2032 complete_state = load_complete_state( | 2035 complete_state = load_complete_state( |
| 2033 options, os.getcwd(), None, options.skip_refresh) | 2036 options, os.getcwd(), None, options.skip_refresh) |
| 2034 blacklist = trace_inputs.gen_blacklist(options.trace_blacklist) | 2037 blacklist = trace_inputs.gen_blacklist(options.trace_blacklist) |
| 2035 value, exceptions = read_trace_as_isolate_dict(complete_state, blacklist) | 2038 value, exceptions = read_trace_as_isolate_dict(complete_state, blacklist) |
| 2036 pretty_print(value, sys.stdout) | 2039 pretty_print(value, sys.stdout) |
| 2037 if exceptions: | 2040 if exceptions: |
| 2038 # It got an exception, raise the first one. | 2041 # It got an exception, raise the first one. |
| 2039 raise \ | 2042 raise \ |
| 2040 exceptions[0][0], \ | 2043 exceptions[0][0], \ |
| 2041 exceptions[0][1], \ | 2044 exceptions[0][1], \ |
| 2042 exceptions[0][2] | 2045 exceptions[0][2] |
| 2043 return 0 | 2046 return 0 |
| 2044 | 2047 |
| 2045 | 2048 |
| 2046 def CMDremap(args): | 2049 def CMDremap(parser, args): |
| 2047 """Creates a directory with all the dependencies mapped into it. | 2050 """Creates a directory with all the dependencies mapped into it. |
| 2048 | 2051 |
| 2049 Useful to test manually why a test is failing. The target executable is not | 2052 Useful to test manually why a test is failing. The target executable is not |
| 2050 run. | 2053 run. |
| 2051 """ | 2054 """ |
| 2052 parser = OptionParserIsolate(command='remap', require_isolated=False) | 2055 parser.require_isolated = False |
| 2053 options, args = parser.parse_args(args) | 2056 options, args = parser.parse_args(args) |
| 2054 if args: | 2057 if args: |
| 2055 parser.error('Unsupported argument: %s' % args) | 2058 parser.error('Unsupported argument: %s' % args) |
| 2056 complete_state = load_complete_state(options, os.getcwd(), None, False) | 2059 complete_state = load_complete_state(options, os.getcwd(), None, False) |
| 2057 | 2060 |
| 2058 if not options.outdir: | 2061 if not options.outdir: |
| 2059 options.outdir = run_isolated.make_temp_dir( | 2062 options.outdir = run_isolated.make_temp_dir( |
| 2060 'isolate', complete_state.root_dir) | 2063 'isolate', complete_state.root_dir) |
| 2061 else: | 2064 else: |
| 2062 if is_url(options.outdir): | 2065 if is_url(options.outdir): |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2073 action=run_isolated.HARDLINK_WITH_FALLBACK, | 2076 action=run_isolated.HARDLINK_WITH_FALLBACK, |
| 2074 as_sha1=False) | 2077 as_sha1=False) |
| 2075 if complete_state.saved_state.read_only: | 2078 if complete_state.saved_state.read_only: |
| 2076 run_isolated.make_writable(options.outdir, True) | 2079 run_isolated.make_writable(options.outdir, True) |
| 2077 | 2080 |
| 2078 if complete_state.isolated_filepath: | 2081 if complete_state.isolated_filepath: |
| 2079 complete_state.save_files() | 2082 complete_state.save_files() |
| 2080 return 0 | 2083 return 0 |
| 2081 | 2084 |
| 2082 | 2085 |
| 2083 def CMDrewrite(args): | 2086 def CMDrewrite(parser, args): |
| 2084 """Rewrites a .isolate file into the canonical format.""" | 2087 """Rewrites a .isolate file into the canonical format.""" |
| 2085 parser = OptionParserIsolate(command='rewrite', require_isolated=False) | 2088 parser.require_isolated = False |
| 2086 options, args = parser.parse_args(args) | 2089 options, args = parser.parse_args(args) |
| 2087 if args: | 2090 if args: |
| 2088 parser.error('Unsupported argument: %s' % args) | 2091 parser.error('Unsupported argument: %s' % args) |
| 2089 | 2092 |
| 2090 if options.isolated: | 2093 if options.isolated: |
| 2091 # Load the previous state if it was present. Namely, "foo.isolated.state". | 2094 # Load the previous state if it was present. Namely, "foo.isolated.state". |
| 2092 complete_state = CompleteState.load_files(options.isolated) | 2095 complete_state = CompleteState.load_files(options.isolated) |
| 2093 isolate = options.isolate or complete_state.saved_state.isolate_filepath | 2096 isolate = options.isolate or complete_state.saved_state.isolate_filepath |
| 2094 else: | 2097 else: |
| 2095 isolate = options.isolate | 2098 isolate = options.isolate |
| 2096 if not isolate: | 2099 if not isolate: |
| 2097 raise ExecutionError('A .isolate file is required.') | 2100 raise ExecutionError('A .isolate file is required.') |
| 2098 with open(isolate, 'r') as f: | 2101 with open(isolate, 'r') as f: |
| 2099 content = f.read() | 2102 content = f.read() |
| 2100 config = load_isolate_as_config( | 2103 config = load_isolate_as_config( |
| 2101 os.path.dirname(os.path.abspath(isolate)), | 2104 os.path.dirname(os.path.abspath(isolate)), |
| 2102 eval_content(content), | 2105 eval_content(content), |
| 2103 extract_comment(content)) | 2106 extract_comment(content)) |
| 2104 data = config.make_isolate_file() | 2107 data = config.make_isolate_file() |
| 2105 print('Updating %s' % isolate) | 2108 print('Updating %s' % isolate) |
| 2106 with open(isolate, 'wb') as f: | 2109 with open(isolate, 'wb') as f: |
| 2107 print_all(config.file_comment, data, f) | 2110 print_all(config.file_comment, data, f) |
| 2108 return 0 | 2111 return 0 |
| 2109 | 2112 |
| 2110 | 2113 |
| 2111 def CMDrun(args): | 2114 def CMDrun(parser, args): |
| 2112 """Runs the test executable in an isolated (temporary) directory. | 2115 """Runs the test executable in an isolated (temporary) directory. |
| 2113 | 2116 |
| 2114 All the dependencies are mapped into the temporary directory and the | 2117 All the dependencies are mapped into the temporary directory and the |
| 2115 directory is cleaned up after the target exits. Warning: if --outdir is | 2118 directory is cleaned up after the target exits. Warning: if --outdir is |
| 2116 specified, it is deleted upon exit. | 2119 specified, it is deleted upon exit. |
| 2117 | 2120 |
| 2118 Argument processing stops at the first non-recognized argument and these | 2121 Argument processing stops at the first non-recognized argument and these |
| 2119 arguments are appended to the command line of the target to run. For example, | 2122 arguments are appended to the command line of the target to run. For example, |
| 2120 use: isolate.py --isolated foo.isolated -- --gtest_filter=Foo.Bar | 2123 use: isolate.py --isolated foo.isolated -- --gtest_filter=Foo.Bar |
| 2121 """ | 2124 """ |
| 2122 parser = OptionParserIsolate(command='run', require_isolated=False) | 2125 parser.require_isolated = False |
| 2123 parser.add_option( | 2126 parser.add_option( |
| 2124 '--skip-refresh', action='store_true', | 2127 '--skip-refresh', action='store_true', |
| 2125 help='Skip reading .isolate file and do not refresh the sha1 of ' | 2128 help='Skip reading .isolate file and do not refresh the sha1 of ' |
| 2126 'dependencies') | 2129 'dependencies') |
| 2127 parser.enable_interspersed_args() | 2130 parser.enable_interspersed_args() |
| 2128 options, args = parser.parse_args(args) | 2131 options, args = parser.parse_args(args) |
| 2129 complete_state = load_complete_state( | 2132 complete_state = load_complete_state( |
| 2130 options, os.getcwd(), None, options.skip_refresh) | 2133 options, os.getcwd(), None, options.skip_refresh) |
| 2131 cmd = complete_state.saved_state.command + args | 2134 cmd = complete_state.saved_state.command + args |
| 2132 if not cmd: | 2135 if not cmd: |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2163 result = subprocess.call(cmd, cwd=cwd) | 2166 result = subprocess.call(cmd, cwd=cwd) |
| 2164 finally: | 2167 finally: |
| 2165 if options.outdir: | 2168 if options.outdir: |
| 2166 run_isolated.rmtree(options.outdir) | 2169 run_isolated.rmtree(options.outdir) |
| 2167 | 2170 |
| 2168 if complete_state.isolated_filepath: | 2171 if complete_state.isolated_filepath: |
| 2169 complete_state.save_files() | 2172 complete_state.save_files() |
| 2170 return result | 2173 return result |
| 2171 | 2174 |
| 2172 | 2175 |
| 2173 def CMDtrace(args): | 2176 def CMDtrace(parser, args): |
| 2174 """Traces the target using trace_inputs.py. | 2177 """Traces the target using trace_inputs.py. |
| 2175 | 2178 |
| 2176 It runs the executable without remapping it, and traces all the files it and | 2179 It runs the executable without remapping it, and traces all the files it and |
| 2177 its child processes access. Then the 'merge' command can be used to generate | 2180 its child processes access. Then the 'merge' command can be used to generate |
| 2178 an updated .isolate file out of it or the 'read' command to print it out to | 2181 an updated .isolate file out of it or the 'read' command to print it out to |
| 2179 stdout. | 2182 stdout. |
| 2180 | 2183 |
| 2181 Argument processing stops at the first non-recognized argument and these | 2184 Argument processing stops at the first non-recognized argument and these |
| 2182 arguments are appended to the command line of the target to run. For example, | 2185 arguments are appended to the command line of the target to run. For example, |
| 2183 use: isolate.py --isolated foo.isolated -- --gtest_filter=Foo.Bar | 2186 use: isolate.py --isolated foo.isolated -- --gtest_filter=Foo.Bar |
| 2184 """ | 2187 """ |
| 2185 parser = OptionParserIsolate(command='trace') | |
| 2186 add_trace_option(parser) | 2188 add_trace_option(parser) |
| 2187 parser.enable_interspersed_args() | 2189 parser.enable_interspersed_args() |
| 2188 parser.add_option( | 2190 parser.add_option( |
| 2189 '-m', '--merge', action='store_true', | 2191 '-m', '--merge', action='store_true', |
| 2190 help='After tracing, merge the results back in the .isolate file') | 2192 help='After tracing, merge the results back in the .isolate file') |
| 2191 parser.add_option( | 2193 parser.add_option( |
| 2192 '--skip-refresh', action='store_true', | 2194 '--skip-refresh', action='store_true', |
| 2193 help='Skip reading .isolate file and do not refresh the sha1 of ' | 2195 help='Skip reading .isolate file and do not refresh the sha1 of ' |
| 2194 'dependencies') | 2196 'dependencies') |
| 2195 options, args = parser.parse_args(args) | 2197 options, args = parser.parse_args(args) |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2306 # but it wouldn't be backward compatible. | 2308 # but it wouldn't be backward compatible. |
| 2307 def try_make_int(s): | 2309 def try_make_int(s): |
| 2308 """Converts a value to int if possible, converts to unicode otherwise.""" | 2310 """Converts a value to int if possible, converts to unicode otherwise.""" |
| 2309 try: | 2311 try: |
| 2310 return int(s) | 2312 return int(s) |
| 2311 except ValueError: | 2313 except ValueError: |
| 2312 return s.decode('utf-8') | 2314 return s.decode('utf-8') |
| 2313 options.variables = dict((k, try_make_int(v)) for k, v in options.variables) | 2315 options.variables = dict((k, try_make_int(v)) for k, v in options.variables) |
| 2314 | 2316 |
| 2315 | 2317 |
| 2316 class OptionParserIsolate(trace_inputs.OptionParserWithNiceDescription): | 2318 class OptionParserIsolate(trace_inputs.OptionParserWithLogging): |
| 2317 """Adds automatic --isolate, --isolated, --out and --variable handling.""" | 2319 """Adds automatic --isolate, --isolated, --out and --variable handling.""" |
| 2318 def __init__(self, require_isolated=True, **kwargs): | 2320 # Set it to False if it is not required, e.g. it can be passed on but do not |
| 2319 trace_inputs.OptionParserWithNiceDescription.__init__( | 2321 # fail if not given. |
| 2322 require_isolated = True |
| 2323 |
| 2324 def __init__(self, **kwargs): |
| 2325 trace_inputs.OptionParserWithLogging.__init__( |
| 2320 self, | 2326 self, |
| 2321 verbose=int(os.environ.get('ISOLATE_DEBUG', 0)), | 2327 verbose=int(os.environ.get('ISOLATE_DEBUG', 0)), |
| 2322 **kwargs) | 2328 **kwargs) |
| 2323 group = optparse.OptionGroup(self, "Common options") | 2329 group = optparse.OptionGroup(self, "Common options") |
| 2324 group.add_option( | 2330 group.add_option( |
| 2325 '-i', '--isolate', | 2331 '-i', '--isolate', |
| 2326 metavar='FILE', | 2332 metavar='FILE', |
| 2327 help='.isolate file to load the dependency data from') | 2333 help='.isolate file to load the dependency data from') |
| 2328 add_variable_option(group) | 2334 add_variable_option(group) |
| 2329 group.add_option( | 2335 group.add_option( |
| 2330 '-o', '--outdir', metavar='DIR', | 2336 '-o', '--outdir', metavar='DIR', |
| 2331 help='Directory used to recreate the tree or store the hash table. ' | 2337 help='Directory used to recreate the tree or store the hash table. ' |
| 2332 'Defaults: run|remap: a /tmp subdirectory, others: ' | 2338 'Defaults: run|remap: a /tmp subdirectory, others: ' |
| 2333 'defaults to the directory containing --isolated') | 2339 'defaults to the directory containing --isolated') |
| 2334 group.add_option( | 2340 group.add_option( |
| 2335 '--ignore_broken_items', action='store_true', | 2341 '--ignore_broken_items', action='store_true', |
| 2336 default=bool(os.environ.get('ISOLATE_IGNORE_BROKEN_ITEMS')), | 2342 default=bool(os.environ.get('ISOLATE_IGNORE_BROKEN_ITEMS')), |
| 2337 help='Indicates that invalid entries in the isolated file to be ' | 2343 help='Indicates that invalid entries in the isolated file to be ' |
| 2338 'only be logged and not stop processing. Defaults to True if ' | 2344 'only be logged and not stop processing. Defaults to True if ' |
| 2339 'env var ISOLATE_IGNORE_BROKEN_ITEMS is set') | 2345 'env var ISOLATE_IGNORE_BROKEN_ITEMS is set') |
| 2340 self.add_option_group(group) | 2346 self.add_option_group(group) |
| 2341 self.require_isolated = require_isolated | |
| 2342 | 2347 |
| 2343 def parse_args(self, *args, **kwargs): | 2348 def parse_args(self, *args, **kwargs): |
| 2344 """Makes sure the paths make sense. | 2349 """Makes sure the paths make sense. |
| 2345 | 2350 |
| 2346 On Windows, / and \ are often mixed together in a path. | 2351 On Windows, / and \ are often mixed together in a path. |
| 2347 """ | 2352 """ |
| 2348 options, args = trace_inputs.OptionParserWithNiceDescription.parse_args( | 2353 options, args = trace_inputs.OptionParserWithLogging.parse_args( |
| 2349 self, *args, **kwargs) | 2354 self, *args, **kwargs) |
| 2350 if not self.allow_interspersed_args and args: | 2355 if not self.allow_interspersed_args and args: |
| 2351 self.error('Unsupported argument: %s' % args) | 2356 self.error('Unsupported argument: %s' % args) |
| 2352 | 2357 |
| 2353 cwd = trace_inputs.get_native_path_case(unicode(os.getcwd())) | 2358 cwd = trace_inputs.get_native_path_case(unicode(os.getcwd())) |
| 2354 parse_isolated_option(self, options, cwd, self.require_isolated) | 2359 parse_isolated_option(self, options, cwd, self.require_isolated) |
| 2355 parse_variable_option(options) | 2360 parse_variable_option(options) |
| 2356 | 2361 |
| 2357 if options.isolate: | 2362 if options.isolate: |
| 2358 # TODO(maruel): Work with non-ASCII. | 2363 # TODO(maruel): Work with non-ASCII. |
| 2359 # The path must be in native path case for tracing purposes. | 2364 # The path must be in native path case for tracing purposes. |
| 2360 options.isolate = unicode(options.isolate).replace('/', os.path.sep) | 2365 options.isolate = unicode(options.isolate).replace('/', os.path.sep) |
| 2361 options.isolate = os.path.normpath(os.path.join(cwd, options.isolate)) | 2366 options.isolate = os.path.normpath(os.path.join(cwd, options.isolate)) |
| 2362 options.isolate = trace_inputs.get_native_path_case(options.isolate) | 2367 options.isolate = trace_inputs.get_native_path_case(options.isolate) |
| 2363 | 2368 |
| 2364 if options.outdir and not is_url(options.outdir): | 2369 if options.outdir and not is_url(options.outdir): |
| 2365 options.outdir = unicode(options.outdir).replace('/', os.path.sep) | 2370 options.outdir = unicode(options.outdir).replace('/', os.path.sep) |
| 2366 # outdir doesn't need native path case since tracing is never done from | 2371 # outdir doesn't need native path case since tracing is never done from |
| 2367 # there. | 2372 # there. |
| 2368 options.outdir = os.path.normpath(os.path.join(cwd, options.outdir)) | 2373 options.outdir = os.path.normpath(os.path.join(cwd, options.outdir)) |
| 2369 | 2374 |
| 2370 return options, args | 2375 return options, args |
| 2371 | 2376 |
| 2372 | 2377 |
| 2373 ### Glue code to make all the commands works magically. | |
| 2374 | |
| 2375 | |
| 2376 CMDhelp = trace_inputs.CMDhelp | |
| 2377 | |
| 2378 | |
| 2379 def main(argv): | 2378 def main(argv): |
| 2379 dispatcher = subcommand.CommandDispatcher(__name__) |
| 2380 try: | 2380 try: |
| 2381 return trace_inputs.main_impl(argv) | 2381 return dispatcher.execute(OptionParserIsolate(), argv) |
| 2382 except ( | 2382 except ( |
| 2383 ExecutionError, | 2383 ExecutionError, |
| 2384 run_isolated.MappingError, | 2384 run_isolated.MappingError, |
| 2385 run_isolated.ConfigError) as e: | 2385 run_isolated.ConfigError) as e: |
| 2386 sys.stderr.write('\nError: ') | 2386 sys.stderr.write('\nError: ') |
| 2387 sys.stderr.write(str(e)) | 2387 sys.stderr.write(str(e)) |
| 2388 sys.stderr.write('\n') | 2388 sys.stderr.write('\n') |
| 2389 return 1 | 2389 return 1 |
| 2390 | 2390 |
| 2391 | 2391 |
| 2392 if __name__ == '__main__': | 2392 if __name__ == '__main__': |
| 2393 fix_encoding.fix_encoding() |
| 2394 trace_inputs.disable_buffering() |
| 2395 colorama.init() |
| 2393 sys.exit(main(sys.argv[1:])) | 2396 sys.exit(main(sys.argv[1:])) |
| OLD | NEW |