KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > cruisecontrol > sourcecontrols > Vss


1 /********************************************************************************
2  * CruiseControl, a Continuous Integration Toolkit
3  * Copyright (c) 2001, ThoughtWorks, Inc.
4  * 651 W Washington Ave. Suite 600
5  * Chicago, IL 60661 USA
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * + Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * + Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  *
20  * + Neither the name of ThoughtWorks, Inc., CruiseControl, nor the
21  * names of its contributors may be used to endorse or promote
22  * products derived from this software without specific prior
23  * written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  ********************************************************************************/

37 package net.sourceforge.cruisecontrol.sourcecontrols;
38
39 import net.sourceforge.cruisecontrol.CruiseControlException;
40 import net.sourceforge.cruisecontrol.Modification;
41 import net.sourceforge.cruisecontrol.SourceControl;
42 import net.sourceforge.cruisecontrol.util.Commandline;
43 import net.sourceforge.cruisecontrol.util.ValidationHelper;
44
45 import org.apache.log4j.Level;
46 import org.apache.log4j.Logger;
47
48 import java.io.BufferedReader JavaDoc;
49 import java.io.File JavaDoc;
50 import java.io.FileReader JavaDoc;
51 import java.io.IOException JavaDoc;
52 import java.text.ParseException JavaDoc;
53 import java.text.SimpleDateFormat JavaDoc;
54 import java.util.ArrayList JavaDoc;
55 import java.util.Date JavaDoc;
56 import java.util.Hashtable JavaDoc;
57 import java.util.Iterator JavaDoc;
58 import java.util.List JavaDoc;
59 import java.util.Locale JavaDoc;
60 import java.util.Map JavaDoc;
61
62 /**
63  * This class handles all VSS-related aspects of determining the modifications since the last good build.
64  *
65  * @author <a HREF="mailto:alden@thoughtworks.com">alden almagro</a>
66  * @author Eli Tucker
67  * @author <a HREF="mailto:jcyip@thoughtworks.com">Jason Yip</a>
68  * @author Arun Aggarwal
69  */

