View Javadoc
1   package org.apache.maven.scm.provider.bazaar.command;
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.ScmFileStatus;
23  import org.apache.maven.scm.log.ScmLogger;
24  import org.apache.maven.scm.util.AbstractConsumer;
25  
26  import java.util.ArrayList;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.Map;
31  
32  /**
33   * Base consumer to do common parsing for all bazaar commands.
34   * <p/>
35   * More specific: log line each line if debug is enabled, get file status
36   * and detect warnings from bazaar
37   *
38   * @author <a href="mailto:torbjorn@smorgrav.org">Torbj�rn Eikli Sm�rgrav</a>
39   *
40   */
41  public class BazaarConsumer
42      extends AbstractConsumer
43  {
44  
45      /**
46       * A list of known keywords from bazaar
47       */
48      private static final Map<String,ScmFileStatus> IDENTIFIERS = new HashMap<String,ScmFileStatus>();
49  
50      /**
51       * A list of known message prefixes from bazaar
52       */
53      private static final Map<String,String> MESSAGES = new HashMap<String,String>();
54  
55      /**
56       * Number of lines to keep from Std.Err
57       * This size is set to ensure that we capture enough info
58       * but still keeps a low memory footprint.
59       */
60      private static final int MAX_STDERR_SIZE = 10;
61  
62      /**
63       * A list of the MAX_STDERR_SIZE last errors or warnings.
64       */
65      private final List<String> stderr = new ArrayList<String>();
66  
67      static
68      {
69          IDENTIFIERS.put( "added", ScmFileStatus.ADDED );
70          IDENTIFIERS.put( "adding", ScmFileStatus.ADDED );
71          IDENTIFIERS.put( "unknown", ScmFileStatus.UNKNOWN );
72          IDENTIFIERS.put( "modified", ScmFileStatus.MODIFIED );
73          IDENTIFIERS.put( "removed", ScmFileStatus.DELETED );
74          IDENTIFIERS.put( "renamed", ScmFileStatus.RENAMED );
75          MESSAGES.put( "bzr: WARNING:", "WARNING" );
76          MESSAGES.put( "bzr: ERROR:", "ERROR" );
77          MESSAGES.put( "'bzr' ", "ERROR" ); // bzr isn't found in windows path
78      }
79  
80      public BazaarConsumer( ScmLogger logger )
81      {
82          super( logger );
83      }
84  
85      public void doConsume( ScmFileStatus status, String trimmedLine )
86      {
87          //override this
88      }
89  
90      /** {@inheritDoc} */
91      public void consumeLine( String line )
92      {
93          if ( getLogger().isDebugEnabled() )
94          {
95              getLogger().debug( line );
96          }
97          String trimmedLine = line.trim();
98  
99          String statusStr = processInputForKnownIdentifiers( trimmedLine );
100 
101         //If its not a status report - then maybe its a message?
102         if ( statusStr == null )
103         {
104             boolean isMessage = processInputForKnownMessages( trimmedLine );
105             //If it is then its already processed and we can ignore futher processing
106             if ( isMessage )
107             {
108                 return;
109             }
110         }
111         else
112         {
113             //Strip away identifier
114             trimmedLine = trimmedLine.substring( statusStr.length() );
115             trimmedLine = trimmedLine.trim(); //one or more spaces
116         }
117 
118         ScmFileStatus status = statusStr != null ? ( (ScmFileStatus) IDENTIFIERS.get( statusStr.intern() ) ) : null;
119         doConsume( status, trimmedLine );
120     }
121 
122     /**
123      * Warnings and errors is usually printed out in Std.Err, thus for derived consumers
124      * operating on Std.Out this would typically return an empty string.
125      *
126      * @return Return the last lines interpreted as an warning or an error
127      */
128     public String getStdErr()
129     {
130         StringBuilder str = new StringBuilder();
131         for ( Iterator<String> it = stderr.iterator(); it.hasNext(); )
132         {
133             str.append( it.next() );
134         }
135         return str.toString();
136     }
137 
138     private static String processInputForKnownIdentifiers( String line )
139     {
140         for ( Iterator<String> it = IDENTIFIERS.keySet().iterator(); it.hasNext(); )
141         {
142             String id = it.next();
143             if ( line.startsWith( id ) )
144             {
145                 return id;
146             }
147         }
148         return null;
149     }
150 
151     private boolean processInputForKnownMessages( String line )
152     {
153         for ( Iterator<String> it = MESSAGES.keySet().iterator(); it.hasNext(); )
154         {
155             String prefix = it.next();
156             if ( line.startsWith( prefix ) )
157             {
158                 stderr.add( line ); //Add line
159                 if ( stderr.size() > MAX_STDERR_SIZE )
160                 {
161                     stderr.remove( 0 ); //Rotate list
162                 }
163                 String message = line.substring( prefix.length() );
164                 if ( MESSAGES.get( prefix ).equals( "WARNING" ) )
165                 {
166                     if ( getLogger().isWarnEnabled() )
167                     {
168                         getLogger().warn( message );
169                     }
170                 }
171                 else
172                 {
173                     if ( getLogger().isErrorEnabled() )
174                     {
175                         getLogger().error( message );
176                     }
177                 }
178                 return true;
179             }
180         }
181         return false;
182     }
183 }