-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathStyleErrors.java
160 lines (152 loc) · 6.5 KB
/
StyleErrors.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Read the file(s) given on the command line, which are presumed to be
* the output of the "check styles", and generate a summary of the results.
*/
public final class StyleErrors {
/** Private constructor because we only use static methods here. */
private StyleErrors() {
}
/**
* A summary object holding one type of error and the number of times
* it was encountered.
*/
private static class Info {
/** The error class from the check styles configuration. */
private String errorClass;
/** The final count of how many times this error was encountered. */
private Integer count;
/** Construct one of these with the given information.
* @param errClass The checkstyle error.
* @param c The final count of these errors.
*/
Info(final String errClass, final Integer c) {
this.errorClass = errClass;
this.count = c;
}
/** @return The saved checkstyle error name. */
String getErrorClass() {
return errorClass;
}
/** @return The final count of this error type. */
Integer getCount() {
return count;
}
}
/**
* A comparator that sorts first by count and then by the error class name.
*/
private static Comparator<Info> comparator = new Comparator<Info>() {
@Override
public int compare(final Info o1, final Info o2) {
// Order first by count, then by class name
int c1 = o1.count.intValue();
int c2 = o2.count.intValue();
if (c1 == c2) {
return o1.errorClass.compareTo(o2.errorClass);
} else {
return Integer.signum(c1 - c2);
}
}
};
/** Pattern used to parse each input line. */
private static final Pattern LINE_PATTERN =
Pattern.compile("^\\[[A-Z]+\\]\\s+(([a-zA-Z]\\:)?([^:]+))(\\:[0-9]+\\:)([0-9]+\\:)?\\s+(.+)\\s+(\\[[a-zA-Z]+\\])$");
/** The group in the {@link #LINE_PATTERN} that contains the file name. */
private static final int FILE_NAME_GROUP = 1;
/** The group in the {@link #LINE_PATTERN} that contains the checkstyle error name. */
private static final int CLASS_NAME_GROUP = 7;
/** A format string used to output all the information in a uniform manner. */
private static final String FORMAT = "%1$-32s%2$5d%n";
/** Format string used to print the underlines. */
private static final String UNDER_FORMAT = "%1$-32s%2$5s%n";
/** The set of unique file names found in the list. */
private static Set<String> fileNameSet = new HashSet<>();
/** For each type of checkstyle error, the name and running count for each. */
private static Map<String, Integer> counts = new TreeMap<>();
/** At the end of each file, the list used to sort by count and name. */
private static List<Info> sortedList = new ArrayList<>();
/**
* The main method, executed from the command line, which reads through each file
* and processes it.
* @param args The command line arguments.
*/
public static void main(final String[] args) {
for (String arg : args) {
int lineNo = 0;
counts.clear();
sortedList.clear();
try (BufferedReader reader = new BufferedReader(new FileReader(new File(arg)))) {
String line;
while ((line = reader.readLine()) != null) {
lineNo++;
Matcher m = LINE_PATTERN.matcher(line);
if (m.matches()) {
String fileName = m.group(FILE_NAME_GROUP);
fileNameSet.add(fileName);
String errorClass = m.group(CLASS_NAME_GROUP);
Integer count = counts.get(errorClass);
if (count == null) {
count = Integer.valueOf(1);
} else {
int i = count.intValue() + 1;
count = Integer.valueOf(i);
}
counts.put(errorClass, count);
} else if (line.equals("Starting audit...") || line.equals("Audit done.")) {
continue;
} else {
System.err.println("Line " + lineNo + ". Doesn't match the pattern.");
System.err.println("\t" + line);
}
}
} catch (IOException ioe) {
System.err.println("Error reading the \"" + arg + "\" file: " + ioe.getMessage());
}
int total = 0;
for (String key : counts.keySet()) {
Integer count = counts.get(key);
total += count.intValue();
Info info = new Info(key, count);
sortedList.add(info);
}
Collections.sort(sortedList, comparator);
for (Info info : sortedList) {
System.out.format(FORMAT, info.getErrorClass(), info.getCount());
}
System.out.format(UNDER_FORMAT, "----------------------------", "-----");
System.out.format(FORMAT, "Grand Total", total);
System.out.format(FORMAT, "Total Files With Errors", fileNameSet.size());
System.out.println();
}
}
}