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

Side by Side Diff: presubmit_support.py

Issue 269483002: Get presubmit_support to compute diffs against a given upstream. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/tools/depot_tools
Patch Set: Created 6 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 | Annotate | Revision Log
« no previous file with comments | « git_cl.py ('k') | tests/presubmit_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 (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 """Enables directory-specific presubmit checks to run at upload and/or commit. 6 """Enables directory-specific presubmit checks to run at upload and/or commit.
7 """ 7 """
8 8
9 __version__ = '1.8.0' 9 __version__ = '1.8.0'
10 10
(...skipping 482 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 msgs.extend(pool.map_async(CallCommand, tests).get(99999)) 493 msgs.extend(pool.map_async(CallCommand, tests).get(99999))
494 pool.close() 494 pool.close()
495 pool.join() 495 pool.join()
496 else: 496 else:
497 msgs.extend(map(CallCommand, tests)) 497 msgs.extend(map(CallCommand, tests))
498 return [m for m in msgs if m] 498 return [m for m in msgs if m]
499 499
500 500
501 class _DiffCache(object): 501 class _DiffCache(object):
502 """Caches diffs retrieved from a particular SCM.""" 502 """Caches diffs retrieved from a particular SCM."""
503 def __init__(self, upstream=None):
504 """Stores the upstream revision against which all diffs will be computed."""
505 self._upstream = upstream
503 506
504 def GetDiff(self, path, local_root): 507 def GetDiff(self, path, local_root):
505 """Get the diff for a particular path.""" 508 """Get the diff for a particular path."""
506 raise NotImplementedError() 509 raise NotImplementedError()
507 510
508 511
509 class _SvnDiffCache(_DiffCache): 512 class _SvnDiffCache(_DiffCache):
510 """DiffCache implementation for subversion.""" 513 """DiffCache implementation for subversion."""
511 def __init__(self): 514 def __init__(self, *args, **kwargs):
512 super(_SvnDiffCache, self).__init__() 515 super(_SvnDiffCache, self).__init__(*args, **kwargs)
513 self._diffs_by_file = {} 516 self._diffs_by_file = {}
514 517
515 def GetDiff(self, path, local_root): 518 def GetDiff(self, path, local_root):
516 if path not in self._diffs_by_file: 519 if path not in self._diffs_by_file:
517 self._diffs_by_file[path] = scm.SVN.GenerateDiff([path], local_root, 520 self._diffs_by_file[path] = scm.SVN.GenerateDiff([path], local_root,
518 False, None) 521 False, None)
519 return self._diffs_by_file[path] 522 return self._diffs_by_file[path]
520 523
521 524
522 class _GitDiffCache(_DiffCache): 525 class _GitDiffCache(_DiffCache):
523 """DiffCache implementation for git; gets all file diffs at once.""" 526 """DiffCache implementation for git; gets all file diffs at once."""
524 def __init__(self): 527 def __init__(self, upstream):
525 super(_GitDiffCache, self).__init__() 528 super(_GitDiffCache, self).__init__(upstream=upstream)
526 self._diffs_by_file = None 529 self._diffs_by_file = None
527 530
528 def GetDiff(self, path, local_root): 531 def GetDiff(self, path, local_root):
529 if not self._diffs_by_file: 532 if not self._diffs_by_file:
530 # Compute a single diff for all files and parse the output; should 533 # Compute a single diff for all files and parse the output; should
531 # with git this is much faster than computing one diff for each file. 534 # with git this is much faster than computing one diff for each file.
532 diffs = {} 535 diffs = {}
533 536
534 # Don't specify any filenames below, because there are command line length 537 # Don't specify any filenames below, because there are command line length
535 # limits on some platforms and GenerateDiff would fail. 538 # limits on some platforms and GenerateDiff would fail.
536 unified_diff = scm.GIT.GenerateDiff(local_root, files=[], full_move=True) 539 unified_diff = scm.GIT.GenerateDiff(local_root, files=[], full_move=True,
540 branch=self._upstream)
537 541
538 # This regex matches the path twice, separated by a space. Note that 542 # This regex matches the path twice, separated by a space. Note that
539 # filename itself may contain spaces. 543 # filename itself may contain spaces.
540 file_marker = re.compile('^diff --git (?P<filename>.*) (?P=filename)$') 544 file_marker = re.compile('^diff --git (?P<filename>.*) (?P=filename)$')
541 current_diff = [] 545 current_diff = []
542 keep_line_endings = True 546 keep_line_endings = True
543 for x in unified_diff.splitlines(keep_line_endings): 547 for x in unified_diff.splitlines(keep_line_endings):
544 match = file_marker.match(x) 548 match = file_marker.match(x)
545 if match: 549 if match:
546 # Marks the start of a new per-file section. 550 # Marks the start of a new per-file section.
(...skipping 13 matching lines...) Expand all
560 return self._diffs_by_file[path] 564 return self._diffs_by_file[path]
561 565
562 566
563 class AffectedFile(object): 567 class AffectedFile(object):
564 """Representation of a file in a change.""" 568 """Representation of a file in a change."""
565 569
566 DIFF_CACHE = _DiffCache 570 DIFF_CACHE = _DiffCache
567 571
568 # Method could be a function 572 # Method could be a function
569 # pylint: disable=R0201 573 # pylint: disable=R0201
570 def __init__(self, path, action, repository_root, diff_cache=None): 574 def __init__(self, path, action, repository_root, diff_cache):
571 self._path = path 575 self._path = path
572 self._action = action 576 self._action = action
573 self._local_root = repository_root 577 self._local_root = repository_root
574 self._is_directory = None 578 self._is_directory = None
575 self._properties = {} 579 self._properties = {}
576 self._cached_changed_contents = None 580 self._cached_changed_contents = None
577 self._cached_new_contents = None 581 self._cached_new_contents = None
578 if diff_cache: 582 self._diff_cache = diff_cache
579 self._diff_cache = diff_cache
580 else:
581 self._diff_cache = self.DIFF_CACHE()
582 logging.debug('%s(%s)' % (self.__class__.__name__, self._path)) 583 logging.debug('%s(%s)' % (self.__class__.__name__, self._path))
583 584
584 def ServerPath(self): 585 def ServerPath(self):
585 """Returns a path string that identifies the file in the SCM system. 586 """Returns a path string that identifies the file in the SCM system.
586 587
587 Returns the empty string if the file does not exist in SCM. 588 Returns the empty string if the file does not exist in SCM.
588 """ 589 """
589 return '' 590 return ''
590 591
591 def LocalPath(self): 592 def LocalPath(self):
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 """ 786 """
786 787
787 _AFFECTED_FILES = AffectedFile 788 _AFFECTED_FILES = AffectedFile
788 789
789 # Matches key/value (or "tag") lines in changelist descriptions. 790 # Matches key/value (or "tag") lines in changelist descriptions.
790 TAG_LINE_RE = re.compile( 791 TAG_LINE_RE = re.compile(
791 '^[ \t]*(?P<key>[A-Z][A-Z_0-9]*)[ \t]*=[ \t]*(?P<value>.*?)[ \t]*$') 792 '^[ \t]*(?P<key>[A-Z][A-Z_0-9]*)[ \t]*=[ \t]*(?P<value>.*?)[ \t]*$')
792 scm = '' 793 scm = ''
793 794
794 def __init__( 795 def __init__(
795 self, name, description, local_root, files, issue, patchset, author): 796 self, name, description, local_root, files, issue, patchset, author,
797 upstream=None):
796 if files is None: 798 if files is None:
797 files = [] 799 files = []
798 self._name = name 800 self._name = name
799 # Convert root into an absolute path. 801 # Convert root into an absolute path.
800 self._local_root = os.path.abspath(local_root) 802 self._local_root = os.path.abspath(local_root)
803 self._upstream = upstream
801 self.issue = issue 804 self.issue = issue
802 self.patchset = patchset 805 self.patchset = patchset
803 self.author_email = author 806 self.author_email = author
804 807
805 self._full_description = '' 808 self._full_description = ''
806 self.tags = {} 809 self.tags = {}
807 self._description_without_tags = '' 810 self._description_without_tags = ''
808 self.SetDescriptionText(description) 811 self.SetDescriptionText(description)
809 812
810 assert all( 813 assert all(
811 (isinstance(f, (list, tuple)) and len(f) == 2) for f in files), files 814 (isinstance(f, (list, tuple)) and len(f) == 2) for f in files), files
812 815
813 diff_cache = self._AFFECTED_FILES.DIFF_CACHE() 816 diff_cache = self._AFFECTED_FILES.DIFF_CACHE(self._upstream)
814 self._affected_files = [ 817 self._affected_files = [
815 self._AFFECTED_FILES(path, action.strip(), self._local_root, diff_cache) 818 self._AFFECTED_FILES(path, action.strip(), self._local_root, diff_cache)
816 for action, path in files 819 for action, path in files
817 ] 820 ]
818 821
819 def Name(self): 822 def Name(self):
820 """Returns the change name.""" 823 """Returns the change name."""
821 return self._name 824 return self._name
822 825
823 def DescriptionText(self): 826 def DescriptionText(self):
(...skipping 781 matching lines...) Expand 10 before | Expand all | Expand 10 after
1605 def default(self, obj): 1608 def default(self, obj):
1606 if isinstance(obj, set): 1609 if isinstance(obj, set):
1607 return sorted(obj) 1610 return sorted(obj)
1608 return json.JSONEncoder.default(self, obj) 1611 return json.JSONEncoder.default(self, obj)
1609 change = change_class(options.name, 1612 change = change_class(options.name,
1610 options.description, 1613 options.description,
1611 options.root, 1614 options.root,
1612 files, 1615 files,
1613 options.issue, 1616 options.issue,
1614 options.patchset, 1617 options.patchset,
1615 options.author) 1618 options.author,
1619 upstream=options.upstream)
1616 trybots = DoGetTrySlaves( 1620 trybots = DoGetTrySlaves(
1617 change, 1621 change,
1618 change.LocalPaths(), 1622 change.LocalPaths(),
1619 change.RepositoryRoot(), 1623 change.RepositoryRoot(),
1620 None, 1624 None,
1621 None, 1625 None,
1622 options.verbose, 1626 options.verbose,
1623 sys.stdout) 1627 sys.stdout)
1624 json.dump(trybots, f, cls=SetEncoder) 1628 json.dump(trybots, f, cls=SetEncoder)
1625 try: 1629 try:
1626 with canned_check_filter(options.skip_canned): 1630 with canned_check_filter(options.skip_canned):
1627 results = DoPresubmitChecks( 1631 results = DoPresubmitChecks(
1628 change_class(options.name, 1632 change_class(options.name,
1629 options.description, 1633 options.description,
1630 options.root, 1634 options.root,
1631 files, 1635 files,
1632 options.issue, 1636 options.issue,
1633 options.patchset, 1637 options.patchset,
1634 options.author), 1638 options.author,
1639 upstream=options.upstream),
1635 options.commit, 1640 options.commit,
1636 options.verbose, 1641 options.verbose,
1637 sys.stdout, 1642 sys.stdout,
1638 sys.stdin, 1643 sys.stdin,
1639 options.default_presubmit, 1644 options.default_presubmit,
1640 options.may_prompt, 1645 options.may_prompt,
1641 rietveld_obj) 1646 rietveld_obj)
1642 return not results.should_continue() 1647 return not results.should_continue()
1643 except NonexistantCannedCheckFilter, e: 1648 except NonexistantCannedCheckFilter, e:
1644 print >> sys.stderr, ( 1649 print >> sys.stderr, (
1645 'Attempted to skip nonexistent canned presubmit check: %s' % e.message) 1650 'Attempted to skip nonexistent canned presubmit check: %s' % e.message)
1646 return 2 1651 return 2
1647 except PresubmitFailure, e: 1652 except PresubmitFailure, e:
1648 print >> sys.stderr, e 1653 print >> sys.stderr, e
1649 print >> sys.stderr, 'Maybe your depot_tools is out of date?' 1654 print >> sys.stderr, 'Maybe your depot_tools is out of date?'
1650 print >> sys.stderr, 'If all fails, contact maruel@' 1655 print >> sys.stderr, 'If all fails, contact maruel@'
1651 return 2 1656 return 2
1652 1657
1653 1658
1654 if __name__ == '__main__': 1659 if __name__ == '__main__':
1655 fix_encoding.fix_encoding() 1660 fix_encoding.fix_encoding()
1656 sys.exit(Main(None)) 1661 sys.exit(Main(None))
OLDNEW
« no previous file with comments | « git_cl.py ('k') | tests/presubmit_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698