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

Side by Side Diff: tools/isolate/isolate.py

Issue 9834052: [strace] Add support for interrupted calls and proper chdir handling. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix test again Created 8 years, 8 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/isolate/isolate_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 """Does one of the following depending on the --mode argument: 6 """Does one of the following depending on the --mode argument:
7 check Verifies all the inputs exist, touches the file specified with 7 check Verifies all the inputs exist, touches the file specified with
8 --result and exits. 8 --result and exits.
9 hashtable Puts a manifest file and hard links each of the inputs into the 9 hashtable Puts a manifest file and hard links each of the inputs into the
10 output directory. 10 output directory.
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 cmd = args 67 cmd = args
68 args = [] 68 args = []
69 if files: 69 if files:
70 args = [ 70 args = [
71 i.decode('utf-8') for i in open(files, 'rb').read().splitlines() if i 71 i.decode('utf-8') for i in open(files, 'rb').read().splitlines() if i
72 ] + args 72 ] + args
73 cwd = os.getcwd() 73 cwd = os.getcwd()
74 return [relpath(os.path.join(cwd, arg), root) for arg in args], cmd 74 return [relpath(os.path.join(cwd, arg), root) for arg in args], cmd
75 75
76 76
77 def isolate(outdir, resultfile, indir, infiles, mode, read_only, cmd): 77 def isolate(outdir, resultfile, indir, infiles, mode, read_only, cmd, no_save):
78 """Main function to isolate a target with its dependencies. 78 """Main function to isolate a target with its dependencies.
79 79
80 Arguments: 80 Arguments:
81 - outdir: Output directory where the result is stored. Depends on |mode|. 81 - outdir: Output directory where the result is stored. Depends on |mode|.
82 - resultfile: File to save the json data. 82 - resultfile: File to save the json data.
83 - indir: Root directory to be used as the base directory for infiles. 83 - indir: Root directory to be used as the base directory for infiles.
84 - infiles: List of files, with relative path, to process. 84 - infiles: List of files, with relative path, to process.
85 - mode: Action to do. See file level docstring. 85 - mode: Action to do. See file level docstring.
86 - read_only: Makes the temporary directory read only. 86 - read_only: Makes the temporary directory read only.
87 - cmd: Command to execute. 87 - cmd: Command to execute.
88 - no_save: If True, do not touch resultfile.
88 89
89 Some arguments are optional, dependending on |mode|. See the corresponding 90 Some arguments are optional, dependending on |mode|. See the corresponding
90 MODE<mode> function for the exact behavior. 91 MODE<mode> function for the exact behavior.
91 """ 92 """
92 mode_fn = getattr(sys.modules[__name__], 'MODE' + mode) 93 mode_fn = getattr(sys.modules[__name__], 'MODE' + mode)
93 assert mode_fn 94 assert mode_fn
95 assert os.path.isabs(resultfile)
94 96
95 infiles = tree_creator.expand_directories( 97 infiles = tree_creator.expand_directories(
96 indir, infiles, lambda x: re.match(r'.*\.(svn|pyc)$', x)) 98 indir, infiles, lambda x: re.match(r'.*\.(svn|pyc)$', x))
97 99
98 # Note the relative current directory. 100 # Note the relative current directory.
99 # In general, this path will be the path containing the gyp file where the 101 # In general, this path will be the path containing the gyp file where the
100 # target was defined. This relative directory may be created implicitely if a 102 # target was defined. This relative directory may be created implicitely if a
101 # file from this directory is needed to run the test. Otherwise it won't be 103 # file from this directory is needed to run the test. Otherwise it won't be
102 # created and the process creation will fail. It's up to the caller to create 104 # created and the process creation will fail. It's up to the caller to create
103 # this directory manually before starting the test. 105 # this directory manually before starting the test.
104 cwd = os.getcwd() 106 cwd = os.getcwd()
105 relative_cwd = os.path.relpath(cwd, indir) 107 relative_cwd = os.path.relpath(cwd, indir)
106 108
107 # Workaround make behavior of passing absolute paths. 109 # Workaround make behavior of passing absolute paths.
108 cmd = [to_relative(i, indir, cwd) for i in cmd] 110 cmd = [to_relative(i, indir, cwd) for i in cmd]
109 111
110 if not cmd: 112 if not cmd:
111 # Note that it is exactly the reverse of relative_cwd. 113 # Note that it is exactly the reverse of relative_cwd.
112 cmd = [os.path.join(os.path.relpath(indir, cwd), infiles[0])] 114 cmd = [os.path.join(os.path.relpath(indir, cwd), infiles[0])]
113 if cmd[0].endswith('.py'): 115 if cmd[0].endswith('.py'):
114 cmd.insert(0, sys.executable) 116 cmd.insert(0, sys.executable)
115 117
116 # Only hashtable mode really needs the sha-1. 118 # Only hashtable mode really needs the sha-1.
117 dictfiles = tree_creator.process_inputs( 119 dictfiles = tree_creator.process_inputs(
118 indir, infiles, mode == 'hashtable', read_only) 120 indir, infiles, mode == 'hashtable', read_only)
119 121
120 result = mode_fn( 122 result = mode_fn(
121 outdir, indir, dictfiles, read_only, cmd, relative_cwd, resultfile) 123 outdir, indir, dictfiles, read_only, cmd, relative_cwd, resultfile)
122 124
123 if result == 0: 125 if result == 0 and not no_save:
124 # Saves the resulting file. 126 # Saves the resulting file.
125 out = { 127 out = {
126 'command': cmd, 128 'command': cmd,
127 'relative_cwd': relative_cwd, 129 'relative_cwd': relative_cwd,
128 'files': dictfiles, 130 'files': dictfiles,
131 'read_only': read_only,
129 } 132 }
130 with open(resultfile, 'wb') as f: 133 with open(resultfile, 'wb') as f:
131 json.dump(out, f, indent=2, sort_keys=True) 134 json.dump(out, f, indent=2, sort_keys=True)
132 return result 135 return result
133 136
134 137
135 def MODEcheck( 138 def MODEcheck(
136 _outdir, _indir, _dictfiles, _read_only, _cmd, _relative_cwd, _resultfile): 139 _outdir, _indir, _dictfiles, _read_only, _cmd, _relative_cwd, _resultfile):
137 """No-op.""" 140 """No-op."""
138 return 0 141 return 0
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 tree_creator.rmtree(outdir) 192 tree_creator.rmtree(outdir)
190 193
191 194
192 def MODEtrace( 195 def MODEtrace(
193 _outdir, indir, _dictfiles, _read_only, cmd, relative_cwd, resultfile): 196 _outdir, indir, _dictfiles, _read_only, cmd, relative_cwd, resultfile):
194 """Shortcut to use trace_inputs.py properly. 197 """Shortcut to use trace_inputs.py properly.
195 198
196 It constructs the equivalent of dictfiles. It is hardcoded to base the 199 It constructs the equivalent of dictfiles. It is hardcoded to base the
197 checkout at src/. 200 checkout at src/.
198 """ 201 """
199 gyppath = os.path.relpath(relative_cwd, indir) 202 logging.info('Running %s, cwd=%s' % (cmd, os.path.join(indir, relative_cwd)))
200 cwd = os.path.join(indir, relative_cwd)
201 logging.info('Running %s, cwd=%s' % (cmd, cwd))
202 return trace_inputs.trace_inputs( 203 return trace_inputs.trace_inputs(
203 '%s.log' % resultfile, 204 '%s.log' % resultfile,
204 cmd, 205 cmd,
205 cwd,
206 gyppath,
207 indir, 206 indir,
208 True) 207 relative_cwd,
208 os.path.dirname(resultfile), # Guesswork here.
209 False)
209 210
210 211
211 def get_valid_modes(): 212 def get_valid_modes():
212 """Returns the modes that can be used.""" 213 """Returns the modes that can be used."""
213 return sorted( 214 return sorted(
214 i[4:] for i in dir(sys.modules[__name__]) if i.startswith('MODE')) 215 i[4:] for i in dir(sys.modules[__name__]) if i.startswith('MODE'))
215 216
216 217
217 def main(): 218 def main():
218 valid_modes = get_valid_modes() 219 valid_modes = get_valid_modes()
219 parser = optparse.OptionParser( 220 parser = optparse.OptionParser(
220 usage='%prog [options] [inputs] -- [command line]', 221 usage='%prog [options] [inputs] -- [command line]',
221 description=sys.modules[__name__].__doc__) 222 description=sys.modules[__name__].__doc__)
222 parser.allow_interspersed_args = False 223 parser.allow_interspersed_args = False
223 parser.format_description = lambda *_: parser.description 224 parser.format_description = lambda *_: parser.description
224 parser.add_option( 225 parser.add_option(
225 '-v', '--verbose', action='count', default=0, help='Use multiple times') 226 '-v', '--verbose', action='count', default=0, help='Use multiple times')
226 parser.add_option( 227 parser.add_option(
227 '--mode', choices=valid_modes, 228 '--mode', choices=valid_modes,
228 help='Determines the action to be taken: %s' % ', '.join(valid_modes)) 229 help='Determines the action to be taken: %s' % ', '.join(valid_modes))
229 parser.add_option( 230 parser.add_option(
230 '--result', metavar='FILE', 231 '--result', metavar='FILE',
231 help='Output file containing the json information about inputs') 232 help='File containing the json information about inputs')
232 parser.add_option( 233 parser.add_option(
233 '--root', metavar='DIR', help='Base directory to fetch files, required') 234 '--root', metavar='DIR', help='Base directory to fetch files, required')
234 parser.add_option( 235 parser.add_option(
235 '--outdir', metavar='DIR', 236 '--outdir', metavar='DIR',
236 help='Directory used to recreate the tree or store the hash table. ' 237 help='Directory used to recreate the tree or store the hash table. '
237 'For run and remap, uses a /tmp subdirectory. For the other modes, ' 238 'For run and remap, uses a /tmp subdirectory. For the other modes, '
238 'defaults to the directory containing --result') 239 'defaults to the directory containing --result')
239 parser.add_option( 240 parser.add_option(
240 '--read-only', action='store_true', 241 '--read-only', action='store_true', default=False,
241 help='Make the temporary tree read-only') 242 help='Make the temporary tree read-only')
242 parser.add_option( 243 parser.add_option(
244 '--from-results', action='store_true',
245 help='Loads everything from the result file instead of generating it')
246 parser.add_option(
243 '--files', metavar='FILE', 247 '--files', metavar='FILE',
244 help='File to be read containing input files') 248 help='File to be read containing input files')
245 249
246 options, args = parser.parse_args() 250 options, args = parser.parse_args()
247 level = [logging.ERROR, logging.INFO, logging.DEBUG][min(2, options.verbose)] 251 level = [logging.ERROR, logging.INFO, logging.DEBUG][min(2, options.verbose)]
248 logging.basicConfig( 252 logging.basicConfig(
249 level=level, 253 level=level,
250 format='%(levelname)5s %(module)15s(%(lineno)3d): %(message)s') 254 format='%(levelname)5s %(module)15s(%(lineno)3d): %(message)s')
251 255
252 if not options.root: 256 if not options.mode:
253 parser.error('--root is required.') 257 parser.error('--mode is required')
258
254 if not options.result: 259 if not options.result:
255 parser.error('--result is required.') 260 parser.error('--result is required.')
261 if options.from_results:
262 if not options.root:
263 options.root = os.getcwd()
264 if args:
265 parser.error('Arguments cannot be used with --from-result')
266 if options.files:
267 parser.error('--files cannot be used with --from-result')
268 else:
269 if not options.root:
270 parser.error('--root is required.')
271
272 options.result = os.path.abspath(options.result)
256 273
257 # Normalize the root input directory. 274 # Normalize the root input directory.
258 indir = os.path.normpath(options.root) 275 indir = os.path.normpath(options.root)
259 if not os.path.isdir(indir): 276 if not os.path.isdir(indir):
260 parser.error('%s is not a directory' % indir) 277 parser.error('%s is not a directory' % indir)
261 278
262 # Do not call abspath until it was verified the directory exists. 279 # Do not call abspath until it was verified the directory exists.
263 indir = os.path.abspath(indir) 280 indir = os.path.abspath(indir)
264 281
265 logging.info('sys.argv: %s' % sys.argv) 282 logging.info('sys.argv: %s' % sys.argv)
266 logging.info('cwd: %s' % os.getcwd()) 283 logging.info('cwd: %s' % os.getcwd())
267 logging.info('Args: %s' % args) 284 logging.info('Args: %s' % args)
268 infiles, cmd = separate_inputs_command(args, indir, options.files) 285 if not options.from_results:
269 if not infiles: 286 infiles, cmd = separate_inputs_command(args, indir, options.files)
270 parser.error('Need at least one input file to map') 287 if not infiles:
288 parser.error('Need at least one input file to map')
289 else:
290 data = json.load(open(options.result))
291 cmd = data['command']
292 infiles = data['files'].keys()
293 os.chdir(data['relative_cwd'])
294
271 logging.info('infiles: %s' % infiles) 295 logging.info('infiles: %s' % infiles)
272 296
273 try: 297 try:
274 return isolate( 298 return isolate(
275 options.outdir, 299 options.outdir,
276 os.path.abspath(options.result), 300 options.result,
277 indir, 301 indir,
278 infiles, 302 infiles,
279 options.mode, 303 options.mode,
280 options.read_only, 304 options.read_only,
281 cmd) 305 cmd,
306 options.from_results)
282 except tree_creator.MappingError, e: 307 except tree_creator.MappingError, e:
283 print >> sys.stderr, str(e) 308 print >> sys.stderr, str(e)
284 return 1 309 return 1
285 310
286 311
287 if __name__ == '__main__': 312 if __name__ == '__main__':
288 sys.exit(main()) 313 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | tools/isolate/isolate_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698