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 = Pattern.compile( "\\((\\d+)\\) \"(.*)\" <-> \\((\\d+)\\) \"(.*)\"" );
72  
73      //  Component: (1001) "BogusComponent"
74      private static final Pattern COMPONENT_PATTERN1 = Pattern.compile( "\\((\\d+)\\) \"(.*)\"" );
75  
76      //  Component: (1158) "GPDB" <-> (1157) "GPDBStream"
77      //  Component: (1002) "FireDragon" <-> (1005) "MavenR3Stream Workspace" (outgoing addition)
78      private static final Pattern COMPONENT_PATTERN2 = Pattern.compile( "\\((\\d+)\\) \"(.*)\" <.*>" );
79  
80      //  Baseline: (1128) 27 "BogusTestJazz-3.0.0.40"
81      private static final Pattern BASELINE_PATTERN = Pattern.compile( "\\((\\d+)\\) (\\d+) \"(.*)\"" );
82  
83      // Additional data we collect. (eye catchers)
84  
85      /**
86       * The "Status" command output line that contains the "Workspace" name.
87       */
88      public static final String STATUS_CMD_WORKSPACE = "Workspace:";
89  
90      /**
91       * The "Status" command output line that contains the "Component" name.
92       */
93      public static final String STATUS_CMD_COMPONENT = "Component:";
94  
95      /**
96       * The "Status" command output line that contains the "Workspace" name.
97       */
98      public static final String STATUS_CMD_BASELINE = "Baseline:";
99  
100     // File Status Commands (eye catchers)
101 
102     /**
103      * The "Status" command status flag for a resource that has been added.
104      */
105     public static final String STATUS_CMD_ADD_FLAG = "a-";
106 
107     /**
108      * The "Status" command status flag for when the content or properties of
109      * a file have been modified, or the properties of a directory have changed.
110      */
111     public static final String STATUS_CMD_CHANGE_FLAG = "-c";
112 
113     /**
114      * The "Status" command status flag for a resource that has been deleted.
115      */
116     public static final String STATUS_CMD_DELETE_FLAG = "d-";
117 
118     /**
119      * The "Status" command status flag for a resource that has been renamed or moved.
120      */
121     public static final String STATUS_CMD_MOVED_FLAG = "m-";
122 
123     /**
124      * A List of ScmFile objects that have their ScmFileStatus set.
125      */
126     private List<ScmFile> fChangedFiles = new ArrayList<ScmFile>();
127 
128     /**
129      * Constructor for our "scm status" consumer.
130      *
131      * @param repo   The JazzScmProviderRepository being used.
132      * @param logger The ScmLogger to use.
133      */
134     public JazzStatusConsumer( ScmProviderRepository repo, ScmLogger logger )
135     {
136         super( repo, logger );
137     }
138 
139     /**
140      * Process one line of output from the execution of the "scm status" command.
141      *
142      * @param line The line of output from the external command that has been pumped to us.
143      * @see org.codehaus.plexus.util.cli.StreamConsumer#consumeLine(java.lang.String)
144      */
145     public void consumeLine( String line )
146     {
147         super.consumeLine( line );
148         if ( containsWorkspace( line ) )
149         {
150             extractWorkspace( line );
151         }
152         if ( containsComponent( line ) )
153         {
154             extractComponent( line );
155         }
156         if ( containsBaseline( line ) )
157         {
158             extractBaseline( line );
159         }
160         if ( containsStatusFlag( line ) )
161         {
162             extractChangedFile( line );
163         }
164     }
165 
166     private boolean containsWorkspace( String line )
167     {
168         return line.trim().startsWith( STATUS_CMD_WORKSPACE );
169     }
170 
171     private void extractWorkspace( String line )
172     {
173         // With no stream (flow target):
174         //   Workspace: (1000) "BogusRepositoryWorkspace" <-> (1000) "BogusRepositoryWorkspace"
175         // With a stream:
176         //   Workspace: (1156) "GPDBWorkspace" <-> (1157) "GPDBStream"
177 
178         Matcher matcher = WORKSPACE_PATTERN.matcher( line );
179         if ( matcher.find() )
180         {
181             JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository();
182 
183             int workspaceAlias = Integer.parseInt( matcher.group( 1 ) );
184             String workspace = matcher.group( 2 );
185             int streamAlias = Integer.parseInt( matcher.group( 3 ) );
186             String stream = matcher.group( 4 );
187             if ( getLogger().isDebugEnabled() )
188             {
189                 getLogger().debug( "Successfully parsed \"Workspace:\" line:" );
190                 getLogger().debug( "  workspaceAlias = " + workspaceAlias );
191                 getLogger().debug( "  workspace      = " + workspace );
192                 getLogger().debug( "  streamAlias    = " + streamAlias );
193                 getLogger().debug( "  stream         = " + stream );
194             }
195             jazzRepository.setWorkspaceAlias( workspaceAlias );
196             jazzRepository.setWorkspace( workspace );
197             jazzRepository.setFlowTargetAlias( streamAlias );
198             jazzRepository.setFlowTarget( stream );
199         }
200     }
201 
202     private boolean containsComponent( String line )
203     {
204         return line.trim().startsWith( STATUS_CMD_COMPONENT );
205     }
206 
207     private void extractComponent( String line )
208     {
209         // With no stream (flow target):
210         //     Component: (1001) "BogusComponent"
211         // With a stream:
212         //     Component: (1158) "GPDB" <-> (1157) "GPDBStream"
213         // With some additional information:
214         //     Component: (1002) "FireDragon" <-> (1005) "MavenR3Stream Workspace" (outgoing addition)
215 
216         Matcher matcher = COMPONENT_PATTERN1.matcher( line );
217         if ( matcher.find() )
218         {
219             //     Component: (1001) "BogusComponent"
220             JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository();
221             int componentAlias = Integer.parseInt( matcher.group( 1 ) );
222             String component = matcher.group( 2 );
223             if ( getLogger().isDebugEnabled() )
224             {
225                 getLogger().debug( "Successfully parsed \"Component:\" line:" );
226                 getLogger().debug( "  componentAlias = " + componentAlias );
227                 getLogger().debug( "  component      = " + component );
228             }
229             jazzRepository.setComponent( component );
230         }
231 
232         matcher = COMPONENT_PATTERN2.matcher( line );
233         if ( matcher.find() )
234         {
235             //     Component: (1158) "GPDB" <-> (1157) "GPDBStream"
236             JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository();
237             int componentAlias = Integer.parseInt( matcher.group( 1 ) );
238             String component = matcher.group( 2 );
239             if ( getLogger().isDebugEnabled() )
240             {
241                 getLogger().debug( "Successfully parsed \"Component:\" line:" );
242                 getLogger().debug( "  componentAlias = " + componentAlias );
243                 getLogger().debug( "  component      = " + component );
244             }
245             jazzRepository.setComponent( component );
246         }
247     }
248 
249     private boolean containsBaseline( String line )
250     {
251         return line.trim().startsWith( STATUS_CMD_BASELINE );
252     }
253 
254     private void extractBaseline( String line )
255     {
256         // Baseline: (1128) 27 "BogusTestJazz-3.0.0.40"
257 
258         Matcher matcher = BASELINE_PATTERN.matcher( line );
259         if ( matcher.find() )
260         {
261             JazzScmProviderRepository jazzRepository = (JazzScmProviderRepository) getRepository();
262 
263             int baselineAlias = Integer.parseInt( matcher.group( 1 ) );
264             int baselineId = Integer.parseInt( matcher.group( 2 ) );
265             String baseline = matcher.group( 3 );
266             if ( getLogger().isDebugEnabled() )
267             {
268                 getLogger().debug( "Successfully parsed \"Baseline:\" line:" );
269                 getLogger().debug( "  baselineAlias = " + baselineAlias );
270                 getLogger().debug( "  baselineId    = " + baselineId );
271                 getLogger().debug( "  baseline      = " + baseline );
272             }
273             jazzRepository.setBaseline( baseline );
274         }
275     }
276 
277     private boolean containsStatusFlag( String line )
278     {
279         boolean containsStatusFlag = false;
280 
281         if ( line.trim().length() > 2 )
282         {
283             String flag = line.trim().substring( 0, 2 );
284             if ( STATUS_CMD_ADD_FLAG.equals( flag ) ||
285                 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 }