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 |