KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > cvslib > ChangeLogTask


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 package org.apache.tools.ant.taskdefs.cvslib;
19
20 import java.io.File JavaDoc;
21 import java.io.FileInputStream JavaDoc;
22 import java.io.FileOutputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.OutputStreamWriter JavaDoc;
25 import java.io.PrintWriter JavaDoc;
26 import java.io.UnsupportedEncodingException JavaDoc;
27 import java.text.SimpleDateFormat JavaDoc;
28 import java.util.Date JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.util.Properties JavaDoc;
31 import java.util.Vector JavaDoc;
32 import org.apache.tools.ant.BuildException;
33 import org.apache.tools.ant.DirectoryScanner;
34 import org.apache.tools.ant.Project;
35 import org.apache.tools.ant.taskdefs.AbstractCvsTask;
36 import org.apache.tools.ant.types.FileSet;
37 import org.apache.tools.ant.util.FileUtils;
38
39 /**
40  * Examines the output of cvs log and group related changes together.
41  *
42  * It produces an XML output representing the list of changes.
43  * <pre>
44  * <font color=#0000ff>&lt;!-- Root element --&gt;</font>
45  * <font color=#6a5acd>&lt;!ELEMENT</font> changelog <font color=#ff00ff>
46  * (entry</font><font color=#ff00ff>+</font><font color=#ff00ff>)
47  * </font><font color=#6a5acd>&gt;</font>
48  * <font color=#0000ff>&lt;!-- CVS Entry --&gt;</font>
49  * <font color=#6a5acd>&lt;!ELEMENT</font> entry <font color=#ff00ff>
50  * (date,author,file</font><font color=#ff00ff>+</font><font color=#ff00ff>,msg)
51  * </font><font color=#6a5acd>&gt;</font>
52  * <font color=#0000ff>&lt;!-- Date of cvs entry --&gt;</font>
53  * <font color=#6a5acd>&lt;!ELEMENT</font> date <font color=#ff00ff>(#PCDATA)
54  * </font><font color=#6a5acd>&gt;</font>
55  * <font color=#0000ff>&lt;!-- Author of change --&gt;</font>
56  * <font color=#6a5acd>&lt;!ELEMENT</font> author <font color=#ff00ff>(#PCDATA)
57  * </font><font color=#6a5acd>&gt;</font>
58  * <font color=#0000ff>&lt;!-- List of files affected --&gt;</font>
59  * <font color=#6a5acd>&lt;!ELEMENT</font> msg <font color=#ff00ff>(#PCDATA)
60  * </font><font color=#6a5acd>&gt;</font>
61  * <font color=#0000ff>&lt;!-- File changed --&gt;</font>
62  * <font color=#6a5acd>&lt;!ELEMENT</font> file <font color=#ff00ff>
63  * (name,revision,prevrevision</font><font color=#ff00ff>?</font>
64  * <font color=#ff00ff>)</font><font color=#6a5acd>&gt;</font>
65  * <font color=#0000ff>&lt;!-- Name of the file --&gt;</font>
66  * <font color=#6a5acd>&lt;!ELEMENT</font> name <font color=#ff00ff>(#PCDATA)
67  * </font><font color=#6a5acd>&gt;</font>
68  * <font color=#0000ff>&lt;!-- Revision number --&gt;</font>
69  * <font color=#6a5acd>&lt;!ELEMENT</font> revision <font color=#ff00ff>
70  * (#PCDATA)</font><font color=#6a5acd>&gt;</font>
71  * <font color=#0000ff>&lt;!-- Previous revision number --&gt;</font>
72  * <font color=#6a5acd>&lt;!ELEMENT</font> prevrevision <font color=#ff00ff>
73  * (#PCDATA)</font><font color=#6a5acd>&gt;</font>
74  * </pre>
75  *
76  * @since Ant 1.5
77  * @ant.task name="cvschangelog" category="scm"
78  */

