001 package org.apache.maven.scm.provider.bazaar.command;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import org.apache.maven.scm.ScmFileStatus;
023 import org.apache.maven.scm.log.ScmLogger;
024 import org.apache.maven.scm.util.AbstractConsumer;
025
026 import java.util.ArrayList;
027 import java.util.HashMap;
028 import java.util.Iterator;
029 import java.util.List;
030 import java.util.Map;
031
032 /**
033 * Base consumer to do common parsing for all bazaar commands.
034 * <p/>
035 * More specific: log line each line if debug is enabled, get file status
036 * and detect warnings from bazaar
037 *
038 * @author <a href="mailto:torbjorn@smorgrav.org">Torbj�rn Eikli Sm�rgrav</a>
039 *
040 */
041 public class BazaarConsumer
042 extends AbstractConsumer
043 {
044
045 /**
046 * A list of known keywords from bazaar
047 */
048 private static final Map<String,ScmFileStatus> IDENTIFIERS = new HashMap<String,ScmFileStatus>();
049
050 /**
051 * A list of known message prefixes from bazaar
052 */
053 private static final Map<String,String> MESSAGES = new HashMap<String,String>();
054
055 /**
056 * Number of lines to keep from Std.Err
057 * This size is set to ensure that we capture enough info
058 * but still keeps a low memory footprint.
059 */
060 private static final int MAX_STDERR_SIZE = 10;
061
062 /**
063 * A list of the MAX_STDERR_SIZE last errors or warnings.
064 */
065 private final List<String> stderr = new ArrayList<String>();
066
067 static
068 {
069 IDENTIFIERS.put( "added", ScmFileStatus.ADDED );
070 IDENTIFIERS.put( "adding", ScmFileStatus.ADDED );
071 IDENTIFIERS.put( "unknown", ScmFileStatus.UNKNOWN );
072 IDENTIFIERS.put( "modified", ScmFileStatus.MODIFIED );
073 IDENTIFIERS.put( "removed", ScmFileStatus.DELETED );
074 IDENTIFIERS.put( "renamed", ScmFileStatus.RENAMED );
075 MESSAGES.put( "bzr: WARNING:", "WARNING" );
076 MESSAGES.put( "bzr: ERROR:", "ERROR" );
077 MESSAGES.put( "'bzr' ", "ERROR" ); // bzr isn't found in windows path
078 }
079
080 public BazaarConsumer( ScmLogger logger )
081 {
082 super( logger );
083 }
084
085 public void doConsume( ScmFileStatus status, String trimmedLine )
086 {
087 //override this
088 }
089
090 /** {@inheritDoc} */
091 public void consumeLine( String line )
092 {
093 if ( getLogger().isDebugEnabled() )
094 {
095 getLogger().debug( line );
096 }
097 String trimmedLine = line.trim();
098
099 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 }