70 public class Vss implements SourceControl {
71
72     private static final Logger LOG = Logger.getLogger(Vss.class);
73
74     private SimpleDateFormat JavaDoc vssDateTimeFormat;
75     private String JavaDoc ssDir;
76     private String JavaDoc vssPath;
77     private String JavaDoc serverPath;
78     private String JavaDoc login;
79     private String JavaDoc dateFormat;
80     private String JavaDoc timeFormat;
81     private Hashtable JavaDoc properties = new Hashtable JavaDoc();
82     private String JavaDoc property;
83     private String JavaDoc propertyOnDelete;
84
85     public Vss() {
86         dateFormat = "MM/dd/yy";
87         timeFormat = "hh:mma";
88         constructVssDateTimeFormat();
89     }
90
91     /**
92      * Set the project to get history from
93      *
94      * @param vsspath
95      */

96     public void setVsspath(String JavaDoc vsspath) {
97         this.vssPath = "$" + vsspath;
98     }
99
100     /**
101      * Set the path to the ss executable
102      *
103      * @param ssdir
104      */

105     public void setSsDir(String JavaDoc ssdir) {
106         this.ssDir = ssdir;
107     }
108
109     /**
110      * Set the path to the directory containing the srcsafe.ini file.
111      *
112      * @param dirWithSrcsafeIni
113      */

114     public void setServerPath(String JavaDoc dirWithSrcsafeIni) {
115         serverPath = dirWithSrcsafeIni;
116     }
117
118     /**
119      * Login for vss
120      *
121      * @param usernameCommaPassword
122      */

123     public void setLogin(String JavaDoc usernameCommaPassword) {
124         login = usernameCommaPassword;
125     }
126
127     /**
128      * Choose a property to be set if the project has modifications if we have a change that only requires repackaging,
129      * i.e. jsp, we don't need to recompile everything, just rejar.
130      *
131      * @param propertyName
132      */

133     public void setProperty(String JavaDoc propertyName) {
134         property = propertyName;
135     }
136
137     /**
138      * Choose a property to be set if the project has deletions
139      *
140      * @param propertyName
141      */

142     public void setPropertyOnDelete(String JavaDoc propertyName) {
143         propertyOnDelete = propertyName;
144     }
145
146     /**
147      * Sets the date format to use for querying VSS and processing reports.
148      *
149      * The default date format is <code>MM/dd/yy</code> . If your computer is set to a different region, you may wish
150      * to use a format such as <code>dd/MM/yy</code> .
151      *
152      * @see java.text.SimpleDateFormat
153      */

154     public void setDateFormat(String JavaDoc format) {
155         dateFormat = format;
156         constructVssDateTimeFormat();
157     }
158
159     /**
160      * Sets the time format to use for querying VSS and processing reports.
161      *
162      * The default time format is <code>hh:mma</code> . If your computer is set to a different region, you may wish to
163      * use a format such as <code>HH:mm</code> .
164      *
165      * @see java.text.SimpleDateFormat
166      */

167     public void setTimeFormat(String JavaDoc format) {
168         timeFormat = format;
169         constructVssDateTimeFormat();
170     }
171
172     public Map JavaDoc getProperties() {
173         return properties;
174     }
175
176     public void validate() throws CruiseControlException {
177         ValidationHelper.assertIsSet(vssPath, "vsspath", this.getClass());
178         ValidationHelper.assertIsSet(login, "login", this.getClass());
179     }
180
181     /**
182      * Calls "ss history [dir] -R -Vd[now]~[lastBuild] -Y[login] -I-N -O[tempFileName]" Results written to a file since
183      * VSS will start wrapping lines if read directly from the stream.
184      *
185      * @param lastBuild
186      * @param now
187      * @return List of modifications
188      */

189     public List JavaDoc getModifications(Date JavaDoc lastBuild, Date JavaDoc now) {
190         ArrayList JavaDoc modifications = new ArrayList JavaDoc();
191
192         String JavaDoc[] env = VSSHelper.loadVSSEnvironment(serverPath);
193         LOG.info("Vss: getting modifications for " + vssPath);
194
195         try {
196             Process JavaDoc p = Runtime.getRuntime().exec(getCommandLine(lastBuild, now), env);
197             p.waitFor();
198             p.getInputStream().close();
199             p.getOutputStream().close();
200             p.getErrorStream().close();
201
202             parseTempFile(modifications);
203         } catch (IOException JavaDoc e) {
204             LOG.equals(e);
205             throw new RuntimeException JavaDoc(e.getMessage());
206         } catch (CruiseControlException e) {
207             LOG.equals(e);
208             throw new RuntimeException JavaDoc(e.getMessage());
209         } catch (InterruptedException JavaDoc e) {
210             LOG.equals(e);
211             throw new RuntimeException JavaDoc(e.getMessage());
212         }
213
214         if (property != null && modifications.size() > 0) {
215             properties.put(property, "true");
216         }
217
218         return modifications;
219     }
220
221     private void parseTempFile(ArrayList JavaDoc modifications) throws IOException JavaDoc {
222         Level loggingLevel = LOG.getEffectiveLevel();
223         if (Level.DEBUG.equals(loggingLevel)) {
224             logVSSTempFile();
225         }
226
227         File JavaDoc tempFile = getTempFile();
228         BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new FileReader JavaDoc(tempFile));
229
230         parseHistoryEntries(modifications, reader);
231
232         reader.close();
233         tempFile.delete();
234     }
235
236     private void logVSSTempFile() throws IOException JavaDoc {
237         BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new FileReader JavaDoc(getTempFile()));
238         String JavaDoc currLine = reader.readLine();
239         LOG.debug(" ");
240         while (currLine != null) {
241             LOG.debug(getTempFile().getName() + ": " + currLine);
242             currLine = reader.readLine();
243         }
244         LOG.debug(" ");
245         reader.close();
246     }
247
248     private File JavaDoc getTempFile() {
249         return new File JavaDoc(createFileNameFromVssPath());
250     }
251
252     String JavaDoc createFileNameFromVssPath() {
253         // don't include the leading $
254
String JavaDoc filename = vssPath.substring(1).replace('/', '_') + ".tmp";
255         while (filename.charAt(0) == '_') {
256             filename = filename.substring(1);
257         }
258         return filename;
259     }
260
261     void parseHistoryEntries(ArrayList JavaDoc modifications, BufferedReader JavaDoc reader) throws IOException JavaDoc {
262         String JavaDoc currLine = reader.readLine();
263
264         while (currLine != null) {
265             if (currLine.startsWith("*****")) {
266                 ArrayList JavaDoc vssEntry = new ArrayList JavaDoc();
267                 vssEntry.add(currLine);
268                 currLine = reader.readLine();
269                 while (currLine != null && !currLine.startsWith("*****")) {
270                     vssEntry.add(currLine);
271                     currLine = reader.readLine();
272                 }
273                 Modification mod = handleEntry(vssEntry);
274                 if (mod != null) {
275                     modifications.add(mod);
276                 }
277             } else {
278                 currLine = reader.readLine();
279             }
280         }
281     }
282
283     protected String JavaDoc[] getCommandLine(Date JavaDoc lastBuild, Date JavaDoc now) throws CruiseControlException {
284         Commandline commandline = new Commandline();
285         String JavaDoc execCommand;
286         try {
287             execCommand = (ssDir != null) ? new File JavaDoc(ssDir, "ss.exe").getCanonicalPath() : "ss.exe";
288         } catch (IOException JavaDoc e) {
289             throw new CruiseControlException(e);
290         }
291
292         commandline.setExecutable(execCommand);
293         commandline.createArgument().setValue("history");
294         commandline.createArgument().setValue(vssPath);
295         commandline.createArgument().setValue("-R");
296         commandline.createArgument().setValue("-Vd" + formatDateForVSS(now) + "~" + formatDateForVSS(lastBuild));
297         commandline.createArgument().setValue("-Y" + login);
298         commandline.createArgument().setValue("-I-N");
299         commandline.createArgument().setValue("-O" + getTempFile().getName());
300
301         String JavaDoc[] line = commandline.getCommandline();
302
303         LOG.debug(" ");
304         for (int i = 0; i < line.length; i++) {
305             LOG.debug("Vss command line arguments: " + line[i]);
306         }
307         LOG.debug(" ");
308
309         return line;
310     }
311
312     /**
313      * Format a date for vss in the format specified by the dateFormat. By default, this is in the form
314      * <code>12/21/2000;8:14A</code> (vss doesn't like the m in am or pm). This format can be changed with
315      * <code>setDateFormat()</code>
316      *
317      * @param d
318      * Date to format.
319      * @return String of date in format that VSS requires.
320      * @see #setDateFormat
321      */

