@@ 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() |