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.List; 029import java.util.Map; 030 031/** 032 * Base consumer to do common parsing for all bazaar commands. 033 * <p/> 034 * More specific: log line each line if debug is enabled, get file status 035 * and detect warnings from bazaar 036 * 037 * @author <a href="mailto:torbjorn@smorgrav.org">Torbjörn Eikli Smörgrav</a> 038 * 039 */ 040public class BazaarConsumer 041 extends AbstractConsumer 042{ 043 044 /** 045 * A list of known keywords from bazaar 046 */ 047 private static final Map<String, ScmFileStatus> IDENTIFIERS = new HashMap<String, ScmFileStatus>(); 048 049 /** 050 * A list of known message prefixes from bazaar 051 */ 052 private static final Map<String, String> MESSAGES = new HashMap<String, String>(); 053 054 /** 055 * Number of lines to keep from Std.Err 056 * This size is set to ensure that we capture enough info 057 * but still keeps a low memory footprint. 058 */ 059 private static final int MAX_STDERR_SIZE = 10; 060 061 /** 062 * A list of the MAX_STDERR_SIZE last errors or warnings. 063 */ 064 private final List<String> stderr = new ArrayList<String>(); 065 066 static 067 { 068 IDENTIFIERS.put( "added", ScmFileStatus.ADDED ); 069 IDENTIFIERS.put( "adding", ScmFileStatus.ADDED ); 070 IDENTIFIERS.put( "unknown", ScmFileStatus.UNKNOWN ); 071 IDENTIFIERS.put( "modified", ScmFileStatus.MODIFIED ); 072 IDENTIFIERS.put( "removed", ScmFileStatus.DELETED ); 073 IDENTIFIERS.put( "renamed", ScmFileStatus.RENAMED ); 074 MESSAGES.put( "bzr: WARNING:", "WARNING" ); 075 MESSAGES.put( "bzr: ERROR:", "ERROR" ); 076 MESSAGES.put( "'bzr' ", "ERROR" ); // bzr isn't found in windows path 077 } 078 079 public BazaarConsumer( ScmLogger logger ) 080 { 081 super( logger ); 082 } 083 084 public void doConsume( ScmFileStatus status, String trimmedLine ) 085 { 086 //override this 087 } 088 089 /** {@inheritDoc} */ 090 public void consumeLine( String line ) 091 { 092 if ( getLogger().isDebugEnabled() ) 093 { 094 getLogger().debug( line ); 095 } 096 String trimmedLine = line.trim(); 097 098 String statusStr = processInputForKnownIdentifiers( trimmedLine ); 099 100 //If its not a status report - then maybe its a message? 101 if ( statusStr == null ) 102 { 103 boolean isMessage = processInputForKnownMessages( trimmedLine ); 104 //If it is then its already processed and we can ignore futher processing 105 if ( isMessage ) 106 { 107 return; 108 } 109 } 110 else 111 { 112 //Strip away identifier 113 trimmedLine = trimmedLine.substring( statusStr.length() ); 114 trimmedLine = trimmedLine.trim(); //one or more spaces 115 } 116 117 ScmFileStatus status = statusStr != null ? ( (ScmFileStatus) IDENTIFIERS.get( statusStr.intern() ) ) : null; 118 doConsume( status, trimmedLine ); 119 } 120 121 /** 122 * Warnings and errors is usually printed out in Std.Err, thus for derived consumers 123 * operating on Std.Out this would typically return an empty string. 124 * 125 * @return Return the last lines interpreted as an warning or an error 126 */ 127 public String getStdErr() 128 { 129 StringBuilder str = new StringBuilder(); 130 for ( String line : stderr ) 131 { 132 str.append( line ); 133 } 134 return str.toString(); 135 } 136 137 private static String processInputForKnownIdentifiers( String line ) 138 { 139 for ( String id : IDENTIFIERS.keySet() ) 140 { 141 if ( line.startsWith( id ) ) 142 { 143 return id; 144 } 145 } 146 return null; 147 } 148 149 private boolean processInputForKnownMessages( String line ) 150 { 151 for ( String prefix : MESSAGES.keySet() ) 152 { 153 if ( line.startsWith( prefix ) ) 154 { 155 stderr.add( line ); //Add line 156 if ( stderr.size() > MAX_STDERR_SIZE ) 157 { 158 stderr.remove( 0 ); //Rotate list 159 } 160 String message = line.substring( prefix.length() ); 161 if ( MESSAGES.get( prefix ).equals( "WARNING" ) ) 162 { 163 if ( getLogger().isWarnEnabled() ) 164 { 165 getLogger().warn( message ); 166 } 167 } 168 else 169 { 170 if ( getLogger().isErrorEnabled() ) 171 { 172 getLogger().error( message ); 173 } 174 } 175 return true; 176 } 177 } 178 return false; 179 } 180}