View Javadoc
1   package org.apache.maven.scm.provider.perforce.command.tag;
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.ScmException;
23  import org.apache.maven.scm.ScmFileSet;
24  import org.apache.maven.scm.ScmResult;
25  import org.apache.maven.scm.ScmTagParameters;
26  import org.apache.maven.scm.command.tag.AbstractTagCommand;
27  import org.apache.maven.scm.command.tag.TagScmResult;
28  import org.apache.maven.scm.provider.ScmProviderRepository;
29  import org.apache.maven.scm.provider.perforce.PerforceScmProvider;
30  import org.apache.maven.scm.provider.perforce.command.PerforceCommand;
31  import org.apache.maven.scm.provider.perforce.command.PerforceInfoCommand;
32  import org.apache.maven.scm.provider.perforce.repository.PerforceScmProviderRepository;
33  import org.codehaus.plexus.util.IOUtil;
34  import org.codehaus.plexus.util.cli.CommandLineException;
35  import org.codehaus.plexus.util.cli.CommandLineUtils;
36  import org.codehaus.plexus.util.cli.Commandline;
37  
38  import java.io.BufferedReader;
39  import java.io.DataOutputStream;
40  import java.io.File;
41  import java.io.IOException;
42  import java.io.InputStreamReader;
43  import java.io.OutputStream;
44  import java.util.List;
45  
46  /**
47   * @author Mike Perham
48   * @author Olivier Lamy
49   *
50   */
51  public class PerforceTagCommand
52      extends AbstractTagCommand
53      implements PerforceCommand
54  {
55      private String actualRepoLocation = null;
56  
57  
58      protected ScmResult executeTagCommand( ScmProviderRepository repo, ScmFileSet files, String tag, String message )
59          throws ScmException
60      {
61          return executeTagCommand( repo, files, tag, new ScmTagParameters( message ) );
62      }
63  
64      /**
65       * {@inheritDoc}
66       */
67      protected ScmResult executeTagCommand( ScmProviderRepository repo, ScmFileSet files, String tag,
68                                             ScmTagParameters scmTagParameters )
69          throws ScmException
70      {
71          PerforceScmProviderRepository prepo = (PerforceScmProviderRepository) repo;
72          actualRepoLocation = PerforceScmProvider.getRepoPath( getLogger(), prepo, files.getBasedir() );
73  
74          PerforceTagConsumer consumer = new PerforceTagConsumer();
75          createLabel( repo, files, tag, consumer, false );
76          if ( consumer.isSuccess() )
77          {
78              syncLabel( repo, files, tag, consumer );
79          }
80          if ( consumer.isSuccess() )
81          {
82              // Now update the label if we need to lock it
83              if ( shouldLock() )
84              {
85                  consumer = new PerforceTagConsumer();
86                  createLabel( repo, files, tag, consumer, true );
87              }
88          }
89  
90          if ( consumer.isSuccess() )
91          {
92              // Unclear what to pass as the first arg
93              return new TagScmResult( "p4 label -i", consumer.getTagged() );
94          }
95  
96          // Unclear what to pass as the first arg
97          return new TagScmResult( "p4 label -i", "Tag failed", consumer.getOutput(), false );
98      }
99  
100     private boolean shouldLock()
101     {
102         return Boolean.valueOf( System.getProperty( "maven.scm.locktag", "true" ) ).booleanValue();
103     }
104 
105     private void syncLabel( ScmProviderRepository repo, ScmFileSet files, String tag, PerforceTagConsumer consumer )
106     {
107         Commandline cl =
108             createLabelsyncCommandLine( (PerforceScmProviderRepository) repo, files.getBasedir(), files, tag );
109         try
110         {
111             if ( getLogger().isDebugEnabled() )
112             {
113                 getLogger().debug( PerforceScmProvider.clean( "Executing: " + cl.toString() ) );
114             }
115             CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
116             int exitCode = CommandLineUtils.executeCommandLine( cl, consumer, err );
117 
118             if ( exitCode != 0 )
119             {
120                 String cmdLine = CommandLineUtils.toString( cl.getCommandline() );
121 
122                 StringBuilder msg = new StringBuilder( "Exit code: " + exitCode + " - " + err.getOutput() );
123                 msg.append( '\n' );
124                 msg.append( "Command line was:" + cmdLine );
125 
126                 throw new CommandLineException( msg.toString() );
127             }
128         }
129         catch ( CommandLineException e )
130         {
131             if ( getLogger().isErrorEnabled() )
132             {
133                 getLogger().error( "CommandLineException " + e.getMessage(), e );
134             }
135         }
136     }
137 
138     private void createLabel( ScmProviderRepository repo, ScmFileSet files, String tag, PerforceTagConsumer consumer,
139                               boolean lock )
140     {
141         Commandline cl = createLabelCommandLine( (PerforceScmProviderRepository) repo, files.getBasedir() );
142         DataOutputStream dos = null;
143         InputStreamReader isReader = null;
144         InputStreamReader isReaderErr = null;
145         try
146         {
147             if ( getLogger().isDebugEnabled() )
148             {
149                 getLogger().debug( PerforceScmProvider.clean( "Executing: " + cl.toString() ) );
150             }
151             Process proc = cl.execute();
152             OutputStream out = proc.getOutputStream();
153             dos = new DataOutputStream( out );
154             String label = createLabelSpecification( (PerforceScmProviderRepository) repo, tag, lock );
155             if ( getLogger().isDebugEnabled() )
156             {
157                 getLogger().debug( "LabelSpec: " + NEWLINE + label );
158             }
159             dos.write( label.getBytes() );
160             dos.close();
161             out.close();
162             // TODO find & use a less naive InputStream multiplexer
163             isReader = new InputStreamReader( proc.getInputStream() );
164             isReaderErr = new InputStreamReader( proc.getErrorStream() );
165             BufferedReader stdout = new BufferedReader( isReader );
166             BufferedReader stderr = new BufferedReader( isReaderErr );
167             String line;
168             while ( ( line = stdout.readLine() ) != null )
169             {
170                 if ( getLogger().isDebugEnabled() )
171                 {
172                     getLogger().debug( "Consuming stdout: " + line );
173                 }
174                 consumer.consumeLine( line );
175             }
176             while ( ( line = stderr.readLine() ) != null )
177             {
178                 if ( getLogger().isDebugEnabled() )
179                 {
180                     getLogger().debug( "Consuming stderr: " + line );
181                 }
182                 consumer.consumeLine( line );
183             }
184             stderr.close();
185             stdout.close();
186         }
187         catch ( CommandLineException e )
188         {
189             if ( getLogger().isErrorEnabled() )
190             {
191                 getLogger().error( "CommandLineException " + e.getMessage(), e );
192             }
193         }
194         catch ( IOException e )
195         {
196             if ( getLogger().isErrorEnabled() )
197             {
198                 getLogger().error( "IOException " + e.getMessage(), e );
199             }
200         }
201         finally
202         {
203             IOUtil.close( dos );
204             IOUtil.close( isReader );
205             IOUtil.close( isReaderErr );
206         }
207     }
208 
209     public static Commandline createLabelCommandLine( PerforceScmProviderRepository repo, File workingDirectory )
210     {
211         Commandline command = PerforceScmProvider.createP4Command( repo, workingDirectory );
212 
213         command.createArg().setValue( "label" );
214         command.createArg().setValue( "-i" );
215         return command;
216     }
217 
218     public static Commandline createLabelsyncCommandLine( PerforceScmProviderRepository repo, File workingDirectory,
219                                                           ScmFileSet files, String tag )
220     {
221         Commandline command = PerforceScmProvider.createP4Command( repo, workingDirectory );
222 
223         command.createArg().setValue( "labelsync" );
224         command.createArg().setValue( "-l" );
225         command.createArg().setValue( tag );
226 
227         List<File> fs = files.getFileList();
228         for ( File file : fs )
229         {
230             command.createArg().setValue( file.getPath() );
231         }
232         return command;
233     }
234 
235     private static final String NEWLINE = "\r\n";
236 
237     /*
238      * Label: foo-label
239      * View: //depot/path/to/repos/...
240      * Owner: mperham
241      */
242     public String createLabelSpecification( PerforceScmProviderRepository repo, String tag, boolean lock )
243     {
244         StringBuilder buf = new StringBuilder();
245         buf.append( "Label: " ).append( tag ).append( NEWLINE );
246         buf.append( "View: " ).append( PerforceScmProvider.getCanonicalRepoPath( actualRepoLocation ) ).append(
247             NEWLINE );
248         String username = repo.getUser();
249         if ( username == null )
250         {
251             // I have no idea why but Perforce doesn't default the owner to the current user.
252             // Since the user is not explicitly set, we use 'p4 info' to query for the current user.
253             username = PerforceInfoCommand.getInfo( getLogger(), repo ).getEntry( "User name" );
254         }
255         buf.append( "Owner: " ).append( username ).append( NEWLINE );
256         buf.append( "Options: " ).append( lock ? "" : "un" ).append( "locked" ).append( NEWLINE );
257         return buf.toString();
258     }
259 }