View Javadoc

1   package org.apache.maven.scm.provider.starteam.command.changelog;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.scm.ChangeFile;
23  import org.apache.maven.scm.ChangeSet;
24  import org.apache.maven.scm.log.ScmLogger;
25  import org.apache.maven.scm.provider.starteam.command.StarteamCommandLineUtils;
26  import org.apache.maven.scm.util.AbstractConsumer;
27  
28  import java.io.File;
29  import java.text.SimpleDateFormat;
30  import java.util.ArrayList;
31  import java.util.Date;
32  import java.util.List;
33  
34  /**
35   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
36   * @version $Id: StarteamChangeLogConsumer.java 483105 2006-12-06 15:07:54Z evenisse $
37   */
38  public class StarteamChangeLogConsumer
39      extends AbstractConsumer
40  {
41      private SimpleDateFormat localFormat = new SimpleDateFormat();
42  
43      private List entries = new ArrayList();
44  
45      private String workingDirectory;
46  
47      private String currentDir = "";
48  
49      // state machine constants for reading Starteam output
50  
51      /**
52       * expecting file information
53       */
54      private static final int GET_FILE = 1;
55  
56      /**
57       * expecting date
58       */
59      private static final int GET_AUTHOR = 2;
60  
61      /**
62       * expecting comments
63       */
64      private static final int GET_COMMENT = 3;
65  
66      /**
67       * expecting revision
68       */
69      private static final int GET_REVISION = 4;
70  
71  
72      /**
73       * Marks current directory data
74       */
75      private static final String DIR_MARKER = "(working dir: ";
76  
77      /**
78       * Marks start of file data
79       */
80      private static final String START_FILE = "History for: ";
81  
82  
83      /**
84       * Marks end of file
85       */
86      private static final String END_FILE =
87          "===================================" + "==========================================";
88  
89      /**
90       * Marks start of revision
91       */
92      private static final String START_REVISION = "----------------------------";
93  
94      /**
95       * Marks revision data
96       */
97      private static final String REVISION_TAG = "Branch Revision: ";
98  
99      /**
100      * Marks author data
101      */
102     private static final String AUTHOR_TAG = "Author: ";
103 
104     /**
105      * Marks date data
106      */
107     private static final String DATE_TAG = " Date: ";
108 
109     /**
110      * current status of the parser
111      */
112     private int status = GET_FILE;
113 
114     /**
115      * the current log entry being processed by the parser
116      */
117     private ChangeSet currentChange = null;
118 
119     /**
120      * the current file being processed by the parser
121      */
122     private ChangeFile currentFile = null;
123 
124     /**
125      * the before date
126      */
127     private Date startDate;
128 
129     /**
130      * the to date
131      */
132     private Date endDate;
133 
134     private String userDateFormat;
135 
136     // ----------------------------------------------------------------------
137     //
138     // ----------------------------------------------------------------------
139 
140     public StarteamChangeLogConsumer( File workingDirectory, ScmLogger logger, Date startDate, Date endDate,
141                                       String userDateFormat )
142     {
143         super( logger );
144 
145         this.workingDirectory = workingDirectory.getPath().replace( '\\', '/' );
146 
147         this.startDate = startDate;
148 
149         this.endDate = endDate;
150 
151         this.userDateFormat = userDateFormat;
152 
153         //work around for all en_US compatible locales, where Starteam
154         // stcmd hist output uses a different format, ugly eh?
155         // makesure to change the test file as well if this ever got fixed
156 
157         if ( "M/d/yy h:mm a".equals( localFormat.toLocalizedPattern() ) )
158         {
159             this.localFormat = new SimpleDateFormat( "M/d/yy h:mm:ss a z" );
160         }
161     }
162 
163     // ----------------------------------------------------------------------
164     //
165     // ----------------------------------------------------------------------
166 
167     public List getModifications()
168     {
169         return entries;
170     }
171 
172     // ----------------------------------------------------------------------
173     // StreamConsumer Implementation
174     // ----------------------------------------------------------------------
175 
176     public void consumeLine( String line )
177     {
178         getLogger().debug( line );
179 
180         int pos = 0;
181 
182         if ( ( pos = line.indexOf( DIR_MARKER ) ) != -1 )
183         {
184             processDirectory( line, pos );
185             return;
186         }
187 
188         // current state transitions in the state machine - starts with Get File
189         //      Get File                -> Get Revision
190         //      Get Revision            -> Get Date or Get File
191         //      Get Date                -> Get Comment
192         //      Get Comment             -> Get Comment or Get Revision
193         switch ( getStatus() )
194         {
195             case GET_FILE:
196                 processGetFile( line );
197                 break;
198             case GET_REVISION:
199                 processGetRevision( line );
200                 break;
201             case GET_AUTHOR:
202                 processGetAuthor( line );
203                 break;
204             case GET_COMMENT:
205                 processGetComment( line );
206                 break;
207             default:
208                 throw new IllegalStateException( "Unknown state: " + status );
209         }
210     }
211 
212     // ----------------------------------------------------------------------
213     //
214     // ----------------------------------------------------------------------
215 
216     /**
217      * Add a change log entry to the list (if it's not already there)
218      * with the given file.
219      *
220      * @param entry a {@link ChangeSet} to be added to the list if another
221      *              with the same key doesn't exist already. If the entry's author
222      *              is null, the entry wont be added
223      * @param file  a {@link ChangeFile} to be added to the entry
224      */
225     private void addEntry( ChangeSet entry, ChangeFile file )
226     {
227         // do not add if entry is not populated
228         if ( entry.getAuthor() == null )
229         {
230             return;
231         }
232 
233         // do not add if entry is out of date range
234         if ( startDate != null && entry.getDate().before( startDate ) )
235         {
236             return;
237         }
238 
239         if ( endDate != null && entry.getDate().after( endDate ) )
240         {
241             return;
242         }
243 
244         entry.addFile( file );
245 
246         entries.add( entry );
247     }
248 
249     private void processDirectory( String line, int pos )
250     {
251         String dirPath = line.substring( pos + DIR_MARKER.length(), line.length() - 1 ).replace( '\\', '/' );
252         try
253         {
254             this.currentDir = StarteamCommandLineUtils.getRelativeChildDirectory( this.workingDirectory, dirPath );
255         }
256         catch ( IllegalStateException e )
257         {
258             String error = "Working and checkout directories are not on the same tree";
259 
260             this.getLogger().error( error );
261 
262             this.getLogger().error( "Working directory: " + workingDirectory );
263 
264             this.getLogger().error( "Checked out directory: " + dirPath );
265 
266             throw new IllegalStateException( error );
267         }
268     }
269 
270     /**
271      * Process the current input line in the Get File state.
272      *
273      * @param line a line of text from the Starteam log output
274      */
275     private void processGetFile( String line )
276     {
277         if ( line.startsWith( START_FILE ) )
278         {
279             setCurrentChange( new ChangeSet() );
280 
281             setCurrentFile(
282                 new ChangeFile( this.currentDir + "/" + line.substring( START_FILE.length(), line.length() ) ) );
283 
284             setStatus( GET_REVISION );
285         }
286     }
287 
288     /**
289      * Process the current input line in the Get Revision state.
290      *
291      * @param line a line of text from the Starteam log output
292      */
293     private void processGetRevision( String line )
294     {
295         int pos;
296 
297         if ( ( pos = line.indexOf( REVISION_TAG ) ) != -1 )
298         {
299             getCurrentFile().setRevision( line.substring( pos + REVISION_TAG.length() ) );
300 
301             setStatus( GET_AUTHOR );
302         }
303         else if ( line.startsWith( END_FILE ) )
304         {
305             // If we encounter an end of file line, it means there
306             // are no more revisions for the current file.
307             // there could also be a file still being processed.
308             setStatus( GET_FILE );
309 
310             addEntry( getCurrentChange(), getCurrentFile() );
311         }
312     }
313 
314     /**
315      * Process the current input line in the Get Author/Date state.
316      *
317      * @param line a line of text from the Starteam log output
318      */
319     private void processGetAuthor( String line )
320     {
321         if ( line.startsWith( AUTHOR_TAG ) )
322         {
323             int posDateTag = line.indexOf( DATE_TAG );
324 
325             String author = line.substring( AUTHOR_TAG.length(), posDateTag );
326 
327             getCurrentChange().setAuthor( author );
328 
329             String date = line.substring( posDateTag + DATE_TAG.length() );
330 
331             Date dateObj = parseDate( date, userDateFormat, localFormat.toPattern() );
332 
333             if ( dateObj != null )
334             {
335                 getCurrentChange().setDate( dateObj );
336             }
337             else
338             {
339                 getCurrentChange().setDate( date, userDateFormat );
340             }
341 
342             setStatus( GET_COMMENT );
343         }
344     }
345 
346     /**
347      * Process the current input line in the Get Comment state.
348      *
349      * @param line a line of text from the Starteam log output
350      */
351     private void processGetComment( String line )
352     {
353         if ( line.startsWith( START_REVISION ) )
354         {
355             // add entry, and set state to get revision
356             addEntry( getCurrentChange(), getCurrentFile() );
357 
358             // new change log entry
359             setCurrentChange( new ChangeSet() );
360 
361             // same file name, but different rev
362             setCurrentFile( new ChangeFile( getCurrentFile().getName() ) );
363 
364             setStatus( GET_REVISION );
365         }
366         else if ( line.startsWith( END_FILE ) )
367         {
368             addEntry( getCurrentChange(), getCurrentFile() );
369 
370             setStatus( GET_FILE );
371         }
372         else
373         {
374             // keep gathering comments
375             getCurrentChange().setComment( getCurrentChange().getComment() + line + "\n" );
376         }
377     }
378 
379     /**
380      * Getter for property currentFile.
381      *
382      * @return Value of property currentFile.
383      */
384     private ChangeFile getCurrentFile()
385     {
386         return currentFile;
387     }
388 
389     /**
390      * Setter for property currentFile.
391      *
392      * @param currentFile New value of property currentFile.
393      */
394     private void setCurrentFile( ChangeFile currentFile )
395     {
396         this.currentFile = currentFile;
397     }
398 
399     /**
400      * Getter for property currentChange.
401      *
402      * @return Value of property currentChange.
403      */
404     private ChangeSet getCurrentChange()
405     {
406         return currentChange;
407     }
408 
409     /**
410      * Setter for property currentChange.
411      *
412      * @param currentChange New value of property currentChange.
413      */
414     private void setCurrentChange( ChangeSet currentChange )
415     {
416         this.currentChange = currentChange;
417     }
418 
419     /**
420      * Getter for property status.
421      *
422      * @return Value of property status.
423      */
424     private int getStatus()
425     {
426         return status;
427     }
428 
429     /**
430      * Setter for property status.
431      *
432      * @param status New value of property status.
433      */
434     private void setStatus( int status )
435     {
436         this.status = status;
437     }
438 }