322     private String JavaDoc formatDateForVSS(Date JavaDoc d) {
323         SimpleDateFormat JavaDoc sdf = new SimpleDateFormat JavaDoc(dateFormat + ";" + timeFormat, Locale.US);
324         String JavaDoc vssFormattedDate = sdf.format(d);
325         if (timeFormat.endsWith("a")) {
326             return vssFormattedDate.substring(0, vssFormattedDate.length() - 1);
327         }
328         return vssFormattedDate;
329     }
330
331     // ***** the rest of this is just parsing the vss output *****
332

333     /**
334      * Parse individual VSS history entry
335      *
336      * @param entry
337      */

338     protected Modification handleEntry(List JavaDoc entry) {
339         LOG.debug("VSS history entry BEGIN");
340         for (Iterator JavaDoc i = entry.iterator(); i.hasNext();) {
341             LOG.debug("entry: " + i.next());
342         }
343         LOG.debug("VSS history entry END");
344
345         try {
346             final String JavaDoc labelDelimiter = "**********************";
347             boolean isLabelEntry = labelDelimiter.equals(entry.get(0));
348
349             if (isLabelEntry) {
350                 LOG.debug("this is a label; ignoring this entry");
351                 return null;
352             }
353
354             // but need to adjust for cases where Label: line exists
355
//
356
// ***** DateChooser.java *****
357
// Version 8
358
// Label: "Completely new version!"
359
// User: Arass Date: 10/21/02 Time: 12:48p
360
// Checked in $/code/development/src/org/ets/cbtidg/common/gui
361
// Comment: This is where I add a completely new, but alot nicer
362
// version of the date chooser.
363
// Label comment:
364

365             int nameAndDateIndex = 2;
366             if (((String JavaDoc) entry.get(0)).startsWith("***************** ")) {
367                 nameAndDateIndex = 1;
368             }
369             String JavaDoc nameAndDateLine = (String JavaDoc) entry.get(nameAndDateIndex);
370             if (nameAndDateLine.startsWith("Label:")) {
371                 nameAndDateIndex++;
372                 nameAndDateLine = (String JavaDoc) entry.get(nameAndDateIndex);
373                 LOG.debug("adjusting for the line that starts with Label");
374             }
375
376             Modification modification = new Modification("vss");
377             modification.userName = parseUser(nameAndDateLine);
378             modification.modifiedTime = parseDate(nameAndDateLine);
379
380             String JavaDoc folderLine = (String JavaDoc) entry.get(0);
381             int fileIndex = nameAndDateIndex + 1;
382             String JavaDoc fileLine = (String JavaDoc) entry.get(fileIndex);
383
384             if (fileLine.startsWith("Checked in")) {
385
386                 LOG.debug("this is a checkin");
387                 int commentIndex = fileIndex + 1;
388                 modification.comment = parseComment(entry, commentIndex);
389                 String JavaDoc fileName = folderLine.substring(7, folderLine.indexOf(" *"));
390                 String JavaDoc folderName = fileLine.substring(12);
391
392                 Modification.ModifiedFile modfile = modification.createModifiedFile(fileName, folderName);
393                 modfile.action = "checkin";
394
395             } else if (fileLine.endsWith("Created")) {
396                 modification.type = "create";
397                 LOG.debug("this folder was created");
398             } else {
399                 String JavaDoc fileName;
400                 String JavaDoc folderName;
401
402                 if (nameAndDateIndex == 1) {
403                     folderName = vssPath;
404                 } else {
405                     folderName = vssPath + "\\" + folderLine.substring(7, folderLine.indexOf(" *"));
406                 }
407                 int lastSpace = fileLine.lastIndexOf(" ");
408                 if (lastSpace != -1) {
409                     fileName = fileLine.substring(0, lastSpace);
410                 } else {
411                     fileName = fileLine;
412                     if (fileName.equals("Branched")) {
413                         LOG.debug("Branched file, ignoring as branch directory is handled separately");
414                         return null;
415                     }
416                 }
417
418                 Modification.ModifiedFile modfile = modification.createModifiedFile(fileName, folderName);
419
420                 if (fileLine.endsWith("added")) {
421                     modfile.action = "add";
422                     LOG.debug("this file was added");
423                 } else if (fileLine.endsWith("deleted")) {
424                     modfile.action = "delete";
425                     LOG.debug("this file was deleted");
426                     addPropertyOnDelete();
427                 } else if (fileLine.endsWith("destroyed")) {
428                     modfile.action = "destroy";
429                     LOG.debug("this file was destroyed");
430                     addPropertyOnDelete();
431                 } else if (fileLine.endsWith("recovered")) {
432                     modfile.action = "recover";
433                     LOG.debug("this file was recovered");
434                 } else if (fileLine.endsWith("shared")) {
435                     modfile.action = "share";
436                     LOG.debug("this file was shared");
437                 } else if (fileLine.endsWith("branched")) {
438                     modfile.action = "branch";
439                     LOG.debug("this file was branched");
440                 } else if (fileLine.indexOf(" renamed to ") != -1) {
441                     modfile.fileName = fileLine;
442                     modfile.action = "rename";
443                     LOG.debug("this file was renamed");
444                     addPropertyOnDelete();
445                 } else if (fileLine.startsWith("Labeled")) {
446                     LOG.debug("this is a label; ignoring this entry");
447                     return null;
448                 } else {
449                     LOG.debug("action for this vss entry (" + fileLine + ") is unknown");
450                 }
451             }
452
453             if (property != null) {
454                 properties.put(property, "true");
455                 LOG.debug("setting property " + property + " to be true");
456             }
457
458             LOG.debug(" ");
459
460             return modification;
461
462         } catch (RuntimeException JavaDoc e) {
463             LOG.fatal("RuntimeException handling VSS entry:");
464             for (int i = 0; i < entry.size(); i++) {
465                 LOG.fatal(entry.get(i));
466             }
467             throw e;
468         }
469     }
470
471     private void addPropertyOnDelete() {
472         if (propertyOnDelete != null) {
473             properties.put(propertyOnDelete, "true");
474             LOG.debug("setting property " + propertyOnDelete + " to be true");
475         }
476     }
477
478     /**
479      * Parse comment from VSS history (could be multi-line)
480      *
481      * @param commentList
482      * @return the comment
483      */

