| Index: extensions/browser/PRESUBMIT.py
|
| diff --git a/extensions/browser/PRESUBMIT.py b/extensions/browser/PRESUBMIT.py
|
| index 29a709b5c807ff63d08b90bba2efb5c61c888067..659c1761e264a12132b2d104f4ef0e357afe9872 100644
|
| --- a/extensions/browser/PRESUBMIT.py
|
| +++ b/extensions/browser/PRESUBMIT.py
|
| @@ -8,6 +8,8 @@ See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
|
| for more details on the presubmit API built into gcl.
|
| """
|
|
|
| +import sys
|
| +
|
| def GetPreferredTryMasters(project, change):
|
| return {
|
| 'tryserver.chromium': {
|
| @@ -15,294 +17,26 @@ def GetPreferredTryMasters(project, change):
|
| }
|
| }
|
|
|
| -class HistogramValueChecker(object):
|
| - """Verify that changes to "extension_function_histogram_value.h" are valid.
|
| -
|
| - See comments at the top of the "extension_function_histogram_value.h" file
|
| - for what are considered valid changes. There are situations where this script
|
| - gives false positive warnings, i.e. it warns even though the edit is
|
| - legitimate. Since the script warns using prompt warnings, the user can always
|
| - choose to continue. The main point is to attract the attention to all
|
| - (potentially or not) invalid edits.
|
| -
|
| - """
|
| -
|
| - # The name of the file we want to check against
|
| - LOCAL_PATH = "extensions/browser/extension_function_histogram_value.h"
|
| -
|
| - # The markers we look for in the above source file as delimiters of the enum
|
| - # definition.
|
| - ENUM_START_MARKER = "enum HistogramValue {"
|
| - ENUM_END_MARKER = " // Last entry:"
|
| -
|
| - def __init__(self, input_api, output_api):
|
| - self.input_api = input_api
|
| - self.output_api = output_api
|
| - self.results = []
|
| -
|
| - class EnumRange(object):
|
| - """Represents a range of line numbers (1-based)"""
|
| - def __init__(self, first_line, last_line):
|
| - self.first_line = first_line
|
| - self.last_line = last_line
|
| -
|
| - def Count(self):
|
| - return self.last_line - self.first_line + 1
|
| -
|
| - def Contains(self, line_num):
|
| - return self.first_line <= line_num and line_num <= self.last_line
|
| -
|
| - def LogInfo(self, message):
|
| - self.input_api.logging.info(message)
|
| - return
|
| -
|
| - def LogDebug(self, message):
|
| - self.input_api.logging.debug(message)
|
| - return
|
| -
|
| - def ComputeEnumRangeInContents(self, contents):
|
| - """Returns an |EnumRange| object representing the line extent of the
|
| - HistogramValue enum members in |contents|. The line numbers are 1-based,
|
| - compatible with line numbers returned by AffectedFile.ChangeContents().
|
| - |contents| is a list of strings reprenting the lines of a text file.
|
| -
|
| - If either ENUM_START_MARKER or ENUM_END_MARKER cannot be found in
|
| - |contents|, returns None and emits detailed warnings about the problem.
|
| -
|
| - """
|
| - first_enum_line = 0
|
| - last_enum_line = 0
|
| - line_num = 1 # Line numbers are 1-based
|
| - for line in contents:
|
| - if line.startswith(self.ENUM_START_MARKER):
|
| - first_enum_line = line_num + 1
|
| - elif line.startswith(self.ENUM_END_MARKER):
|
| - last_enum_line = line_num
|
| - line_num += 1
|
| -
|
| - if first_enum_line == 0:
|
| - self.EmitWarning("The presubmit script could not find the start of the "
|
| - "enum definition (\"%s\"). Did the enum definition "
|
| - "change?" % self.ENUM_START_MARKER)
|
| - return None
|
| -
|
| - if last_enum_line == 0:
|
| - self.EmitWarning("The presubmit script could not find the end of the "
|
| - "enum definition (\"%s\"). Did the enum definition "
|
| - "change?" % self.ENUM_END_MARKER)
|
| - return None
|
| -
|
| - if first_enum_line >= last_enum_line:
|
| - self.EmitWarning("The presubmit script located the start of the enum "
|
| - "definition (\"%s\" at line %d) *after* its end "
|
| - "(\"%s\" at line %d). Something is not quite right."
|
| - % (self.ENUM_START_MARKER, first_enum_line,
|
| - self.ENUM_END_MARKER, last_enum_line))
|
| - return None
|
| -
|
| - self.LogInfo("Line extent of |HistogramValue| enum definition: "
|
| - "first_line=%d, last_line=%d."
|
| - % (first_enum_line, last_enum_line))
|
| - return self.EnumRange(first_enum_line, last_enum_line)
|
| -
|
| - def ComputeEnumRangeInNewFile(self, affected_file):
|
| - return self.ComputeEnumRangeInContents(affected_file.NewContents())
|
| -
|
| - def GetLongMessage(self):
|
| - return str("The file \"%s\" contains the definition of the "
|
| - "|HistogramValue| enum which should be edited in specific ways "
|
| - "only - *** read the comments at the top of the header file ***"
|
| - ". There are changes to the file that may be incorrect and "
|
| - "warrant manual confirmation after review. Note that this "
|
| - "presubmit script can not reliably report the nature of all "
|
| - "types of invalid changes, especially when the diffs are "
|
| - "complex. For example, an invalid deletion may be reported "
|
| - "whereas the change contains a valid rename."
|
| - % self.LOCAL_PATH)
|
| -
|
| - def EmitWarning(self, message, line_number=None, line_text=None):
|
| - """Emits a presubmit prompt warning containing the short message
|
| - |message|. |item| is |LOCAL_PATH| with optional |line_number| and
|
| - |line_text|.
|
| -
|
| - """
|
| - if line_number is not None and line_text is not None:
|
| - item = "%s(%d): %s" % (self.LOCAL_PATH, line_number, line_text)
|
| - elif line_number is not None:
|
| - item = "%s(%d)" % (self.LOCAL_PATH, line_number)
|
| - else:
|
| - item = self.LOCAL_PATH
|
| - long_message = self.GetLongMessage()
|
| - self.LogInfo(message)
|
| - self.results.append(
|
| - self.output_api.PresubmitPromptWarning(message, [item], long_message))
|
| -
|
| - def CollectRangesInsideEnumDefinition(self, affected_file,
|
| - first_line, last_line):
|
| - """Returns a list of triplet (line_start, line_end, line_text) of ranges of
|
| - edits changes. The |line_text| part is the text at line |line_start|.
|
| - Since it used only for reporting purposes, we do not need all the text
|
| - lines in the range.
|
| -
|
| - """
|
| - results = []
|
| - previous_line_number = 0
|
| - previous_range_start_line_number = 0
|
| - previous_range_start_text = ""
|
| -
|
| - def addRange():
|
| - tuple = (previous_range_start_line_number,
|
| - previous_line_number,
|
| - previous_range_start_text)
|
| - results.append(tuple)
|
| -
|
| - for line_number, line_text in affected_file.ChangedContents():
|
| - if first_line <= line_number and line_number <= last_line:
|
| - self.LogDebug("Line change at line number " + str(line_number) + ": " +
|
| - line_text)
|
| - # Start a new interval if none started
|
| - if previous_range_start_line_number == 0:
|
| - previous_range_start_line_number = line_number
|
| - previous_range_start_text = line_text
|
| - # Add new interval if we reached past the previous one
|
| - elif line_number != previous_line_number + 1:
|
| - addRange()
|
| - previous_range_start_line_number = line_number
|
| - previous_range_start_text = line_text
|
| - previous_line_number = line_number
|
| -
|
| - # Add a last interval if needed
|
| - if previous_range_start_line_number != 0:
|
| - addRange()
|
| - return results
|
| -
|
| - def CheckForFileDeletion(self, affected_file):
|
| - """Emits a warning notification if file has been deleted """
|
| - if not affected_file.NewContents():
|
| - self.EmitWarning("The file seems to be deleted in the changelist. If "
|
| - "your intent is to really delete the file, the code in "
|
| - "PRESUBMIT.py should be updated to remove the "
|
| - "|HistogramValueChecker| class.");
|
| - return False
|
| - return True
|
| -
|
| - def GetDeletedLinesFromScmDiff(self, affected_file):
|
| - """Return a list of of line numbers (1-based) corresponding to lines
|
| - deleted from the new source file (if they had been present in it). Note
|
| - that if multiple contiguous lines have been deleted, the returned list will
|
| - contain contiguous line number entries. To prevent false positives, we
|
| - return deleted line numbers *only* from diff chunks which decrease the size
|
| - of the new file.
|
| -
|
| - Note: We need this method because we have access to neither the old file
|
| - content nor the list of "delete" changes from the current presubmit script
|
| - API.
|
| -
|
| - """
|
| - results = []
|
| - line_num = 0
|
| - deleting_lines = False
|
| - for line in affected_file.GenerateScmDiff().splitlines():
|
| - # Parse the unified diff chunk optional section heading, which looks like
|
| - # @@ -l,s +l,s @@ optional section heading
|
| - m = self.input_api.re.match(
|
| - r'^@@ \-([0-9]+)\,([0-9]+) \+([0-9]+)\,([0-9]+) @@', line)
|
| - if m:
|
| - old_line_num = int(m.group(1))
|
| - old_size = int(m.group(2))
|
| - new_line_num = int(m.group(3))
|
| - new_size = int(m.group(4))
|
| - line_num = new_line_num
|
| - # Return line numbers only from diff chunks decreasing the size of the
|
| - # new file
|
| - deleting_lines = old_size > new_size
|
| - continue
|
| - if not line.startswith('-'):
|
| - line_num += 1
|
| - if deleting_lines and line.startswith('-') and not line.startswith('--'):
|
| - results.append(line_num)
|
| - return results
|
| -
|
| - def CheckForEnumEntryDeletions(self, affected_file):
|
| - """Look for deletions inside the enum definition. We currently use a
|
| - simple heuristics (not 100% accurate): if there are deleted lines inside
|
| - the enum definition, this might be a deletion.
|
| -
|
| - """
|
| - range_new = self.ComputeEnumRangeInNewFile(affected_file)
|
| - if not range_new:
|
| - return False
|
| -
|
| - is_ok = True
|
| - for line_num in self.GetDeletedLinesFromScmDiff(affected_file):
|
| - if range_new.Contains(line_num):
|
| - self.EmitWarning("It looks like you are deleting line(s) from the "
|
| - "enum definition. This should never happen.",
|
| - line_num)
|
| - is_ok = False
|
| - return is_ok
|
| -
|
| - def CheckForEnumEntryInsertions(self, affected_file):
|
| - range = self.ComputeEnumRangeInNewFile(affected_file)
|
| - if not range:
|
| - return False
|
| -
|
| - first_line = range.first_line
|
| - last_line = range.last_line
|
| -
|
| - # Collect the range of changes inside the enum definition range.
|
| - is_ok = True
|
| - for line_start, line_end, line_text in \
|
| - self.CollectRangesInsideEnumDefinition(affected_file,
|
| - first_line,
|
| - last_line):
|
| - # The only edit we consider valid is adding 1 or more entries *exactly*
|
| - # at the end of the enum definition. Every other edit inside the enum
|
| - # definition will result in a "warning confirmation" message.
|
| - #
|
| - # TODO(rpaquay): We currently cannot detect "renames" of existing entries
|
| - # vs invalid insertions, so we sometimes will warn for valid edits.
|
| - is_valid_edit = (line_end == last_line - 1)
|
| -
|
| - self.LogDebug("Edit range in new file at starting at line number %d and "
|
| - "ending at line number %d: valid=%s"
|
| - % (line_start, line_end, is_valid_edit))
|
| -
|
| - if not is_valid_edit:
|
| - self.EmitWarning("The change starting at line %d and ending at line "
|
| - "%d is *not* located *exactly* at the end of the "
|
| - "enum definition. Unless you are renaming an "
|
| - "existing entry, this is not a valid changes, as new "
|
| - "entries should *always* be added at the end of the "
|
| - "enum definition, right before the 'ENUM_BOUNDARY' "
|
| - "entry." % (line_start, line_end),
|
| - line_start,
|
| - line_text)
|
| - is_ok = False
|
| - return is_ok
|
| -
|
| - def PerformChecks(self, affected_file):
|
| - if not self.CheckForFileDeletion(affected_file):
|
| - return
|
| - if not self.CheckForEnumEntryDeletions(affected_file):
|
| - return
|
| - if not self.CheckForEnumEntryInsertions(affected_file):
|
| - return
|
| +def _CreateHistogramValueChecker(input_api, output_api):
|
| + original_sys_path = sys.path
|
|
|
| - def ProcessHistogramValueFile(self, affected_file):
|
| - self.LogInfo("Start processing file \"%s\"" % affected_file.LocalPath())
|
| - self.PerformChecks(affected_file)
|
| - self.LogInfo("Done processing file \"%s\"" % affected_file.LocalPath())
|
| + try:
|
| + sys.path.append(input_api.os_path.join(
|
| + input_api.PresubmitLocalPath(), '..', '..', 'tools',
|
| + 'strict_enum_value_checker'))
|
| + from strict_enum_value_checker import StrictEnumValueChecker
|
| + finally:
|
| + sys.path = original_sys_path
|
|
|
| - def Run(self):
|
| - for file in self.input_api.AffectedFiles(include_deletes=True):
|
| - if file.LocalPath() == self.LOCAL_PATH:
|
| - self.ProcessHistogramValueFile(file)
|
| - return self.results
|
| + return StrictEnumValueChecker(input_api, output_api,
|
| + start_marker='enum HistogramValue {', end_marker=' // Last entry:',
|
| + path='extensions/browser/extension_function_histogram_value.h')
|
|
|
| def CheckChangeOnUpload(input_api, output_api):
|
| results = []
|
| - results += HistogramValueChecker(input_api, output_api).Run()
|
| + results += _CreateHistogramValueChecker(input_api, output_api).Run()
|
| results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
|
| return results
|
|
|
| +def CheckChangeOnCommit(input_api, output_api):
|
| + return _CreateHistogramValueChecker(input_api, output_api).Run()
|
|
|