View Javadoc
1   package org.apache.maven.scm.provider.jazz.command.status;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.scm.ScmFile;
23  import org.apache.maven.scm.ScmFileStatus;
24  import org.apache.maven.scm.log.ScmLogger;
25  import org.apache.maven.scm.provider.ScmProviderRepository;
26  import org.apache.maven.scm.provider.jazz.command.consumer.AbstractRepositoryConsumer;
27  import org.apache.maven.scm.provider.jazz.repository.JazzScmProviderRepository;
28  
29  import java.util.ArrayList;
30  import java.util.List;
31  import java.util.regex.Matcher;
32  import java.util.regex.Pattern;
33  
34  /**
35   * Consume the output of the scm command for the "status" operation.
36   * <p/>
37   * It is normally just used to build up a list of ScmFile objects that have
38   * their ScmFileStatus set.
39   * This class has been expanded so that the Workspace, Component and Baseline
40   * are also collected and set back in the JazzScmProviderRepository.
41   * The Workspace and Component names are needed for some other commands (list,
42   * for example), so we can easily get this information here.
43   *
44   * @author <a href="mailto:ChrisGWarp@gmail.com">Chris Graham</a>
45   */
46  public class JazzStatusConsumer
47      extends AbstractRepositoryConsumer
48  {
49  // We have have a workspace with no flow targets (it points to itself)
50  //
51  //  Workspace: (1000) "BogusRepositoryWorkspace" <-> (1000) "BogusRepositoryWorkspace"
52  //    Component: (1001) "BogusComponent"
53  //      Baseline: (1128) 27 "BogusTestJazz-3.0.0.40"
54  //      Unresolved:
55  //        d-- /BogusTest/pom.xml.releaseBackup
56  //        d-- /BogusTest/release.properties
57  //
58  // Or, we have have one that does have a flow target (ie a stream or another workspace).
59  //
60  //  Workspace: (1156) "GPDBWorkspace" <-> (1157) "GPDBStream"
61  //    Component: (1158) "GPDB" <-> (1157) "GPDBStream"
62  //      Baseline: (1159) 1 "Initial Baseline"
63  //
64  // Note the (%d) numbers are aliases and are only valid for the machine/instance that made the
65  // remote calls to the server. They are not to be shared across machines (ie don't make them global, public
66  // or persistent).
67  //
68  
69      //  Workspace: (1000) "BogusRepositoryWorkspace" <-> (1000) "BogusRepositoryWorkspace"
70      //  Workspace: (1156) "GPDBWorkspace" <-> (1157) "GPDBStream"
71      private static final Pattern WORKSPACE_PATTERN =
72          Pattern.compile( "\\((\\d+)\\) \"(.*)\" <-> \\((\\d+)\\) \"(.*)\"" );
73  
74      //  Component: (1001) "BogusComponent"
75      private static final Pattern COMPONENT_PATTERN1 = Pattern.compile( "\\((\\d+)\\) \"(.*)\"" );
76  
77      //  Component: (1158) "GPDB" <-> (1157) "GPDBStream"
78      //  Component: (1002) "FireDragon" <-> (1005) "MavenR3Stream Workspace" (outgoing addition)
79      private static final Pattern COMPONENT_PATTERN2 = Pattern.compile( "\\((\\d+)\\) \"(.*)\" <.*>" );
80  
81      //  Baseline: (1128) 27 "BogusTestJazz-3.0.0.40"
82      private static final Pattern BASELINE_PATTERN = Pattern.compile( "\\((\\d+)\\) (\\d+) \"(.*)\"" );
83  
84      // Additional data we collect. (eye catchers)
85  
86      /**
87       * The "Status" command output line that contains the "Workspace" name.
88       */
89      public static final String STATUS_CMD_WORKSPACE = "Workspace:";
90  
91      /**
92       * The "Status" command output line that contains the "Component" name.
93       */
94      public static final String STATUS_CMD_COMPONENT = "Component:";
95  
96      /**
97       * The "Status" command output line that contains the "Workspace" name.
98       */
99      public static final String STATUS_CMD_BASELINE = "Baseline:";
100 
101     // File Status Commands (eye catchers)
102 
103     /**
104      * The "Status" command status flag for a resource that has been added.
105      */
106     public static final String STATUS_CMD_ADD_FLAG = "a-";
107 
108     /**
109      * The "Status" command status flag for when the content or properties of
110      * a file have been modified, or the properties of a directory have changed.
111      */
112     public static final String STATUS_CMD_CHANGE_FLAG = "-c";
113 
114     /**
115      * The "Status" command status flag for a resource that has been deleted.
116      */
117     public static final String STATUS_CMD_DELETE_FLAG = "d-";
118 
119     /**
120      * The "Status" command status flag for a resource that has been renamed or moved.
121      */
122     public static final String STATUS_CMD_MOVED_FLAG = "m-";
123 
124     /**
125      * A List of ScmFile objects that have their ScmFileStatus set.
126      */
127     private List<ScmFile> fChangedFiles = new ArrayList<ScmFile>();
128 
129     /**
130      * Constructor for our "scm status" consumer.
131      *
132      * @param repo   The JazzScmProviderRepository being used.
133      * @param logger The ScmLogger to use.
134      */
135     public JazzStatusConsumer( ScmProviderRepository repo, ScmLogger logger )
136     {
137         super( repo, logger );
138     }
139 
140     /**
141      * Process one line of output from the execution of the "scm status" command.
142      *
143      * @param line The line of output from the external command that has been pumped to us.
144      * @see org.codehaus.plexus.util.cli.StreamConsumer#consumeLine(java.lang.String)
145      */
146     public void consumeLine( String line )
147     {
148         super.consumeLine( line );
149         if ( containsWorkspace( line ) )
150         {
151             extractWorkspace( line );
152         }
153         if ( containsComponent( line ) )
154         {
155             extractComponent( line );
156         }
157         if ( containsBaseline( line ) )
158         {
159             extractBaseline( line );
160         }
161         if ( containsStatusFlag( line ) )
162         {
163             extractChangedFile( line );
164         }
165     }
166 
167     private boolean containsWorkspace( String line )
168     {
169         return line.trim().startsWith( STATUS_CMD_WORKSPACE );
170     }
171 
172     private void extractWorkspace( String line )
173     {
174         // With no stream (flow target):
175         //   Workspace: (1000) "BogusRepositoryWorkspace" <-> (1000) "BogusRepositoryWorkspace"
176         // With a stream:
177         //   Workspace: (1156) "GPDBWorkspace" <-> (1157) "GPDBStream"
178 
179         Matcher matcher = WORKSPACE_PATTERN.matcher( line );
180         if ( matcher.find() )
181         {
182             JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository();
183 
184             int workspaceAlias = Integer.parseInt( matcher.group( 1 ) );
185             String workspace = matcher.group( 2 );
186             int streamAlias = Integer.parseInt( matcher.group( 3 ) );
187             String stream = matcher.group( 4 );
188             if ( getLogger().isDebugEnabled() )
189             {
190                 getLogger().debug( "Successfully parsed \"Workspace:\" line:" );
191                 getLogger().debug( "  workspaceAlias = " + workspaceAlias );
192                 getLogger().debug( "  workspace      = " + workspace );
193                 getLogger().debug( "  streamAlias    = " + streamAlias );
194                 getLogger().debug( "  stream         = " + stream );
195             }
196             jazzRepository.setWorkspaceAlias( workspaceAlias );
197             jazzRepository.setWorkspace( workspace );
198             jazzRepository.setFlowTargetAlias( streamAlias );
199             jazzRepository.setFlowTarget( stream );
200         }
201     }
202 
203     private boolean containsComponent( String line )
204     {
205         return line.trim().startsWith( STATUS_CMD_COMPONENT );
206     }
207 
208     private void extractComponent( String line )
209     {
210         // With no stream (flow target):
211         //     Component: (1001) "BogusComponent"
212         // With a stream:
213         //     Component: (1158) "GPDB" <-> (1157) "GPDBStream"
214         // With some additional information:
215         //     Component: (1002) "FireDragon" <-> (1005) "MavenR3Stream Workspace" (outgoing addition)
216 
217         Matcher matcher = COMPONENT_PATTERN1.matcher( line );
218         if ( matcher.find() )
219         {
220             //     Component: (1001) "BogusComponent"
221             JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository();
222             int componentAlias = Integer.parseInt( matcher.group( 1 ) );
223             String component = matcher.group( 2 );
224             if ( getLogger().isDebugEnabled() )
225             {
226                 getLogger().debug( "Successfully parsed \"Component:\" line:" );
227                 getLogger().debug( "  componentAlias = " + componentAlias );
228                 getLogger().debug( "  component      = " + component );
229             }
230             jazzRepository.setComponent( component );
231         }
232 
233         matcher = COMPONENT_PATTERN2.matcher( line );
234         if ( matcher.find() )
235         {
236             //     Component: (1158) "GPDB" <-> (1157) "GPDBStream"
237             JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository();
238             int componentAlias = Integer.parseInt( matcher.group( 1 ) );
239             String component = matcher.group( 2 );
240             if ( getLogger().isDebugEnabled() )
241             {
242                 getLogger().debug( "Successfully parsed \"Component:\" line:" );
243                 getLogger().debug( "  componentAlias = " + componentAlias );
244                 getLogger().debug( "  component      = " + component );
245             }
246             jazzRepository.setComponent( component );
247         }
248     }
249 
250     private boolean containsBaseline( String line )
251     {
252         return line.trim().startsWith( STATUS_CMD_BASELINE );
253     }
254 
255     private void extractBaseline( String line )
256     {
257         // Baseline: (1128) 27 "BogusTestJazz-3.0.0.40"
258 
259         Matcher matcher = BASELINE_PATTERN.matcher( line );
260         if ( matcher.find() )
261         {
262             JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository();
263 
264             int baselineAlias = Integer.parseInt( matcher.group( 1 ) );
265             int baselineId = Integer.parseInt( matcher.group( 2 ) );
266             String baseline = matcher.group( 3 );
267             if ( getLogger().isDebugEnabled() )
268             {
269                 getLogger().debug( "Successfully parsed \"Baseline:\" line:" );
270                 getLogger().debug( "  baselineAlias = " + baselineAlias );
271                 getLogger().debug( "  baselineId    = " + baselineId );
272                 getLogger().debug( "  baseline      = " + baseline );
273             }
274             jazzRepository.setBaseline( baseline );
275         }
276     }
277 
278     private boolean containsStatusFlag( String line )
279     {
280         boolean containsStatusFlag = false;
281 
282         if ( line.trim().length() > 2 )
283         {
284             String flag = line.trim().substring( 0, 2 );
285             if ( STATUS_CMD_ADD_FLAG.equals( flag ) || STATUS_CMD_CHANGE_FLAG.equals( flag )
286                 || STATUS_CMD_DELETE_FLAG.equals( flag ) )
287             {
288                 containsStatusFlag = true;
289             }
290         }
291         return containsStatusFlag;
292     }
293 
294     private void extractChangedFile( String line )
295     {
296         String flag = line.trim().substring( 0, 2 );
297         String filePath = line.trim().substring( 3 ).trim();
298         ScmFileStatus status = ScmFileStatus.UNKNOWN;
299 
300         if ( STATUS_CMD_ADD_FLAG.equals( flag ) )
301         {
302             status = ScmFileStatus.ADDED;
303         }
304 
305         if ( STATUS_CMD_CHANGE_FLAG.equals( flag ) )
306         {
307             status = ScmFileStatus.MODIFIED;
308         }
309 
310         if ( STATUS_CMD_DELETE_FLAG.equals( flag ) )
311         {
312             status = ScmFileStatus.DELETED;
313         }
314 
315         if ( getLogger().isDebugEnabled() )
316         {
317             getLogger().debug( " Line               : '" + line + "'" );
318             getLogger().debug( " Extracted filePath : '" + filePath + "'" );
319             getLogger().debug( " Extracted     flag : '" + flag + "'" );
320             getLogger().debug( " Extracted   status : '" + status + "'" );
321         }
322 
323         fChangedFiles.add( new ScmFile( filePath, status ) );
324     }
325 
326     public List<ScmFile> getChangedFiles()
327     {
328         return fChangedFiles;
329     }
330 }