484     private String JavaDoc parseComment(List JavaDoc commentList, int commentIndex) {
485         StringBuffer JavaDoc comment = new StringBuffer JavaDoc();
486         comment.append(commentList.get(commentIndex)).append(" ");
487         for (int i = commentIndex + 1; i < commentList.size(); i++) {
488             comment.append(commentList.get(i)).append(" ");
489         }
490
491         return comment.toString().trim();
492     }
493
494     /**
495      * Parse date/time from VSS file history
496      *
497      * The nameAndDateLine will look like <br>
498      * <code>User: Etucker Date: 6/26/01 Time: 11:53a</code><br>
499      * Sometimes also this<br>
500      * <code>User: Aaggarwa Date: 6/29/:1 Time: 3:40p</code><br>
501      * Note the ":" instead of a "0"
502      *
503      * @param nameAndDateLine
504      * @return Date in form "'Date: 'MM/dd/yy 'Time: 'hh:mma", or a different form based on dateFormat
505      * @see #setDateFormat
506      */

507     public Date JavaDoc parseDate(String JavaDoc nameAndDateLine) {
508         String JavaDoc dateAndTime = nameAndDateLine.substring(nameAndDateLine.indexOf("Date: "));
509
510         int indexOfColon = dateAndTime.indexOf("/:");
511         if (indexOfColon != -1) {
512             dateAndTime = dateAndTime.substring(0, indexOfColon)
513                     + dateAndTime.substring(indexOfColon, indexOfColon + 2).replace(':', '0')
514                     + dateAndTime.substring(indexOfColon + 2);
515         }
516
517         try {
518             Date JavaDoc lastModifiedDate;
519             if (timeFormat.endsWith("a")) {
520                 lastModifiedDate = vssDateTimeFormat.parse(dateAndTime.trim() + "m");
521             } else {
522                 lastModifiedDate = vssDateTimeFormat.parse(dateAndTime.trim());
523             }
524
525             return lastModifiedDate;
526         } catch (ParseException JavaDoc pe) {
527             LOG.warn(pe);
528             return null;
529         }
530     }
531
532     /**
533      * Parse username from VSS file history
534      *
535      * @param userLine
536      * @return the user name who made the modification
537      */

538     public String JavaDoc parseUser(String JavaDoc userLine) {
539         final int userIndex = "User: ".length();
540
541         return userLine.substring(userIndex, userLine.indexOf("Date: ") - 1).trim();
542     }
543
544     /**
545      * Constructs the vssDateTimeFormat based on the dateFormat for this element.
546      *
547      * @see #setDateFormat
548      */

549     private void constructVssDateTimeFormat() {
550         vssDateTimeFormat = new SimpleDateFormat JavaDoc("'Date: '" + dateFormat + " 'Time: '" + timeFormat, Locale.US);
551     }
552
553     protected SimpleDateFormat JavaDoc getVssDateTimeFormat() {
554         return vssDateTimeFormat;
555     }
556
557 }
558
Popular Tags