79 public class ChangeLogTask extends AbstractCvsTask {
80     /** User list */
81     private File JavaDoc usersFile;
82
83     /** User list */
84     private Vector JavaDoc cvsUsers = new Vector JavaDoc();
85
86     /** Input dir */
87     private File JavaDoc inputDir;
88
89     /** Output file */
90     private File JavaDoc destFile;
91
92     /** The earliest date at which to start processing entries. */
93     private Date JavaDoc startDate;
94
95     /** The latest date at which to stop processing entries. */
96     private Date JavaDoc endDate;
97
98     /**
99      * Filesets containing list of files against which the cvs log will be
100      * performed. If empty then all files in the working directory will
101      * be checked.
102      */

103     private final Vector JavaDoc filesets = new Vector JavaDoc();
104
105
106     /**
107      * Set the base dir for cvs.
108      *
109      * @param inputDir The new dir value
110      */

111     public void setDir(final File JavaDoc inputDir) {
112         this.inputDir = inputDir;
113     }
114
115
116     /**
117      * Set the output file for the log.
118      *
119      * @param destFile The new destfile value
120      */

121     public void setDestfile(final File JavaDoc destFile) {
122         this.destFile = destFile;
123     }
124
125
126     /**
127      * Set a lookup list of user names & addresses
128      *
129      * @param usersFile The file containing the users info.
130      */

131     public void setUsersfile(final File JavaDoc usersFile) {
132         this.usersFile = usersFile;
133     }
134
135
136     /**
137      * Add a user to list changelog knows about.
138      *
139      * @param user the user
140      */

141     public void addUser(final CvsUser user) {
142         cvsUsers.addElement(user);
143     }
144
145
146     /**
147      * Set the date at which the changelog should start.
148      *
149      * @param start The date at which the changelog should start.
150      */

151     public void setStart(final Date JavaDoc start) {
152         this.startDate = start;
153     }
154
155
156     /**
157      * Set the date at which the changelog should stop.
158      *
159      * @param endDate The date at which the changelog should stop.
160      */

161     public void setEnd(final Date JavaDoc endDate) {
162         this.endDate = endDate;
163     }
164
165
166     /**
167      * Set the number of days worth of log entries to process.
168      *
169      * @param days the number of days of log to process.
170      */

171     public void setDaysinpast(final int days) {
172         final long time = System.currentTimeMillis()
173              - (long) days * 24 * 60 * 60 * 1000;
174
175         setStart(new Date JavaDoc(time));
176     }
177
178
179     /**
180      * Adds a set of files about which cvs logs will be generated.
181      *
182      * @param fileSet a set of files about which cvs logs will be generated.
183      */

184     public void addFileset(final FileSet fileSet) {
185         filesets.addElement(fileSet);
186     }
187
188
189     /**
190      * Execute task
191      *
192      * @exception BuildException if something goes wrong executing the
193      * cvs command
194      */

195     public void execute() throws BuildException {
196         File JavaDoc savedDir = inputDir; // may be altered in validate
197

198         try {
199
200             validate();
201             final Properties JavaDoc userList = new Properties JavaDoc();
202
203             loadUserlist(userList);
204
205             for (int i = 0, size = cvsUsers.size(); i < size; i++) {
206                 final CvsUser user = (CvsUser) cvsUsers.get(i);
207                 user.validate();
208                 userList.put(user.getUserID(), user.getDisplayname());
209             }
210
211             setCommand("log");
212
213             if (getTag() != null) {
214                 CvsVersion myCvsVersion = new CvsVersion();
215                 myCvsVersion.setProject(getProject());
216                 myCvsVersion.setTaskName("cvsversion");
217                 myCvsVersion.setCvsRoot(getCvsRoot());
218                 myCvsVersion.setCvsRsh(getCvsRsh());
219                 myCvsVersion.setPassfile(getPassFile());
220                 myCvsVersion.setDest(inputDir);
221                 myCvsVersion.execute();
222                 if (myCvsVersion.supportsCvsLogWithSOption()) {
223                     addCommandArgument("-S");
224                 }
225             }
226             if (null != startDate) {
227                 final SimpleDateFormat JavaDoc outputDate =
228                     new SimpleDateFormat JavaDoc("yyyy-MM-dd");
229
230                 // We want something of the form: -d ">=YYYY-MM-dd"
231
final String JavaDoc dateRange = ">=" + outputDate.format(startDate);
232
233                 // Supply '-d' as a separate argument - Bug# 14397
234
addCommandArgument("-d");
235                 addCommandArgument(dateRange);
236             }
237
238             // Check if list of files to check has been specified
239
if (!filesets.isEmpty()) {
240                 final Enumeration JavaDoc e = filesets.elements();
241
242                 while (e.hasMoreElements()) {
243                     final FileSet fileSet = (FileSet) e.nextElement();
244                     final DirectoryScanner scanner =
245                         fileSet.getDirectoryScanner(getProject());
246                     final String JavaDoc[] files = scanner.getIncludedFiles();
247
248                     for (int i = 0; i < files.length; i++) {
249                         addCommandArgument(files[i]);
250                     }
251                 }
252             }
253
254             final ChangeLogParser parser = new ChangeLogParser();
255             final RedirectingStreamHandler handler =
256                 new RedirectingStreamHandler(parser);
257
258             log(getCommand(), Project.MSG_VERBOSE);
259
260             setDest(inputDir);
261             setExecuteStreamHandler(handler);
262             try {
263                 super.execute();
264             } finally {
265                 final String JavaDoc errors = handler.getErrors();
266
267                 if (null != errors) {
268                     log(errors, Project.MSG_ERR);
269                 }
270             }
271             final CVSEntry[] entrySet = parser.getEntrySetAsArray();
272             final CVSEntry[] filteredEntrySet = filterEntrySet(entrySet);
273
274             replaceAuthorIdWithName(userList, filteredEntrySet);
275
276             writeChangeLog(filteredEntrySet);
277
278         } finally {
279             inputDir = savedDir;
280         }
281     }
282
283     /**
284      * Validate the parameters specified for task.
285      *
286      * @throws BuildException if fails validation checks
287      */

288     private void validate()
289          throws BuildException {
290         if (null == inputDir) {
291             inputDir = getProject().getBaseDir();
292         }
293         if (null == destFile) {
294             final String JavaDoc message = "Destfile must be set.";
295
296             throw new BuildException(message);
297         }
298         if (!inputDir.exists()) {
299             final String JavaDoc message = "Cannot find base dir "
300                  + inputDir.getAbsolutePath();
301
302             throw new BuildException(message);
303         }
304         if (null != usersFile && !usersFile.exists()) {
305             final String JavaDoc message = "Cannot find user lookup list "
306                  + usersFile.getAbsolutePath();
307
308             throw new BuildException(message);
309         }
310     }
311
312     /**
313      * Load the userlist from the userList file (if specified) and add to
314      * list of users.
315      *
316      * @param userList the file of users
317      * @throws BuildException if file can not be loaded for some reason
318      */

319     private void loadUserlist(final Properties JavaDoc userList)
320          throws BuildException {
321         if (null != usersFile) {
322             try {
323                 userList.load(new FileInputStream JavaDoc(usersFile));
324             } catch (final IOException JavaDoc ioe) {
325                 throw new BuildException(ioe.toString(), ioe);
326             }
327         }
328     }
329
330     /**
331      * Filter the specified entries according to an appropriate rule.
332      *
333      * @param entrySet the entry set to filter
334      * @return the filtered entry set
335      */

336     private CVSEntry[] filterEntrySet(final CVSEntry[] entrySet) {
337         final Vector JavaDoc results = new Vector JavaDoc();
338
339         for (int i = 0; i < entrySet.length; i++) {
340             final CVSEntry cvsEntry = entrySet[i];
341             final Date JavaDoc date = cvsEntry.getDate();
342
343             //bug#30471
344
//this is caused by Date.after throwing a NullPointerException
345
//for some reason there's no date set in the CVSEntry
346
//Java 1.3.1 API
347
//http://java.sun.com/j2se/1.3/docs/api/java/util/Date.html#after(java.util.Date)
348
//doesn't throw NullPointerException
349
//Java 1.4.2 + 1.5 API
350
//http://java.sun.com/j2se/1.4.2/docs/api/java/util/Date.html#after(java.util.Date)
351
//according to the docs it doesn't throw, according to the bug report it does
352
//http://java.sun.com/j2se/1.5.0/docs/api/java/util/Date.html#after(java.util.Date)
353
//according to the docs it does throw
354

355             //for now skip entries which are missing a date
356
if (null == date) {
357                 continue;
358             }
359
360             if (null != startDate && startDate.after(date)) {
361                 //Skip dates that are too early
362
continue;
363             }
364             if (null != endDate && endDate.before(date)) {
365                 //Skip dates that are too late
366
continue;
367             }
368             results.addElement(cvsEntry);
369         }
370
371         final CVSEntry[] resultArray = new CVSEntry[results.size()];
372
373         results.copyInto(resultArray);
374         return resultArray;
375     }
376
377     /**
378      * replace all known author's id's with their maven specified names
379      */

380     private void replaceAuthorIdWithName(final Properties JavaDoc userList,
381                                          final CVSEntry[] entrySet) {
382         for (int i = 0; i < entrySet.length; i++) {
383
384             final CVSEntry entry = entrySet[ i ];
385             if (userList.containsKey(entry.getAuthor())) {
386                 entry.setAuthor(userList.getProperty(entry.getAuthor()));
387             }
388         }
389     }
390
391     /**
392      * Print changelog to file specified in task.
393      *
394      * @param entrySet the entry set to write.
395      * @throws BuildException if there is an error writing changelog.
396      */

397     private void writeChangeLog(final CVSEntry[] entrySet)
398          throws BuildException {
399         FileOutputStream JavaDoc output = null;
400
401         try {
402             output = new FileOutputStream JavaDoc(destFile);
403
404             final PrintWriter JavaDoc writer =
405                 new PrintWriter JavaDoc(new OutputStreamWriter JavaDoc(output, "UTF-8"));
406
407             final ChangeLogWriter serializer = new ChangeLogWriter();
408
409             serializer.printChangeLog(writer, entrySet);
410         } catch (final UnsupportedEncodingException JavaDoc uee) {
411             getProject().log(uee.toString(), Project.MSG_ERR);
412         } catch (final IOException JavaDoc ioe) {
413             throw new BuildException(ioe.toString(), ioe);
414         } finally {
415             FileUtils.close(output);
416         }
417     }
418 }
419
420
Popular Tags