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

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

Issue 1131623006: Use a response file for gn refs when running 'analyze' on gn bots. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix formatting nits Created 5 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
« no previous file with comments | « no previous file | tools/mb/mb_unittest.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 2015 The Chromium Authors. All rights reserved. 2 # Copyright 2015 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 """MB - the Meta-Build wrapper around GYP and GN 6 """MB - the Meta-Build wrapper around GYP and GN
7 7
8 MB is a wrapper script for GYP and GN that can be used to generate build files 8 MB is a wrapper script for GYP and GN that can be used to generate build files
9 for sets of canned configurations and analyze them. 9 for sets of canned configurations and analyze them.
10 """ 10 """
11 11
12 from __future__ import print_function 12 from __future__ import print_function
13 13
14 import argparse 14 import argparse
15 import ast 15 import ast
16 import json 16 import json
17 import os 17 import os
18 import pipes 18 import pipes
19 import shlex 19 import shlex
20 import shutil 20 import shutil
21 import sys 21 import sys
22 import subprocess 22 import subprocess
23 import tempfile
23 24
24 25
25 def main(args): 26 def main(args):
26 mbw = MetaBuildWrapper() 27 mbw = MetaBuildWrapper()
27 mbw.ParseArgs(args) 28 mbw.ParseArgs(args)
28 return mbw.args.func() 29 return mbw.args.func()
29 30
30 31
31 class MetaBuildWrapper(object): 32 class MetaBuildWrapper(object):
32 def __init__(self): 33 def __init__(self):
(...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 self.Print() 409 self.Print()
409 410
410 output_path = self.args.output_path[0] 411 output_path = self.args.output_path[0]
411 412
412 # Bail out early if a GN file was modified, since 'gn refs' won't know 413 # Bail out early if a GN file was modified, since 'gn refs' won't know
413 # what to do about it. 414 # what to do about it.
414 if any(f.endswith('.gn') or f.endswith('.gni') for f in inp['files']): 415 if any(f.endswith('.gn') or f.endswith('.gni') for f in inp['files']):
415 self.WriteJSON({'status': 'Found dependency (all)'}, output_path) 416 self.WriteJSON({'status': 'Found dependency (all)'}, output_path)
416 return 0 417 return 0
417 418
418 # TODO: Because of the --type=executable filter below, we don't detect 419 # Bail out early if 'all' was asked for, since 'gn refs' won't recognize it.
419 # when files will cause 'all' or 'gn_all' or similar targets to be 420 if 'all' in inp['targets']:
420 # dirty. We need to figure out how to handle that properly, but for
421 # now we can just bail out early.
422 if 'gn_all' in inp['targets'] or 'all' in inp['targets']:
423 self.WriteJSON({'status': 'Found dependency (all)'}, output_path) 421 self.WriteJSON({'status': 'Found dependency (all)'}, output_path)
424 return 0 422 return 0
425 423
426 all_needed_targets = set()
427 ret = 0 424 ret = 0
428 for f in inp['files']: 425 response_file = self.TempFile()
426 response_file.write('\n'.join(inp['files']) + '\n')
427 response_file.close()
428
429 matching_targets = []
430 try:
429 cmd = self.GNCmd('refs', self.args.path[0]) + [ 431 cmd = self.GNCmd('refs', self.args.path[0]) + [
430 '//' + f, '--type=executable', '--all', '--as=output'] 432 '@%s' % response_file.name,
433 '--type=executable', '--all', '--as=output'
434 ]
431 ret, out, _ = self.Run(cmd) 435 ret, out, _ = self.Run(cmd)
432 if ret and not 'The input matches no targets' in out: 436 if ret and not 'The input matches no targets' in out:
433 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), 437 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out),
434 output_path) 438 output_path)
439 build_dir = self.ToSrcRelPath(self.args.path[0]) + os.sep
440 for output in out.splitlines():
441 build_output = output.replace(build_dir, '')
442 if build_output in inp['targets']:
443 matching_targets.append(build_output)
444 finally:
445 self.RemoveFile(response_file.name)
435 446
436 rpath = self.ToSrcRelPath(self.args.path[0]) + os.sep 447 if matching_targets:
437 needed_targets = [t.replace(rpath, '') for t in out.splitlines()]
438 needed_targets = [nt for nt in needed_targets if nt in inp['targets']]
439 all_needed_targets.update(set(needed_targets))
440
441 if all_needed_targets:
442 # TODO: it could be that a target X might depend on a target Y 448 # TODO: it could be that a target X might depend on a target Y
443 # and both would be listed in the input, but we would only need 449 # and both would be listed in the input, but we would only need
444 # to specify target X as a build_target (whereas both X and Y are 450 # to specify target X as a build_target (whereas both X and Y are
445 # targets). I'm not sure if that optimization is generally worth it. 451 # targets). I'm not sure if that optimization is generally worth it.
446 self.WriteJSON({'targets': sorted(all_needed_targets), 452 self.WriteJSON({'targets': sorted(matching_targets),
447 'build_targets': sorted(all_needed_targets), 453 'build_targets': sorted(matching_targets),
448 'status': 'Found dependency'}, output_path) 454 'status': 'Found dependency'}, output_path)
449 else: 455 else:
450 self.WriteJSON({'targets': [], 456 self.WriteJSON({'targets': [],
451 'build_targets': [], 457 'build_targets': [],
452 'status': 'No dependency'}, output_path) 458 'status': 'No dependency'}, output_path)
453 459
454 if not ret and self.args.verbose: 460 if not ret and self.args.verbose:
455 outp = json.loads(self.ReadFile(output_path)) 461 outp = json.loads(self.ReadFile(output_path))
456 self.Print() 462 self.Print()
457 self.Print('analyze output:') 463 self.Print('analyze output:')
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
529 535
530 def Exists(self, path): 536 def Exists(self, path):
531 # This function largely exists so it can be overridden for testing. 537 # This function largely exists so it can be overridden for testing.
532 return os.path.exists(path) 538 return os.path.exists(path)
533 539
534 def ReadFile(self, path): 540 def ReadFile(self, path):
535 # This function largely exists so it can be overriden for testing. 541 # This function largely exists so it can be overriden for testing.
536 with open(path) as fp: 542 with open(path) as fp:
537 return fp.read() 543 return fp.read()
538 544
545 def RemoveFile(self, path):
546 # This function largely exists so it can be overriden for testing.
547 os.remove(path)
548
549 def TempFile(self, mode='w'):
550 # This function largely exists so it can be overriden for testing.
551 return tempfile.NamedTemporaryFile(mode=mode, delete=False)
552
539 def WriteFile(self, path, contents): 553 def WriteFile(self, path, contents):
540 # This function largely exists so it can be overriden for testing. 554 # This function largely exists so it can be overriden for testing.
541 with open(path, 'w') as fp: 555 with open(path, 'w') as fp:
542 return fp.write(contents) 556 return fp.write(contents)
543 557
558
544 class MBErr(Exception): 559 class MBErr(Exception):
545 pass 560 pass
546 561
547 562
548 if __name__ == '__main__': 563 if __name__ == '__main__':
549 try: 564 try:
550 sys.exit(main(sys.argv[1:])) 565 sys.exit(main(sys.argv[1:]))
551 except MBErr as e: 566 except MBErr as e:
552 print(e) 567 print(e)
553 sys.exit(1) 568 sys.exit(1)
554 except KeyboardInterrupt: 569 except KeyboardInterrupt:
555 print("interrupted, exiting", stream=sys.stderr) 570 print("interrupted, exiting", stream=sys.stderr)
556 sys.exit(130) 571 sys.exit(130)
OLDNEW
« no previous file with comments | « no previous file | tools/mb/mb_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698