001 package org.apache.maven.scm.provider.jazz.command.status; 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.ScmFile; 023 import org.apache.maven.scm.ScmFileStatus; 024 import org.apache.maven.scm.log.ScmLogger; 025 import org.apache.maven.scm.provider.ScmProviderRepository; 026 import org.apache.maven.scm.provider.jazz.command.consumer.AbstractRepositoryConsumer; 027 import org.apache.maven.scm.provider.jazz.repository.JazzScmProviderRepository; 028 import org.apache.regexp.RE; 029 import org.apache.regexp.RESyntaxException; 030 031 import java.util.ArrayList; 032 import java.util.List; 033 034 /** 035 * Consume the output of the scm command for the "status" operation. 036 * <p/> 037 * It is normally just used to build up a list of ScmFile objects that have 038 * their ScmFileStatus set. 039 * This class has been expanded so that the Workspace, Component and Baseline 040 * are also collected and set back in the JazzScmProviderRepository. 041 * The Workspace and Component names are needed for some other commands (list, 042 * for example), so we can easily get this information here. 043 * 044 * @author <a href="mailto:ChrisGWarp@gmail.com">Chris Graham</a> 045 */ 046 public class JazzStatusConsumer 047 extends AbstractRepositoryConsumer 048 { 049 // We have have a workspace with no flow targets (it points to itself) 050 // 051 // Workspace: (1000) "BogusRepositoryWorkspace" <-> (1000) "BogusRepositoryWorkspace" 052 // Component: (1001) "BogusComponent" 053 // Baseline: (1128) 27 "BogusTestJazz-3.0.0.40" 054 // Unresolved: 055 // d-- /BogusTest/pom.xml.releaseBackup 056 // d-- /BogusTest/release.properties 057 // 058 // Or, we have have one that does have a flow target (ie a stream or another workspace). 059 // 060 // Workspace: (1156) "GPDBWorkspace" <-> (1157) "GPDBStream" 061 // Component: (1158) "GPDB" <-> (1157) "GPDBStream" 062 // Baseline: (1159) 1 "Initial Baseline" 063 // 064 // Note the (%d) numbers are aliases and are only valid for the machine/instance that made the 065 // remote calls to the server. They are not to be shared across machines (ie don't make them global, public 066 // or persistent). 067 // 068 069 // Workspace: (1000) "BogusRepositoryWorkspace" <-> (1000) "BogusRepositoryWorkspace" 070 // Workspace: (1156) "GPDBWorkspace" <-> (1157) "GPDBStream" 071 private static final String WORKSPACE_PATTERN = "\\((\\d+)\\) \"(.*)\" <-> \\((\\d+)\\) \"(.*)\""; 072 073 /** 074 * @see #WORKSPACE_PATTERN 075 */ 076 private RE workspaceRegExp; 077 078 // Component: (1001) "BogusComponent" 079 private static final String COMPONENT_PATTERN1 = "\\((\\d+)\\) \"(.*)\""; 080 081 /** 082 * @see #COMPONENT_PATTERN1 083 */ 084 private RE componentRegExp1; 085 086 // Component: (1158) "GPDB" <-> (1157) "GPDBStream" 087 // Component: (1002) "FireDragon" <-> (1005) "MavenR3Stream Workspace" (outgoing addition) 088 private static final String COMPONENT_PATTERN2 = "\\((\\d+)\\) \"(.*)\" <.*>"; 089 090 /** 091 * @see #COMPONENT_PATTERN2 092 */ 093 private RE componentRegExp2; 094 095 // Baseline: (1128) 27 "BogusTestJazz-3.0.0.40" 096 private static final String BASELINE_PATTERN = "\\((\\d+)\\) (\\d+) \"(.*)\""; 097 098 /** 099 * @see #BASELINE_PATTERN 100 */ 101 private RE baselineRegExp; 102 103 // Additional data we collect. (eye catchers) 104 105 /** 106 * The "Status" command output line that contains the "Workspace" name. 107 */ 108 public static final String STATUS_CMD_WORKSPACE = "Workspace:"; 109 110 /** 111 * The "Status" command output line that contains the "Component" name. 112 */ 113 public static final String STATUS_CMD_COMPONENT = "Component:"; 114 115 /** 116 * The "Status" command output line that contains the "Workspace" name. 117 */ 118 public static final String STATUS_CMD_BASELINE = "Baseline:"; 119 120 // File Status Commands (eye catchers) 121 122 /** 123 * The "Status" command status flag for a resource that has been added. 124 */ 125 public static final String STATUS_CMD_ADD_FLAG = "a-"; 126 127 /** 128 * The "Status" command status flag for when the content or properties of 129 * a file have been modified, or the properties of a directory have changed. 130 */ 131 public static final String STATUS_CMD_CHANGE_FLAG = "-c"; 132 133 /** 134 * The "Status" command status flag for a resource that has been deleted. 135 */ 136 public static final String STATUS_CMD_DELETE_FLAG = "d-"; 137 138 /** 139 * The "Status" command status flag for a resource that has been renamed or moved. 140 */ 141 public static final String STATUS_CMD_MOVED_FLAG = "m-"; 142 143 /** 144 * A List of ScmFile objects that have their ScmFileStatus set. 145 */ 146 private List<ScmFile> fChangedFiles = new ArrayList<ScmFile>(); 147 148 /** 149 * Constructor for our "scm status" consumer. 150 * 151 * @param repo The JazzScmProviderRepository being used. 152 * @param logger The ScmLogger to use. 153 */ 154 public JazzStatusConsumer( ScmProviderRepository repo, ScmLogger logger ) 155 { 156 super( repo, logger ); 157 158 try 159 { 160 workspaceRegExp = new RE( WORKSPACE_PATTERN ); 161 componentRegExp1 = new RE( COMPONENT_PATTERN1 ); 162 componentRegExp2 = new RE( COMPONENT_PATTERN2 ); 163 baselineRegExp = new RE( BASELINE_PATTERN ); 164 } 165 catch ( RESyntaxException ex ) 166 { 167 throw new RuntimeException( 168 "INTERNAL ERROR: Could not create regexp to parse jazz scm status output. This shouldn't happen. Something is probably wrong with the oro installation.", 169 ex ); 170 } 171 } 172 173 /** 174 * Process one line of output from the execution of the "scm status" command. 175 * 176 * @param line The line of output from the external command that has been pumped to us. 177 * @see org.codehaus.plexus.util.cli.StreamConsumer#consumeLine(java.lang.String) 178 */ 179 public void consumeLine( String line ) 180 { 181 super.consumeLine( line ); 182 if ( containsWorkspace( line ) ) 183 { 184 extractWorkspace( line ); 185 } 186 if ( containsComponent( line ) ) 187 { 188 extractComponent( line ); 189 } 190 if ( containsBaseline( line ) ) 191 { 192 extractBaseline( line ); 193 } 194 if ( containsStatusFlag( line ) ) 195 { 196 extractChangedFile( line ); 197 } 198 } 199 200 private boolean containsWorkspace( String line ) 201 { 202 return line.trim().startsWith( STATUS_CMD_WORKSPACE ); 203 } 204 205 private void extractWorkspace( String line ) 206 { 207 // With no stream (flow target): 208 // Workspace: (1000) "BogusRepositoryWorkspace" <-> (1000) "BogusRepositoryWorkspace" 209 // With a stream: 210 // Workspace: (1156) "GPDBWorkspace" <-> (1157) "GPDBStream" 211 212 if ( workspaceRegExp.match( line ) ) 213 { 214 JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository(); 215 216 int workspaceAlias = Integer.parseInt( workspaceRegExp.getParen( 1 ) ); 217 String workspace = workspaceRegExp.getParen( 2 ); 218 int streamAlias = Integer.parseInt( workspaceRegExp.getParen( 3 ) ); 219 String stream = workspaceRegExp.getParen( 4 ); 220 if ( getLogger().isDebugEnabled() ) 221 { 222 getLogger().debug( "Successfully parsed \"Workspace:\" line:" ); 223 getLogger().debug( " workspaceAlias = " + workspaceAlias ); 224 getLogger().debug( " workspace = " + workspace ); 225 getLogger().debug( " streamAlias = " + streamAlias ); 226 getLogger().debug( " stream = " + stream ); 227 } 228 jazzRepository.setWorkspaceAlias( workspaceAlias ); 229 jazzRepository.setWorkspace( workspace ); 230 jazzRepository.setFlowTargetAlias( streamAlias ); 231 jazzRepository.setFlowTarget( stream ); 232 } 233 } 234 235 private boolean containsComponent( String line ) 236 { 237 return line.trim().startsWith( STATUS_CMD_COMPONENT ); 238 } 239 240 private void extractComponent( String line ) 241 { 242 // With no stream (flow target): 243 // Component: (1001) "BogusComponent" 244 // With a stream: 245 // Component: (1158) "GPDB" <-> (1157) "GPDBStream" 246 // With some additional information: 247 // Component: (1002) "FireDragon" <-> (1005) "MavenR3Stream Workspace" (outgoing addition) 248 249 if ( componentRegExp1.match( line ) ) 250 { 251 // Component: (1001) "BogusComponent" 252 JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository(); 253 int componentAlias = Integer.parseInt( componentRegExp1.getParen( 1 ) ); 254 String component = componentRegExp1.getParen( 2 ); 255 if ( getLogger().isDebugEnabled() ) 256 { 257 getLogger().debug( "Successfully parsed \"Component:\" line:" ); 258 getLogger().debug( " componentAlias = " + componentAlias ); 259 getLogger().debug( " component = " + component ); 260 } 261 jazzRepository.setComponent( component ); 262 } 263 264 if ( componentRegExp2.match( line ) ) 265 { 266 // Component: (1158) "GPDB" <-> (1157) "GPDBStream" 267 JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository(); 268 int componentAlias = Integer.parseInt( componentRegExp2.getParen( 1 ) ); 269 String component = componentRegExp2.getParen( 2 ); 270 if ( getLogger().isDebugEnabled() ) 271 { 272 getLogger().debug( "Successfully parsed \"Component:\" line:" ); 273 getLogger().debug( " componentAlias = " + componentAlias ); 274 getLogger().debug( " component = " + component ); 275 } 276 jazzRepository.setComponent( component ); 277 } 278 } 279 280 private boolean containsBaseline( String line ) 281 { 282 return line.trim().startsWith( STATUS_CMD_BASELINE ); 283 } 284 285 private void extractBaseline( String line ) 286 { 287 // Baseline: (1128) 27 "BogusTestJazz-3.0.0.40" 288 289 if ( baselineRegExp.match( line ) ) 290 { 291 JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository(); 292 293 int baselineAlias = Integer.parseInt( baselineRegExp.getParen( 1 ) ); 294 int baselineId = Integer.parseInt( baselineRegExp.getParen( 2 ) ); 295 String baseline = baselineRegExp.getParen( 3 ); 296 if ( getLogger().isDebugEnabled() ) 297 { 298 getLogger().debug( "Successfully parsed \"Baseline:\" line:" ); 299 getLogger().debug( " baselineAlias = " + baselineAlias ); 300 getLogger().debug( " baselineId = " + baselineId ); 301 getLogger().debug( " baseline = " + baseline ); 302 } 303 jazzRepository.setBaseline( baseline ); 304 } 305 } 306 307 private boolean containsStatusFlag( String line ) 308 { 309 boolean containsStatusFlag = false; 310 311 if ( line.trim().length() > 2 ) 312 { 313 String flag = line.trim().substring( 0, 2 ); 314 if ( STATUS_CMD_ADD_FLAG.equals( flag ) || 315 STATUS_CMD_CHANGE_FLAG.equals( flag ) || 316 STATUS_CMD_DELETE_FLAG.equals( flag ) ) 317 { 318 containsStatusFlag = true; 319 } 320 } 321 return containsStatusFlag; 322 } 323 324 private void extractChangedFile( String line ) 325 { 326 String flag = line.trim().substring( 0, 2 ); 327 String filePath = line.trim().substring( 3 ).trim(); 328 ScmFileStatus status = ScmFileStatus.UNKNOWN; 329 330 if ( STATUS_CMD_ADD_FLAG.equals( flag ) ) 331 { 332 status = ScmFileStatus.ADDED; 333 } 334 335 if ( STATUS_CMD_CHANGE_FLAG.equals( flag ) ) 336 { 337 status = ScmFileStatus.MODIFIED; 338 } 339 340 if ( STATUS_CMD_DELETE_FLAG.equals( flag ) ) 341 { 342 status = ScmFileStatus.DELETED; 343 } 344 345 if ( getLogger().isDebugEnabled() ) 346 { 347 getLogger().debug( " Line : '" + line + "'" ); 348 getLogger().debug( " Extracted filePath : '" + filePath + "'" ); 349 getLogger().debug( " Extracted flag : '" + flag + "'" ); 350 getLogger().debug( " Extracted status : '" + status + "'" ); 351 } 352 353 fChangedFiles.add( new ScmFile( filePath, status ) ); 354 } 355 356 public List<ScmFile> getChangedFiles() 357 { 358 return fChangedFiles; 359 } 360 }