View Javadoc
1   package org.apache.maven.scm.provider.tfs.command.consumer;
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 java.text.DateFormat;
23  import java.text.ParseException;
24  import java.util.ArrayList;
25  import java.util.Date;
26  import java.util.List;
27  import java.util.Locale;
28  import java.util.TimeZone;
29  import java.util.regex.Matcher;
30  import java.util.regex.Pattern;
31  
32  import org.apache.maven.scm.ChangeFile;
33  import org.apache.maven.scm.ChangeSet;
34  import org.apache.maven.scm.log.ScmLogger;
35  import org.apache.maven.scm.util.AbstractConsumer;
36  
37  /**
38   * @author Olivier Lamy
39   *
40   */
41  public class TfsChangeLogConsumer
42      extends AbstractConsumer
43  {
44  
45      private static final String PATTERN =
46          "^[^:]*:[ \t]([0-9]*)\n" + "[^:]*:[ \t](.*)\n[^:]*:[ \t](.*)\n"
47              + "[^:]*:((?:\n.*)*)\n\n[^\n :]*:(?=\n  )((?:\n[ \t]+.*)*)";
48  
49      private static final String PATTERN_ITEM = "\n  ([^$]+) (\\$/.*)";
50  
51      private List<ChangeSet> logs = new ArrayList<ChangeSet>();
52  
53      private String buffer = "";
54  
55      boolean fed = false;
56  
57      public TfsChangeLogConsumer( ScmLogger logger )
58      {
59          super( logger );
60      }
61  
62      public void consumeLine( String line )
63      {
64          fed = true;
65          if ( line.startsWith( "-----" ) )
66          {
67              addChangeLog();
68          }
69          buffer += line + "\n";
70      }
71  
72      public List<ChangeSet> getLogs()
73      {
74          addChangeLog();
75          return logs;
76      }
77  
78      private void addChangeLog()
79      {
80          if ( !buffer.equals( "" ) )
81          {
82              Pattern p = Pattern.compile( PATTERN );
83              Matcher m = p.matcher( buffer );
84              if ( m.find() )
85              {
86                  String revision = m.group( 1 ).trim();
87                  String username = m.group( 2 ).trim();
88                  String dateString = m.group( 3 ).trim();
89                  String comment = m.group( 4 ).trim();
90                  Pattern itemPattern = Pattern.compile( PATTERN_ITEM );
91                  Matcher itemMatcher = itemPattern.matcher( m.group( 5 ) );
92                  List<ChangeFile> files = new ArrayList<ChangeFile>();
93                  while ( itemMatcher.find() )
94                  {
95                      ChangeFile file = new ChangeFile( itemMatcher.group( 2 ).trim(), revision );
96                      files.add( file );
97                  }
98                  Date date;
99                  try
100                 {
101                     date = parseDate( dateString );
102                 }
103                 catch ( ParseException e )
104                 {
105                     getLogger().error( "Date parse error", e );
106                     throw new RuntimeException( e );
107                 }
108 
109                 ChangeSet change = new ChangeSet( date, comment, username, files );
110                 logs.add( change );
111             }
112             buffer = "";
113         }
114     }
115 
116     public boolean hasBeenFed()
117     {
118         return fed;
119     }
120 
121     @SuppressWarnings( "deprecation" )
122     protected static Date parseDate( String dateString )
123         throws ParseException
124     {
125         Date date = null;
126         try
127         {
128             // Use the depricated Date.parse method as this is very good at
129             // detecting
130             // dates commonly output by the US and UK standard locales of
131             // dotnet that
132             // are output by the Microsoft command line client.
133             date = new Date( Date.parse( dateString ) );
134         }
135         catch ( IllegalArgumentException e )
136         {
137             // ignore - parse failed.
138         }
139         if ( date == null )
140         {
141             // The old fashioned way did not work. Let's try it using a more
142             // complex
143             // alternative.
144             DateFormat[] formats = createDateFormatsForLocaleAndTimeZone( null, null );
145             return parseWithFormats( dateString, formats );
146         }
147         return date;
148     }
149 
150     private static Date parseWithFormats( String input, DateFormat[] formats )
151         throws ParseException
152     {
153         ParseException parseException = null;
154         for ( int i = 0; i < formats.length; i++ )
155         {
156             try
157             {
158                 return formats[i].parse( input );
159             }
160             catch ( ParseException ex )
161             {
162                 parseException = ex;
163             }
164         }
165 
166         throw parseException;
167     }
168 
169     /**
170      * Build an array of DateFormats that are commonly used for this locale and timezone.
171      */
172     private static DateFormat[] createDateFormatsForLocaleAndTimeZone( Locale locale, TimeZone timeZone )
173     {
174         if ( locale == null )
175         {
176             locale = Locale.getDefault();
177         }
178 
179         if ( timeZone == null )
180         {
181             timeZone = TimeZone.getDefault();
182         }
183 
184         List<DateFormat> formats = new ArrayList<DateFormat>();
185 
186         for ( int dateStyle = DateFormat.FULL; dateStyle <= DateFormat.SHORT; dateStyle++ )
187         {
188             for ( int timeStyle = DateFormat.FULL; timeStyle <= DateFormat.SHORT; timeStyle++ )
189             {
190                 DateFormat df = DateFormat.getDateTimeInstance( dateStyle, timeStyle, locale );
191                 if ( timeZone != null )
192                 {
193                     df.setTimeZone( timeZone );
194                 }
195                 formats.add( df );
196             }
197         }
198 
199         for ( int dateStyle = DateFormat.FULL; dateStyle <= DateFormat.SHORT; dateStyle++ )
200         {
201             DateFormat df = DateFormat.getDateInstance( dateStyle, locale );
202             df.setTimeZone( timeZone );
203             formats.add( df );
204         }
205 
206         return (DateFormat[]) formats.toArray( new DateFormat[formats.size()] );
207     }
208 
209 }