| package org.apache.maven.scm.provider.hg.command; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import org.apache.maven.scm.ScmFileStatus; |
| import org.apache.maven.scm.log.ScmLogger; |
| import org.apache.maven.scm.util.AbstractConsumer; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * Base consumer to do common parsing for all hg commands. |
| * <p/> |
| * More specific: log line each line if debug is enabled, get file status |
| * and detect warnings from hg |
| * |
| * @author <a href="mailto:thurner.rupert@ymono.net">thurner rupert</a> |
| * |
| */ |
| public class HgConsumer |
| extends AbstractConsumer |
| { |
| |
| /** |
| * A list of known keywords from hg |
| */ |
| private static final Map<String, ScmFileStatus> IDENTIFIERS = new HashMap<String, ScmFileStatus>(); |
| |
| /** |
| * A list of known message prefixes from hg |
| */ |
| private static final Map<String, String> MESSAGES = new HashMap<String, String>(); |
| |
| /** |
| * Number of lines to keep from Std.Err |
| * This size is set to ensure that we capture enough info |
| * but still keeps a low memory footprint. |
| */ |
| private static final int MAX_STDERR_SIZE = 10; |
| |
| /** |
| * A list of the MAX_STDERR_SIZE last errors or warnings. |
| */ |
| private final List<String> stderr = new ArrayList<String>(); |
| |
| static |
| { |
| /** Statuses from hg add |
| */ |
| IDENTIFIERS.put( "adding", ScmFileStatus.ADDED ); |
| IDENTIFIERS.put( "unknown", ScmFileStatus.UNKNOWN ); |
| IDENTIFIERS.put( "modified", ScmFileStatus.MODIFIED ); |
| IDENTIFIERS.put( "removed", ScmFileStatus.DELETED ); |
| IDENTIFIERS.put( "renamed", ScmFileStatus.MODIFIED ); |
| |
| /** Statuses from hg status; |
| */ |
| IDENTIFIERS.put( "A", ScmFileStatus.ADDED ); |
| IDENTIFIERS.put( "?", ScmFileStatus.UNKNOWN ); |
| IDENTIFIERS.put( "M", ScmFileStatus.MODIFIED ); |
| IDENTIFIERS.put( "R", ScmFileStatus.DELETED ); |
| IDENTIFIERS.put( "C", ScmFileStatus.CHECKED_IN ); |
| IDENTIFIERS.put( "!", ScmFileStatus.MISSING ); |
| IDENTIFIERS.put( "I", ScmFileStatus.UNKNOWN ); // not precisely the same, but i think semantics work? - rwd |
| |
| MESSAGES.put( "hg: WARNING:", "WARNING" ); |
| MESSAGES.put( "hg: ERROR:", "ERROR" ); |
| MESSAGES.put( "'hg' ", "ERROR" ); // hg isn't found in windows path |
| } |
| |
| public HgConsumer( ScmLogger logger ) |
| { |
| super( logger ); |
| } |
| |
| public void doConsume( ScmFileStatus status, String trimmedLine ) |
| { |
| //override this |
| } |
| |
| /** {@inheritDoc} */ |
| public void consumeLine( String line ) |
| { |
| if ( getLogger().isDebugEnabled() ) |
| { |
| getLogger().debug( line ); |
| } |
| String trimmedLine = line.trim(); |
| |
| String statusStr = processInputForKnownIdentifiers( trimmedLine ); |
| |
| //If its not a status report - then maybe its a message? |
| if ( statusStr == null ) |
| { |
| boolean isMessage = processInputForKnownMessages( trimmedLine ); |
| //If it is then its already processed and we can ignore futher processing |
| if ( isMessage ) |
| { |
| return; |
| } |
| } |
| else |
| { |
| //Strip away identifier |
| trimmedLine = trimmedLine.substring( statusStr.length() ); |
| trimmedLine = trimmedLine.trim(); //one or more spaces |
| } |
| |
| ScmFileStatus status = statusStr != null ? ( (ScmFileStatus) IDENTIFIERS.get( statusStr.intern() ) ) : null; |
| doConsume( status, trimmedLine ); |
| } |
| |
| /** |
| * Warnings and errors is usually printed out in Std.Err, thus for derived consumers |
| * operating on Std.Out this would typically return an empty string. |
| * |
| * @return Return the last lines interpreted as an warning or an error |
| */ |
| public String getStdErr() |
| { |
| StringBuilder str = new StringBuilder(); |
| for ( Iterator<String> it = stderr.iterator(); it.hasNext(); ) |
| { |
| str.append( it.next() ); |
| } |
| return str.toString(); |
| } |
| |
| private static String processInputForKnownIdentifiers( String line ) |
| { |
| for ( Iterator<String> it = IDENTIFIERS.keySet().iterator(); it.hasNext(); ) |
| { |
| String id = it.next(); |
| if ( line.startsWith( id ) ) |
| { |
| return id; |
| } |
| } |
| return null; |
| } |
| |
| private boolean processInputForKnownMessages( String line ) |
| { |
| for ( Iterator<String> it = MESSAGES.keySet().iterator(); it.hasNext(); ) |
| { |
| String prefix = it.next(); |
| if ( line.startsWith( prefix ) ) |
| { |
| stderr.add( line ); //Add line |
| if ( stderr.size() > MAX_STDERR_SIZE ) |
| { |
| stderr.remove( 0 ); //Rotate list |
| } |
| String message = line.substring( prefix.length() ); |
| if ( MESSAGES.get( prefix ).equals( "WARNING" ) ) |
| { |
| if ( getLogger().isWarnEnabled() ) |
| { |
| getLogger().warn( message ); |
| } |
| } |
| else |
| { |
| if ( getLogger().isErrorEnabled() ) |
| { |
| getLogger().error( message ); |
| } |
| } |
| return true; |
| } |
| } |
| return false; |
| } |
| } |