View Javadoc

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