|
1 /* |
|
2 * Licensed to the Apache Software Foundation (ASF) under one or more |
|
3 * contributor license agreements. See the NOTICE file distributed with |
|
4 * this work for additional information regarding copyright ownership. |
|
5 * The ASF licenses this file to You under the Apache License, Version 2.0 |
|
6 * (the "License"); you may not use this file except in compliance with |
|
7 * the License. You may obtain a copy of the License at |
|
8 * |
|
9 * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 * |
|
11 * Unless required by applicable law or agreed to in writing, software |
|
12 * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 * See the License for the specific language governing permissions and |
|
15 * limitations under the License. |
|
16 * |
|
17 */ |
|
18 |
|
19 /* * Portion Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.*/ |
|
20 |
|
21 package com.nokia.ant.taskdefs; |
|
22 |
|
23 import java.io.FileOutputStream; |
|
24 import java.io.IOException; |
|
25 import java.io.PrintStream; |
|
26 import java.util.regex.Matcher; |
|
27 import java.util.regex.Pattern; |
|
28 |
|
29 import com.nokia.ant.types.LogFilterSet; |
|
30 |
|
31 import org.apache.tools.ant.BuildEvent; |
|
32 import org.apache.tools.ant.BuildException; |
|
33 import org.apache.tools.ant.DefaultLogger; |
|
34 import org.apache.tools.ant.Project; |
|
35 import org.apache.tools.ant.SubBuildListener; |
|
36 import org.apache.tools.ant.util.StringUtils; |
|
37 |
|
38 /** |
|
39 * This is a class that represents a recorder. This is the listener to the build |
|
40 * process. |
|
41 * |
|
42 * @since Ant 1.4 |
|
43 */ |
|
44 public class TextLogRecorderEntry implements LogRecorderEntry, SubBuildListener |
|
45 { |
|
46 |
|
47 // //////////////////////////////////////////////////////////////////// |
|
48 // ATTRIBUTES |
|
49 |
|
50 /** The name of the file associated with this recorder entry. */ |
|
51 private String filename; |
|
52 |
|
53 /** The state of the recorder (recorder on or off). */ |
|
54 private boolean record = true; |
|
55 |
|
56 /** The current verbosity level to record at. */ |
|
57 private int loglevel = Project.MSG_INFO; |
|
58 |
|
59 /** The output PrintStream to record to. */ |
|
60 private PrintStream out; |
|
61 |
|
62 /** The start time of the last know target. */ |
|
63 private long targetStartTime; |
|
64 |
|
65 /** Strip task banners if true. */ |
|
66 private boolean emacsMode; |
|
67 |
|
68 private LogFilterSet filterset; |
|
69 |
|
70 private Pattern pattern; |
|
71 |
|
72 /** project instance the recorder is associated with */ |
|
73 private Project project; |
|
74 |
|
75 |
|
76 // //////////////////////////////////////////////////////////////////// |
|
77 // CONSTRUCTORS / INITIALIZERS |
|
78 |
|
79 /** |
|
80 * @param name |
|
81 * The name of this recorder (used as the filename). |
|
82 */ |
|
83 protected TextLogRecorderEntry(String name) |
|
84 { |
|
85 targetStartTime = System.currentTimeMillis(); |
|
86 filename = name; |
|
87 } |
|
88 |
|
89 // //////////////////////////////////////////////////////////////////// |
|
90 // ACCESSOR METHODS |
|
91 |
|
92 /** |
|
93 * @return the name of the file the output is sent to. |
|
94 */ |
|
95 public String getFilename() |
|
96 { |
|
97 return filename; |
|
98 } |
|
99 |
|
100 /** |
|
101 * Turns off or on this recorder. |
|
102 * |
|
103 * @param state |
|
104 * true for on, false for off, null for no change. |
|
105 */ |
|
106 public void setRecordState(boolean state) |
|
107 { |
|
108 flush(); |
|
109 record = state; |
|
110 } |
|
111 |
|
112 public void setRegexp(String regexp) |
|
113 { |
|
114 pattern = Pattern.compile(Pattern.quote(regexp)); |
|
115 } |
|
116 |
|
117 public void setFilterSet(LogFilterSet o) |
|
118 { |
|
119 System.out.println("setFilterSet: " + o); |
|
120 filterset = o; |
|
121 } |
|
122 |
|
123 /** |
|
124 * @see org.apache.tools.ant.BuildListener#buildStarted(BuildEvent) |
|
125 */ |
|
126 /** {@inheritDoc}. */ |
|
127 public void buildStarted(BuildEvent event) |
|
128 { |
|
129 log("> BUILD STARTED", Project.MSG_DEBUG); |
|
130 } |
|
131 |
|
132 /** |
|
133 * @see org.apache.tools.ant.BuildListener#buildFinished(BuildEvent) |
|
134 */ |
|
135 /** {@inheritDoc}. */ |
|
136 public void buildFinished(BuildEvent event) |
|
137 { |
|
138 log("< BUILD FINISHED", Project.MSG_DEBUG); |
|
139 |
|
140 if (record && out != null) |
|
141 { |
|
142 Throwable error = event.getException(); |
|
143 |
|
144 if (error == null) |
|
145 { |
|
146 out.println(StringUtils.LINE_SEP + "BUILD SUCCESSFUL"); |
|
147 } |
|
148 else |
|
149 { |
|
150 out.println(StringUtils.LINE_SEP + "BUILD FAILED" + StringUtils.LINE_SEP); |
|
151 error.printStackTrace(out); |
|
152 } |
|
153 } |
|
154 cleanup(); |
|
155 } |
|
156 |
|
157 /** |
|
158 * Cleans up any resources held by this recorder entry at the end of a |
|
159 * subbuild if it has been created for the subbuild's project instance. |
|
160 * |
|
161 * @param event |
|
162 * the buildFinished event |
|
163 * |
|
164 * @since Ant 1.6.2 |
|
165 */ |
|
166 public void subBuildFinished(BuildEvent event) |
|
167 { |
|
168 if (event.getProject() == project) |
|
169 { |
|
170 cleanup(); |
|
171 } |
|
172 } |
|
173 |
|
174 /** |
|
175 * Empty implementation to satisfy the BuildListener interface. |
|
176 * |
|
177 * @param event |
|
178 * the buildStarted event |
|
179 * |
|
180 * @since Ant 1.6.2 |
|
181 */ |
|
182 public void subBuildStarted(BuildEvent event) |
|
183 { |
|
184 } |
|
185 |
|
186 /** |
|
187 * @see org.apache.tools.ant.BuildListener#targetStarted(BuildEvent) |
|
188 */ |
|
189 /** {@inheritDoc}. */ |
|
190 public void targetStarted(BuildEvent event) |
|
191 { |
|
192 log(">> TARGET STARTED -- " + event.getTarget(), Project.MSG_DEBUG); |
|
193 log(StringUtils.LINE_SEP + event.getTarget().getName() + ":", Project.MSG_INFO); |
|
194 targetStartTime = System.currentTimeMillis(); |
|
195 } |
|
196 |
|
197 /** |
|
198 * @see org.apache.tools.ant.BuildListener#targetFinished(BuildEvent) |
|
199 */ |
|
200 /** {@inheritDoc}. */ |
|
201 public void targetFinished(BuildEvent event) |
|
202 { |
|
203 log("<< TARGET FINISHED -- " + event.getTarget(), Project.MSG_DEBUG); |
|
204 |
|
205 String time = formatTime(System.currentTimeMillis() - targetStartTime); |
|
206 |
|
207 log(event.getTarget() + ": duration " + time, Project.MSG_VERBOSE); |
|
208 flush(); |
|
209 } |
|
210 |
|
211 /** |
|
212 * @see org.apache.tools.ant.BuildListener#taskStarted(BuildEvent) |
|
213 */ |
|
214 /** {@inheritDoc}. */ |
|
215 public void taskStarted(BuildEvent event) |
|
216 { |
|
217 log(">>> TASK STARTED -- " + event.getTask(), Project.MSG_DEBUG); |
|
218 } |
|
219 |
|
220 /** |
|
221 * @see org.apache.tools.ant.BuildListener#taskFinished(BuildEvent) |
|
222 */ |
|
223 /** {@inheritDoc}. */ |
|
224 public void taskFinished(BuildEvent event) |
|
225 { |
|
226 log("<<< TASK FINISHED -- " + event.getTask(), Project.MSG_DEBUG); |
|
227 flush(); |
|
228 } |
|
229 |
|
230 /** |
|
231 * @see org.apache.tools.ant.BuildListener#messageLogged(BuildEvent) |
|
232 */ |
|
233 /** {@inheritDoc}. */ |
|
234 public void messageLogged(BuildEvent event) |
|
235 { |
|
236 log("--- MESSAGE LOGGED", Project.MSG_DEBUG); |
|
237 |
|
238 StringBuffer buf = new StringBuffer(); |
|
239 |
|
240 if (event.getTask() != null) |
|
241 { |
|
242 String name = event.getTask().getTaskName(); |
|
243 |
|
244 if (!emacsMode) |
|
245 { |
|
246 String label = "[" + name + "] "; |
|
247 int size = DefaultLogger.LEFT_COLUMN_SIZE - label.length(); |
|
248 |
|
249 for (int i = 0; i < size; i++) |
|
250 { |
|
251 buf.append(" "); |
|
252 } |
|
253 buf.append(label); |
|
254 } |
|
255 } |
|
256 String message = event.getMessage(); |
|
257 String filteredMessage = filterMessage(message); |
|
258 buf.append(filteredMessage); |
|
259 |
|
260 log(buf.toString(), event.getPriority()); |
|
261 } |
|
262 |
|
263 private String filterMessage(String message) |
|
264 { |
|
265 if (pattern != null) |
|
266 { |
|
267 Matcher match = pattern.matcher(message); |
|
268 message = match.replaceAll("********"); |
|
269 } |
|
270 return message; |
|
271 } |
|
272 |
|
273 /** |
|
274 * The thing that actually sends the information to the output. |
|
275 * |
|
276 * @param mesg |
|
277 * The message to log. |
|
278 * @param level |
|
279 * The verbosity level of the message. |
|
280 */ |
|
281 private void log(String mesg, int level) |
|
282 { |
|
283 if (record && (level <= loglevel) && out != null) |
|
284 { |
|
285 out.println(mesg); |
|
286 } |
|
287 } |
|
288 |
|
289 private void flush() |
|
290 { |
|
291 if (record && out != null) |
|
292 { |
|
293 out.flush(); |
|
294 } |
|
295 } |
|
296 |
|
297 /** |
|
298 * @see BuildLogger#setMessageOutputLevel(int) |
|
299 */ |
|
300 /** {@inheritDoc}. */ |
|
301 public void setMessageOutputLevel(int level) |
|
302 { |
|
303 if (level >= Project.MSG_ERR && level <= Project.MSG_DEBUG) |
|
304 { |
|
305 loglevel = level; |
|
306 } |
|
307 } |
|
308 |
|
309 /** |
|
310 * @see BuildLogger#setOutputPrintStream(PrintStream) |
|
311 */ |
|
312 /** |
|
313 * |
|
314 * @param output Output print stream |
|
315 * |
|
316 */ |
|
317 public void setOutputPrintStream(PrintStream output) |
|
318 { |
|
319 closeFile(); |
|
320 out = output; |
|
321 } |
|
322 |
|
323 /** |
|
324 * @see BuildLogger#setEmacsMode(boolean) |
|
325 */ |
|
326 /** {@inheritDoc}. */ |
|
327 public void setEmacsMode(boolean emacsMode) |
|
328 { |
|
329 this.emacsMode = emacsMode; |
|
330 } |
|
331 |
|
332 /** |
|
333 * @see BuildLogger#setErrorPrintStream(PrintStream) |
|
334 */ |
|
335 /** |
|
336 * |
|
337 * @param err Error print stream |
|
338 * |
|
339 */ |
|
340 public void setErrorPrintStream(PrintStream err) |
|
341 { |
|
342 setOutputPrintStream(err); |
|
343 } |
|
344 |
|
345 private static String formatTime(long millis) |
|
346 { |
|
347 long seconds = millis / 1000; |
|
348 long minutes = seconds / 60; |
|
349 |
|
350 if (minutes > 0) |
|
351 { |
|
352 return Long.toString(minutes) + " minute" + (minutes == 1 ? " " : "s ") |
|
353 + Long.toString(seconds % 60) + " second" + (seconds % 60 == 1 ? "" : "s"); |
|
354 } |
|
355 else |
|
356 { |
|
357 return Long.toString(seconds) + " second" + (seconds % 60 == 1 ? "" : "s"); |
|
358 } |
|
359 |
|
360 } |
|
361 |
|
362 /** |
|
363 * Set the project associated with this recorder entry. |
|
364 * |
|
365 * @param project |
|
366 * the project instance |
|
367 * |
|
368 * @since 1.6.2 |
|
369 */ |
|
370 public void setProject(Project project) |
|
371 { |
|
372 this.project = project; |
|
373 if (project != null) |
|
374 { |
|
375 project.addBuildListener(this); |
|
376 } |
|
377 } |
|
378 |
|
379 /** |
|
380 * @since 1.6.2 |
|
381 */ |
|
382 public void cleanup() |
|
383 { |
|
384 closeFile(); |
|
385 if (project != null) |
|
386 { |
|
387 project.removeBuildListener(this); |
|
388 } |
|
389 project = null; |
|
390 } |
|
391 |
|
392 /** |
|
393 * Initially opens the file associated with this recorder. Used by Recorder. |
|
394 * |
|
395 * @param append |
|
396 * Indicates if output must be appended to the logfile or that |
|
397 * the logfile should be overwritten. |
|
398 * @throws BuildException |
|
399 * @since 1.6.3 |
|
400 */ |
|
401 public void openFile(boolean append) |
|
402 { |
|
403 openFileImpl(append); |
|
404 } |
|
405 |
|
406 /** |
|
407 * Closes the file associated with this recorder. Used by Recorder. |
|
408 * |
|
409 * @since 1.6.3 |
|
410 */ |
|
411 public void closeFile() |
|
412 { |
|
413 if (out != null) |
|
414 { |
|
415 out.close(); |
|
416 out = null; |
|
417 } |
|
418 } |
|
419 |
|
420 /** |
|
421 * Re-opens the file associated with this recorder. Used by Recorder. |
|
422 * |
|
423 * @throws BuildException |
|
424 * @since 1.6.3 |
|
425 */ |
|
426 public void reopenFile() |
|
427 { |
|
428 openFileImpl(true); |
|
429 } |
|
430 |
|
431 private void openFileImpl(boolean append) |
|
432 { |
|
433 if (out == null) |
|
434 { |
|
435 try |
|
436 { |
|
437 out = new PrintStream(new FileOutputStream(filename, append)); |
|
438 } |
|
439 catch (IOException ioe) |
|
440 { |
|
441 throw new BuildException("Problems opening file using a " + "recorder entry", ioe); |
|
442 } |
|
443 } |
|
444 } |
|
445 |
|
446 } |