1
2
3
4 package net.sourceforge.pmd.renderers;
5
6 import java.io.BufferedReader;
7 import java.io.File;
8 import java.io.FileNotFoundException;
9 import java.io.FileReader;
10 import java.io.IOException;
11 import java.io.Reader;
12 import java.util.Iterator;
13 import java.util.Map;
14
15 import net.sourceforge.pmd.PMD;
16 import net.sourceforge.pmd.Report;
17 import net.sourceforge.pmd.RuleViolation;
18 import net.sourceforge.pmd.lang.rule.properties.StringProperty;
19
20 import org.apache.commons.io.IOUtils;
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 public class TextColorRenderer extends AbstractAccumulatingRenderer {
53
54
55 public static final String NAME = "textcolor";
56
57 public static final StringProperty COLOR = new StringProperty("color", "Enables colors with anything other than 'false' or '0'.", "yes", 0);
58 private static final String SYSTEM_PROPERTY_PMD_COLOR = "pmd.color";
59
60
61
62
63 private String pwd;
64
65 private String yellowBold = "";
66 private String whiteBold = "";
67 private String redBold = "";
68 private String cyan = "";
69 private String green = "";
70
71 private String colorReset = "";
72
73 public TextColorRenderer() {
74
75 super(NAME, "Text format, with color support (requires ANSI console support, e.g. xterm, rxvt, etc.).");
76 definePropertyDescriptor(COLOR);
77 }
78
79 public String defaultFileExtension() { return "txt"; }
80
81
82
83
84
85
86
87
88 private void initializeColorsIfSupported() {
89 if (isPropertyEnabled(getProperty(COLOR)) || isPropertyEnabled(System.getProperty(SYSTEM_PROPERTY_PMD_COLOR))) {
90 this.yellowBold = "\u001B[1;33m";
91 this.whiteBold = "\u001B[1;37m";
92 this.redBold = "\u001B[1;31m";
93 this.green = "\u001B[0;32m";
94 this.cyan = "\u001B[0;36m";
95
96 this.colorReset = "\u001B[0m";
97 }
98 }
99
100 private boolean isPropertyEnabled(String property) {
101 return property != null && !(property.equals("0") || property.equalsIgnoreCase("false"));
102 }
103
104
105
106
107 @Override
108 public void end() throws IOException {
109 StringBuffer buf = new StringBuffer(500);
110 buf.append(PMD.EOL);
111 initializeColorsIfSupported();
112 String lastFile = null;
113 int numberOfErrors = 0;
114 int numberOfWarnings = 0;
115
116 for (Iterator<RuleViolation> i = report.iterator(); i.hasNext();) {
117 buf.setLength(0);
118 numberOfWarnings++;
119 RuleViolation rv = i.next();
120 if (!rv.getFilename().equals(lastFile)) {
121 lastFile = rv.getFilename();
122 buf.append(this.yellowBold + "*" + this.colorReset + " file: " + this.whiteBold
123 + this.getRelativePath(lastFile) + this.colorReset + PMD.EOL);
124 }
125 buf.append(this.green + " src: " + this.cyan
126 + lastFile.substring(lastFile.lastIndexOf(File.separator) + 1) + this.colorReset + ":" + this.cyan
127 + rv.getBeginLine() + (rv.getEndLine() == -1 ? "" : ":" + rv.getEndLine()) + this.colorReset
128 + PMD.EOL);
129 buf.append(this.green + " rule: " + this.colorReset + rv.getRule().getName() + PMD.EOL);
130 buf.append(this.green + " msg: " + this.colorReset + rv.getDescription() + PMD.EOL);
131 buf.append(this.green + " code: " + this.colorReset + this.getLine(lastFile, rv.getBeginLine())
132 + PMD.EOL + PMD.EOL);
133 writer.write(buf.toString());
134 }
135 writer.write(PMD.EOL + PMD.EOL);
136 writer.write("Summary:" + PMD.EOL + PMD.EOL);
137 Map<String, Integer> summary = report.getCountSummary();
138 for (Map.Entry<String, Integer> entry : summary.entrySet()) {
139 buf.setLength(0);
140 String key = entry.getKey();
141 buf.append(key).append(" : ").append(entry.getValue()).append(PMD.EOL);
142 writer.write(buf.toString());
143 }
144
145 for (Iterator<Report.ProcessingError> i = report.errors(); i.hasNext();) {
146 buf.setLength(0);
147 numberOfErrors++;
148 Report.ProcessingError error = i.next();
149 if (error.getFile().equals(lastFile)) {
150 lastFile = error.getFile();
151 buf.append(this.redBold + "*" + this.colorReset + " file: " + this.whiteBold
152 + this.getRelativePath(lastFile) + this.colorReset + PMD.EOL);
153 }
154 buf.append(this.green + " err: " + this.cyan + error.getMsg() + this.colorReset + PMD.EOL + PMD.EOL);
155 writer.write(buf.toString());
156 }
157
158
159 if (numberOfErrors > 0) {
160 writer.write(this.redBold + "*" + this.colorReset + " errors: " + this.whiteBold + numberOfWarnings
161 + this.colorReset + PMD.EOL);
162 }
163 writer.write(this.yellowBold + "*" + this.colorReset + " warnings: " + this.whiteBold + numberOfWarnings
164 + this.colorReset + PMD.EOL);
165 }
166
167
168
169
170
171
172
173
174 private String getLine(String sourceFile, int line) {
175 String code = null;
176 BufferedReader br = null;
177 try {
178 br = new BufferedReader(getReader(sourceFile));
179 for (int i = 0; line > i; i++) {
180 String txt = br.readLine();
181 code = txt == null ? "" : txt.trim();
182 }
183 } catch (IOException ioErr) {
184 ioErr.printStackTrace();
185 } finally {
186 IOUtils.closeQuietly(br);
187 }
188 return code;
189 }
190
191 protected Reader getReader(String sourceFile) throws FileNotFoundException {
192 return new FileReader(new File(sourceFile));
193 }
194
195
196
197
198
199
200
201
202 private String getRelativePath(String fileName) {
203 String relativePath;
204
205
206 if (pwd == null) {
207 try {
208 this.pwd = new File(".").getCanonicalPath();
209 } catch (IOException ioErr) {
210
211 this.pwd = "";
212 }
213 }
214
215
216 if (fileName.indexOf(this.pwd) == 0) {
217 relativePath = "." + fileName.substring(this.pwd.length());
218
219
220 if (relativePath.startsWith("." + File.separator + "." + File.separator)) {
221 relativePath = relativePath.substring(2);
222 }
223 } else {
224
225
226
227 relativePath = fileName;
228 }
229
230 return relativePath;
231 }
232 }