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 }