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

Side by Side Diff: client/isolate.py

Issue 2844063005: Add option to collapse symlinks in isolate.py (Closed)
Patch Set: Add -L 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
« no previous file with comments | « no previous file | client/isolated_format.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 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 """Front end tool to operate on .isolate files. 6 """Front end tool to operate on .isolate files.
7 7
8 This includes creating, merging or compiling them to generate a .isolated file. 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
(...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after
472 """Loads state from disk.""" 472 """Loads state from disk."""
473 assert os.path.isabs(isolated_filepath), isolated_filepath 473 assert os.path.isabs(isolated_filepath), isolated_filepath
474 isolated_basedir = os.path.dirname(isolated_filepath) 474 isolated_basedir = os.path.dirname(isolated_filepath)
475 return cls( 475 return cls(
476 isolated_filepath, 476 isolated_filepath,
477 SavedState.load_file( 477 SavedState.load_file(
478 isolatedfile_to_state(isolated_filepath), isolated_basedir)) 478 isolatedfile_to_state(isolated_filepath), isolated_basedir))
479 479
480 def load_isolate( 480 def load_isolate(
481 self, cwd, isolate_file, path_variables, config_variables, 481 self, cwd, isolate_file, path_variables, config_variables,
482 extra_variables, blacklist, ignore_broken_items): 482 extra_variables, blacklist, ignore_broken_items, collapse_symlinks):
483 """Updates self.isolated and self.saved_state with information loaded from a 483 """Updates self.isolated and self.saved_state with information loaded from a
484 .isolate file. 484 .isolate file.
485 485
486 Processes the loaded data, deduce root_dir, relative_cwd. 486 Processes the loaded data, deduce root_dir, relative_cwd.
487 """ 487 """
488 # Make sure to not depend on os.getcwd(). 488 # Make sure to not depend on os.getcwd().
489 assert os.path.isabs(isolate_file), isolate_file 489 assert os.path.isabs(isolate_file), isolate_file
490 isolate_file = file_path.get_native_path_case(isolate_file) 490 isolate_file = file_path.get_native_path_case(isolate_file)
491 logging.info( 491 logging.info(
492 'CompleteState.load_isolate(%s, %s, %s, %s, %s, %s)', 492 'CompleteState.load_isolate(%s, %s, %s, %s, %s, %s, %s)',
493 cwd, isolate_file, path_variables, config_variables, extra_variables, 493 cwd, isolate_file, path_variables, config_variables, extra_variables,
494 ignore_broken_items) 494 ignore_broken_items, collapse_symlinks)
495 495
496 # Config variables are not affected by the paths and must be used to 496 # Config variables are not affected by the paths and must be used to
497 # retrieve the paths, so update them first. 497 # retrieve the paths, so update them first.
498 self.saved_state.update_config(config_variables) 498 self.saved_state.update_config(config_variables)
499 499
500 with fs.open(isolate_file, 'r') as f: 500 with fs.open(isolate_file, 'r') as f:
501 # At that point, variables are not replaced yet in command and infiles. 501 # At that point, variables are not replaced yet in command and infiles.
502 # infiles may contain directory entries and is in posix style. 502 # infiles may contain directory entries and is in posix style.
503 command, infiles, read_only, isolate_cmd_dir = ( 503 command, infiles, read_only, isolate_cmd_dir = (
504 isolate_format.load_isolate_for_config( 504 isolate_format.load_isolate_for_config(
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 '%s; %s' 543 '%s; %s'
544 % (k, v, self.saved_state.root_dir, dest)) 544 % (k, v, self.saved_state.root_dir, dest))
545 # Normalize the files based to self.saved_state.root_dir. It is important to 545 # Normalize the files based to self.saved_state.root_dir. It is important to
546 # keep the trailing os.path.sep at that step. 546 # keep the trailing os.path.sep at that step.
547 infiles = [ 547 infiles = [
548 file_path.relpath( 548 file_path.relpath(
549 file_path.normpath(os.path.join(isolate_cmd_dir, f)), 549 file_path.normpath(os.path.join(isolate_cmd_dir, f)),
550 self.saved_state.root_dir) 550 self.saved_state.root_dir)
551 for f in infiles 551 for f in infiles
552 ] 552 ]
553 follow_symlinks = sys.platform != 'win32' 553 follow_symlinks = False
554 if not collapse_symlinks:
555 follow_symlinks = sys.platform != 'win32'
554 # Expand the directories by listing each file inside. Up to now, trailing 556 # Expand the directories by listing each file inside. Up to now, trailing
555 # os.path.sep must be kept. 557 # os.path.sep must be kept.
556 infiles = isolated_format.expand_directories_and_symlinks( 558 infiles = isolated_format.expand_directories_and_symlinks(
557 self.saved_state.root_dir, 559 self.saved_state.root_dir,
558 infiles, 560 infiles,
559 tools.gen_blacklist(blacklist), 561 tools.gen_blacklist(blacklist),
560 follow_symlinks, 562 follow_symlinks,
561 ignore_broken_items) 563 ignore_broken_items)
562 564
563 # Finally, update the new data to be able to generate the foo.isolated file, 565 # Finally, update the new data to be able to generate the foo.isolated file,
564 # the file that is used by run_isolated.py. 566 # the file that is used by run_isolated.py.
565 self.saved_state.update_isolated(command, infiles, read_only, relative_cwd) 567 self.saved_state.update_isolated(command, infiles, read_only, relative_cwd)
566 logging.debug(self) 568 logging.debug(self)
567 569
568 def files_to_metadata(self, subdir): 570 def files_to_metadata(self, subdir, collapse_symlinks):
569 """Updates self.saved_state.files with the files' mode and hash. 571 """Updates self.saved_state.files with the files' mode and hash.
570 572
571 If |subdir| is specified, filters to a subdirectory. The resulting .isolated 573 If |subdir| is specified, filters to a subdirectory. The resulting .isolated
572 file is tainted. 574 file is tainted.
573 575
574 See isolated_format.file_to_metadata() for more information. 576 See isolated_format.file_to_metadata() for more information.
575 """ 577 """
576 for infile in sorted(self.saved_state.files): 578 for infile in sorted(self.saved_state.files):
577 if subdir and not infile.startswith(subdir): 579 if subdir and not infile.startswith(subdir):
578 self.saved_state.files.pop(infile) 580 self.saved_state.files.pop(infile)
579 else: 581 else:
580 filepath = os.path.join(self.root_dir, infile) 582 filepath = os.path.join(self.root_dir, infile)
581 self.saved_state.files[infile] = isolated_format.file_to_metadata( 583 self.saved_state.files[infile] = isolated_format.file_to_metadata(
582 filepath, 584 filepath,
583 self.saved_state.files[infile], 585 self.saved_state.files[infile],
584 self.saved_state.read_only, 586 self.saved_state.read_only,
585 self.saved_state.algo) 587 self.saved_state.algo,
588 collapse_symlinks)
586 589
587 def save_files(self): 590 def save_files(self):
588 """Saves self.saved_state and creates a .isolated file.""" 591 """Saves self.saved_state and creates a .isolated file."""
589 logging.debug('Dumping to %s' % self.isolated_filepath) 592 logging.debug('Dumping to %s' % self.isolated_filepath)
590 self.saved_state.child_isolated_files = chromium_save_isolated( 593 self.saved_state.child_isolated_files = chromium_save_isolated(
591 self.isolated_filepath, 594 self.isolated_filepath,
592 self.saved_state.to_isolated(), 595 self.saved_state.to_isolated(),
593 self.saved_state.path_variables, 596 self.saved_state.path_variables,
594 self.saved_state.algo) 597 self.saved_state.algo)
595 total_bytes = sum( 598 total_bytes = sum(
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 complete_state.saved_state.isolate_file, 670 complete_state.saved_state.isolate_file,
668 isolatedfile_to_state(options.isolated)) 671 isolatedfile_to_state(options.isolated))
669 complete_state = CompleteState( 672 complete_state = CompleteState(
670 options.isolated, 673 options.isolated,
671 SavedState(complete_state.saved_state.isolated_basedir)) 674 SavedState(complete_state.saved_state.isolated_basedir))
672 675
673 if not skip_update: 676 if not skip_update:
674 # Then load the .isolate and expands directories. 677 # Then load the .isolate and expands directories.
675 complete_state.load_isolate( 678 complete_state.load_isolate(
676 cwd, isolate, options.path_variables, options.config_variables, 679 cwd, isolate, options.path_variables, options.config_variables,
677 options.extra_variables, options.blacklist, options.ignore_broken_items) 680 options.extra_variables, options.blacklist, options.ignore_broken_items,
681 options.collapse_symlinks)
678 682
679 # Regenerate complete_state.saved_state.files. 683 # Regenerate complete_state.saved_state.files.
680 if subdir: 684 if subdir:
681 subdir = unicode(subdir) 685 subdir = unicode(subdir)
682 # This is tricky here. If it is a path, take it from the root_dir. If 686 # This is tricky here. If it is a path, take it from the root_dir. If
683 # it is a variable, it must be keyed from the directory containing the 687 # it is a variable, it must be keyed from the directory containing the
684 # .isolate file. So translate all variables first. 688 # .isolate file. So translate all variables first.
685 translated_path_variables = dict( 689 translated_path_variables = dict(
686 (k, 690 (k,
687 os.path.normpath(os.path.join(complete_state.saved_state.relative_cwd, 691 os.path.normpath(os.path.join(complete_state.saved_state.relative_cwd,
688 v))) 692 v)))
689 for k, v in complete_state.saved_state.path_variables.iteritems()) 693 for k, v in complete_state.saved_state.path_variables.iteritems())
690 subdir = isolate_format.eval_variables(subdir, translated_path_variables) 694 subdir = isolate_format.eval_variables(subdir, translated_path_variables)
691 subdir = subdir.replace('/', os.path.sep) 695 subdir = subdir.replace('/', os.path.sep)
692 696
693 if not skip_update: 697 if not skip_update:
694 complete_state.files_to_metadata(subdir) 698 complete_state.files_to_metadata(subdir, options.collapse_symlinks)
695 return complete_state 699 return complete_state
696 700
697 701
698 def create_isolate_tree(outdir, root_dir, files, relative_cwd, read_only): 702 def create_isolate_tree(outdir, root_dir, files, relative_cwd, read_only):
699 """Creates a isolated tree usable for test execution. 703 """Creates a isolated tree usable for test execution.
700 704
701 Returns the current working directory where the isolated command should be 705 Returns the current working directory where the isolated command should be
702 started in. 706 started in.
703 """ 707 """
704 # Forcibly copy when the tree has to be read only. Otherwise the inode is 708 # Forcibly copy when the tree has to be read only. Otherwise the inode is
(...skipping 410 matching lines...) Expand 10 before | Expand all | Expand 10 after
1115 '-i', '--isolate', 1119 '-i', '--isolate',
1116 metavar='FILE', 1120 metavar='FILE',
1117 help='.isolate file to load the dependency data from') 1121 help='.isolate file to load the dependency data from')
1118 add_variable_option(group) 1122 add_variable_option(group)
1119 group.add_option( 1123 group.add_option(
1120 '--ignore_broken_items', action='store_true', 1124 '--ignore_broken_items', action='store_true',
1121 default=bool(os.environ.get('ISOLATE_IGNORE_BROKEN_ITEMS')), 1125 default=bool(os.environ.get('ISOLATE_IGNORE_BROKEN_ITEMS')),
1122 help='Indicates that invalid entries in the isolated file to be ' 1126 help='Indicates that invalid entries in the isolated file to be '
1123 'only be logged and not stop processing. Defaults to True if ' 1127 'only be logged and not stop processing. Defaults to True if '
1124 'env var ISOLATE_IGNORE_BROKEN_ITEMS is set') 1128 'env var ISOLATE_IGNORE_BROKEN_ITEMS is set')
1129 group.add_option(
1130 '-L', '--collapse_symlinks', action='store_true',
1131 help='Treat any symlinks as if they were the normal underlying file')
1125 parser.add_option_group(group) 1132 parser.add_option_group(group)
1126 1133
1127 1134
1128 def add_subdir_option(parser): 1135 def add_subdir_option(parser):
1129 parser.add_option( 1136 parser.add_option(
1130 '--subdir', 1137 '--subdir',
1131 help='Filters to a subdirectory. Its behavior changes depending if it ' 1138 help='Filters to a subdirectory. Its behavior changes depending if it '
1132 'is a relative path as a string or as a path variable. Path ' 1139 'is a relative path as a string or as a path variable. Path '
1133 'variables are always keyed from the directory containing the ' 1140 'variables are always keyed from the directory containing the '
1134 '.isolate file. Anything else is keyed on the root directory.') 1141 '.isolate file. Anything else is keyed on the root directory.')
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1217 print >> sys.stderr, 'Execution failure: %s' % e 1224 print >> sys.stderr, 'Execution failure: %s' % e
1218 return 1 1225 return 1
1219 1226
1220 1227
1221 if __name__ == '__main__': 1228 if __name__ == '__main__':
1222 subprocess42.inhibit_os_error_reporting() 1229 subprocess42.inhibit_os_error_reporting()
1223 fix_encoding.fix_encoding() 1230 fix_encoding.fix_encoding()
1224 tools.disable_buffering() 1231 tools.disable_buffering()
1225 colorama.init() 1232 colorama.init()
1226 sys.exit(main(sys.argv[1:])) 1233 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | client/isolated_format.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698