| @@ 964-1118 (lines=155) @@ | ||
| 961 | return '' |
|
| 962 | ||
| 963 | ||
| 964 | class _CppLintState(object): |
|
| 965 | """Maintains module-wide state..""" |
|
| 966 | ||
| 967 | def __init__(self): |
|
| 968 | self.verbose_level = 1 # global setting. |
|
| 969 | self.error_count = 0 # global count of reported errors |
|
| 970 | # filters to apply when emitting error messages |
|
| 971 | self.filters = _DEFAULT_FILTERS[:] |
|
| 972 | # backup of filter list. Used to restore the state after each file. |
|
| 973 | self._filters_backup = self.filters[:] |
|
| 974 | self.counting = 'total' # In what way are we counting errors? |
|
| 975 | self.errors_by_category = {} # string to int dict storing error counts |
|
| 976 | ||
| 977 | # output format: |
|
| 978 | # "emacs" - format that emacs can parse (default) |
|
| 979 | # "eclipse" - format that eclipse can parse |
|
| 980 | # "vs7" - format that Microsoft Visual Studio 7 can parse |
|
| 981 | # "junit" - format that Jenkins, Bamboo, etc can parse |
|
| 982 | self.output_format = 'emacs' |
|
| 983 | ||
| 984 | # For JUnit output, save errors and failures until the end so that they |
|
| 985 | # can be written into the XML |
|
| 986 | self._junit_errors = [] |
|
| 987 | self._junit_failures = [] |
|
| 988 | ||
| 989 | def SetOutputFormat(self, output_format): |
|
| 990 | """Sets the output format for errors.""" |
|
| 991 | self.output_format = output_format |
|
| 992 | ||
| 993 | def SetVerboseLevel(self, level): |
|
| 994 | """Sets the module's verbosity, and returns the previous setting.""" |
|
| 995 | last_verbose_level = self.verbose_level |
|
| 996 | self.verbose_level = level |
|
| 997 | return last_verbose_level |
|
| 998 | ||
| 999 | def SetCountingStyle(self, counting_style): |
|
| 1000 | """Sets the module's counting options.""" |
|
| 1001 | self.counting = counting_style |
|
| 1002 | ||
| 1003 | def SetFilters(self, filters): |
|
| 1004 | """Sets the error-message filters. |
|
| 1005 | ||
| 1006 | These filters are applied when deciding whether to emit a given |
|
| 1007 | error message. |
|
| 1008 | ||
| 1009 | Args: |
|
| 1010 | filters: A string of comma-separated filters (eg "+whitespace/indent"). |
|
| 1011 | Each filter should start with + or -; else we die. |
|
| 1012 | ||
| 1013 | Raises: |
|
| 1014 | ValueError: The comma-separated filters did not all start with '+' or '-'. |
|
| 1015 | E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" |
|
| 1016 | """ |
|
| 1017 | # Default filters always have less priority than the flag ones. |
|
| 1018 | self.filters = _DEFAULT_FILTERS[:] |
|
| 1019 | self.AddFilters(filters) |
|
| 1020 | ||
| 1021 | def AddFilters(self, filters): |
|
| 1022 | """ Adds more filters to the existing list of error-message filters. """ |
|
| 1023 | for filt in filters.split(','): |
|
| 1024 | clean_filt = filt.strip() |
|
| 1025 | if clean_filt: |
|
| 1026 | self.filters.append(clean_filt) |
|
| 1027 | for filt in self.filters: |
|
| 1028 | if not (filt.startswith('+') or filt.startswith('-')): |
|
| 1029 | raise ValueError('Every filter in --filters must start with + or -' |
|
| 1030 | ' (%s does not)' % filt) |
|
| 1031 | ||
| 1032 | def BackupFilters(self): |
|
| 1033 | """ Saves the current filter list to backup storage.""" |
|
| 1034 | self._filters_backup = self.filters[:] |
|
| 1035 | ||
| 1036 | def RestoreFilters(self): |
|
| 1037 | """ Restores filters previously backed up.""" |
|
| 1038 | self.filters = self._filters_backup[:] |
|
| 1039 | ||
| 1040 | def ResetErrorCounts(self): |
|
| 1041 | """Sets the module's error statistic back to zero.""" |
|
| 1042 | self.error_count = 0 |
|
| 1043 | self.errors_by_category = {} |
|
| 1044 | ||
| 1045 | def IncrementErrorCount(self, category): |
|
| 1046 | """Bumps the module's error statistic.""" |
|
| 1047 | self.error_count += 1 |
|
| 1048 | if self.counting in ('toplevel', 'detailed'): |
|
| 1049 | if self.counting != 'detailed': |
|
| 1050 | category = category.split('/')[0] |
|
| 1051 | if category not in self.errors_by_category: |
|
| 1052 | self.errors_by_category[category] = 0 |
|
| 1053 | self.errors_by_category[category] += 1 |
|
| 1054 | ||
| 1055 | def PrintErrorCounts(self): |
|
| 1056 | """Print a summary of errors by category, and the total.""" |
|
| 1057 | for category, count in sorted(iteritems(self.errors_by_category)): |
|
| 1058 | self.PrintInfo('Category \'%s\' errors found: %d\n' % |
|
| 1059 | (category, count)) |
|
| 1060 | if self.error_count > 0: |
|
| 1061 | self.PrintInfo('Total errors found: %d\n' % self.error_count) |
|
| 1062 | ||
| 1063 | def PrintInfo(self, message): |
|
| 1064 | if not _quiet and self.output_format != 'junit': |
|
| 1065 | sys.stderr.write(message) |
|
| 1066 | ||
| 1067 | def PrintError(self, message): |
|
| 1068 | if self.output_format == 'junit': |
|
| 1069 | self._junit_errors.append(message) |
|
| 1070 | else: |
|
| 1071 | sys.stderr.write(message) |
|
| 1072 | ||
| 1073 | def AddJUnitFailure(self, filename, linenum, message, category, confidence): |
|
| 1074 | self._junit_failures.append((filename, linenum, message, category, |
|
| 1075 | confidence)) |
|
| 1076 | ||
| 1077 | def FormatJUnitXML(self): |
|
| 1078 | num_errors = len(self._junit_errors) |
|
| 1079 | num_failures = len(self._junit_failures) |
|
| 1080 | ||
| 1081 | testsuite = xml.etree.ElementTree.Element('testsuite') |
|
| 1082 | testsuite.attrib['name'] = 'cpplint' |
|
| 1083 | testsuite.attrib['errors'] = str(num_errors) |
|
| 1084 | testsuite.attrib['failures'] = str(num_failures) |
|
| 1085 | ||
| 1086 | if num_errors == 0 and num_failures == 0: |
|
| 1087 | testsuite.attrib['tests'] = str(1) |
|
| 1088 | xml.etree.ElementTree.SubElement(testsuite, 'testcase', name='passed') |
|
| 1089 | ||
| 1090 | else: |
|
| 1091 | testsuite.attrib['tests'] = str(num_errors + num_failures) |
|
| 1092 | if num_errors > 0: |
|
| 1093 | testcase = xml.etree.ElementTree.SubElement(testsuite, 'testcase') |
|
| 1094 | testcase.attrib['name'] = 'errors' |
|
| 1095 | error = xml.etree.ElementTree.SubElement(testcase, 'error') |
|
| 1096 | error.text = '\n'.join(self._junit_errors) |
|
| 1097 | if num_failures > 0: |
|
| 1098 | # Group failures by file |
|
| 1099 | failed_file_order = [] |
|
| 1100 | failures_by_file = {} |
|
| 1101 | for failure in self._junit_failures: |
|
| 1102 | failed_file = failure[0] |
|
| 1103 | if failed_file not in failed_file_order: |
|
| 1104 | failed_file_order.append(failed_file) |
|
| 1105 | failures_by_file[failed_file] = [] |
|
| 1106 | failures_by_file[failed_file].append(failure) |
|
| 1107 | # Create a testcase for each file |
|
| 1108 | for failed_file in failed_file_order: |
|
| 1109 | failures = failures_by_file[failed_file] |
|
| 1110 | testcase = xml.etree.ElementTree.SubElement(testsuite, 'testcase') |
|
| 1111 | testcase.attrib['name'] = failed_file |
|
| 1112 | failure = xml.etree.ElementTree.SubElement(testcase, 'failure') |
|
| 1113 | template = '{0}: {1} [{2}] [{3}]' |
|
| 1114 | texts = [template.format(f[1], f[2], f[3], f[4]) for f in failures] |
|
| 1115 | failure.text = '\n'.join(texts) |
|
| 1116 | ||
| 1117 | xml_decl = '<?xml version="1.0" encoding="UTF-8" ?>\n' |
|
| 1118 | return xml_decl + xml.etree.ElementTree.tostring(testsuite, 'utf-8').decode('utf-8') |
|
| 1119 | ||
| 1120 | ||
| 1121 | _cpplint_state = _CppLintState() |
|
| @@ 964-1118 (lines=155) @@ | ||
| 961 | return '' |
|
| 962 | ||
| 963 | ||
| 964 | class _CppLintState(object): |
|
| 965 | """Maintains module-wide state..""" |
|
| 966 | ||
| 967 | def __init__(self): |
|
| 968 | self.verbose_level = 1 # global setting. |
|
| 969 | self.error_count = 0 # global count of reported errors |
|
| 970 | # filters to apply when emitting error messages |
|
| 971 | self.filters = _DEFAULT_FILTERS[:] |
|
| 972 | # backup of filter list. Used to restore the state after each file. |
|
| 973 | self._filters_backup = self.filters[:] |
|
| 974 | self.counting = 'total' # In what way are we counting errors? |
|
| 975 | self.errors_by_category = {} # string to int dict storing error counts |
|
| 976 | ||
| 977 | # output format: |
|
| 978 | # "emacs" - format that emacs can parse (default) |
|
| 979 | # "eclipse" - format that eclipse can parse |
|
| 980 | # "vs7" - format that Microsoft Visual Studio 7 can parse |
|
| 981 | # "junit" - format that Jenkins, Bamboo, etc can parse |
|
| 982 | self.output_format = 'emacs' |
|
| 983 | ||
| 984 | # For JUnit output, save errors and failures until the end so that they |
|
| 985 | # can be written into the XML |
|
| 986 | self._junit_errors = [] |
|
| 987 | self._junit_failures = [] |
|
| 988 | ||
| 989 | def SetOutputFormat(self, output_format): |
|
| 990 | """Sets the output format for errors.""" |
|
| 991 | self.output_format = output_format |
|
| 992 | ||
| 993 | def SetVerboseLevel(self, level): |
|
| 994 | """Sets the module's verbosity, and returns the previous setting.""" |
|
| 995 | last_verbose_level = self.verbose_level |
|
| 996 | self.verbose_level = level |
|
| 997 | return last_verbose_level |
|
| 998 | ||
| 999 | def SetCountingStyle(self, counting_style): |
|
| 1000 | """Sets the module's counting options.""" |
|
| 1001 | self.counting = counting_style |
|
| 1002 | ||
| 1003 | def SetFilters(self, filters): |
|
| 1004 | """Sets the error-message filters. |
|
| 1005 | ||
| 1006 | These filters are applied when deciding whether to emit a given |
|
| 1007 | error message. |
|
| 1008 | ||
| 1009 | Args: |
|
| 1010 | filters: A string of comma-separated filters (eg "+whitespace/indent"). |
|
| 1011 | Each filter should start with + or -; else we die. |
|
| 1012 | ||
| 1013 | Raises: |
|
| 1014 | ValueError: The comma-separated filters did not all start with '+' or '-'. |
|
| 1015 | E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" |
|
| 1016 | """ |
|
| 1017 | # Default filters always have less priority than the flag ones. |
|
| 1018 | self.filters = _DEFAULT_FILTERS[:] |
|
| 1019 | self.AddFilters(filters) |
|
| 1020 | ||
| 1021 | def AddFilters(self, filters): |
|
| 1022 | """ Adds more filters to the existing list of error-message filters. """ |
|
| 1023 | for filt in filters.split(','): |
|
| 1024 | clean_filt = filt.strip() |
|
| 1025 | if clean_filt: |
|
| 1026 | self.filters.append(clean_filt) |
|
| 1027 | for filt in self.filters: |
|
| 1028 | if not (filt.startswith('+') or filt.startswith('-')): |
|
| 1029 | raise ValueError('Every filter in --filters must start with + or -' |
|
| 1030 | ' (%s does not)' % filt) |
|
| 1031 | ||
| 1032 | def BackupFilters(self): |
|
| 1033 | """ Saves the current filter list to backup storage.""" |
|
| 1034 | self._filters_backup = self.filters[:] |
|
| 1035 | ||
| 1036 | def RestoreFilters(self): |
|
| 1037 | """ Restores filters previously backed up.""" |
|
| 1038 | self.filters = self._filters_backup[:] |
|
| 1039 | ||
| 1040 | def ResetErrorCounts(self): |
|
| 1041 | """Sets the module's error statistic back to zero.""" |
|
| 1042 | self.error_count = 0 |
|
| 1043 | self.errors_by_category = {} |
|
| 1044 | ||
| 1045 | def IncrementErrorCount(self, category): |
|
| 1046 | """Bumps the module's error statistic.""" |
|
| 1047 | self.error_count += 1 |
|
| 1048 | if self.counting in ('toplevel', 'detailed'): |
|
| 1049 | if self.counting != 'detailed': |
|
| 1050 | category = category.split('/')[0] |
|
| 1051 | if category not in self.errors_by_category: |
|
| 1052 | self.errors_by_category[category] = 0 |
|
| 1053 | self.errors_by_category[category] += 1 |
|
| 1054 | ||
| 1055 | def PrintErrorCounts(self): |
|
| 1056 | """Print a summary of errors by category, and the total.""" |
|
| 1057 | for category, count in sorted(iteritems(self.errors_by_category)): |
|
| 1058 | self.PrintInfo('Category \'%s\' errors found: %d\n' % |
|
| 1059 | (category, count)) |
|
| 1060 | if self.error_count > 0: |
|
| 1061 | self.PrintInfo('Total errors found: %d\n' % self.error_count) |
|
| 1062 | ||
| 1063 | def PrintInfo(self, message): |
|
| 1064 | if not _quiet and self.output_format != 'junit': |
|
| 1065 | sys.stderr.write(message) |
|
| 1066 | ||
| 1067 | def PrintError(self, message): |
|
| 1068 | if self.output_format == 'junit': |
|
| 1069 | self._junit_errors.append(message) |
|
| 1070 | else: |
|
| 1071 | sys.stderr.write(message) |
|
| 1072 | ||
| 1073 | def AddJUnitFailure(self, filename, linenum, message, category, confidence): |
|
| 1074 | self._junit_failures.append((filename, linenum, message, category, |
|
| 1075 | confidence)) |
|
| 1076 | ||
| 1077 | def FormatJUnitXML(self): |
|
| 1078 | num_errors = len(self._junit_errors) |
|
| 1079 | num_failures = len(self._junit_failures) |
|
| 1080 | ||
| 1081 | testsuite = xml.etree.ElementTree.Element('testsuite') |
|
| 1082 | testsuite.attrib['name'] = 'cpplint' |
|
| 1083 | testsuite.attrib['errors'] = str(num_errors) |
|
| 1084 | testsuite.attrib['failures'] = str(num_failures) |
|
| 1085 | ||
| 1086 | if num_errors == 0 and num_failures == 0: |
|
| 1087 | testsuite.attrib['tests'] = str(1) |
|
| 1088 | xml.etree.ElementTree.SubElement(testsuite, 'testcase', name='passed') |
|
| 1089 | ||
| 1090 | else: |
|
| 1091 | testsuite.attrib['tests'] = str(num_errors + num_failures) |
|
| 1092 | if num_errors > 0: |
|
| 1093 | testcase = xml.etree.ElementTree.SubElement(testsuite, 'testcase') |
|
| 1094 | testcase.attrib['name'] = 'errors' |
|
| 1095 | error = xml.etree.ElementTree.SubElement(testcase, 'error') |
|
| 1096 | error.text = '\n'.join(self._junit_errors) |
|
| 1097 | if num_failures > 0: |
|
| 1098 | # Group failures by file |
|
| 1099 | failed_file_order = [] |
|
| 1100 | failures_by_file = {} |
|
| 1101 | for failure in self._junit_failures: |
|
| 1102 | failed_file = failure[0] |
|
| 1103 | if failed_file not in failed_file_order: |
|
| 1104 | failed_file_order.append(failed_file) |
|
| 1105 | failures_by_file[failed_file] = [] |
|
| 1106 | failures_by_file[failed_file].append(failure) |
|
| 1107 | # Create a testcase for each file |
|
| 1108 | for failed_file in failed_file_order: |
|
| 1109 | failures = failures_by_file[failed_file] |
|
| 1110 | testcase = xml.etree.ElementTree.SubElement(testsuite, 'testcase') |
|
| 1111 | testcase.attrib['name'] = failed_file |
|
| 1112 | failure = xml.etree.ElementTree.SubElement(testcase, 'failure') |
|
| 1113 | template = '{0}: {1} [{2}] [{3}]' |
|
| 1114 | texts = [template.format(f[1], f[2], f[3], f[4]) for f in failures] |
|
| 1115 | failure.text = '\n'.join(texts) |
|
| 1116 | ||
| 1117 | xml_decl = '<?xml version="1.0" encoding="UTF-8" ?>\n' |
|
| 1118 | return xml_decl + xml.etree.ElementTree.tostring(testsuite, 'utf-8').decode('utf-8') |
|
| 1119 | ||
| 1120 | ||
| 1121 | _cpplint_state = _CppLintState() |
|