001package 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 022import org.apache.maven.scm.ScmFileStatus; 023import org.apache.maven.scm.log.ScmLogger; 024import org.apache.maven.scm.util.AbstractConsumer; 025 026import java.util.ArrayList; 027import java.util.HashMap; 028import java.util.Iterator; 029import java.util.List; 030import 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 */ 041public 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}