001 package org.apache.maven.scm.provider.perforce.command.tag;
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.ScmException;
023 import org.apache.maven.scm.ScmFileSet;
024 import org.apache.maven.scm.ScmResult;
025 import org.apache.maven.scm.ScmTagParameters;
026 import org.apache.maven.scm.command.tag.AbstractTagCommand;
027 import org.apache.maven.scm.command.tag.TagScmResult;
028 import org.apache.maven.scm.provider.ScmProviderRepository;
029 import org.apache.maven.scm.provider.perforce.PerforceScmProvider;
030 import org.apache.maven.scm.provider.perforce.command.PerforceCommand;
031 import org.apache.maven.scm.provider.perforce.command.PerforceInfoCommand;
032 import org.apache.maven.scm.provider.perforce.repository.PerforceScmProviderRepository;
033 import org.codehaus.plexus.util.IOUtil;
034 import org.codehaus.plexus.util.cli.CommandLineException;
035 import org.codehaus.plexus.util.cli.CommandLineUtils;
036 import org.codehaus.plexus.util.cli.Commandline;
037
038 import java.io.BufferedReader;
039 import java.io.DataOutputStream;
040 import java.io.File;
041 import java.io.IOException;
042 import java.io.InputStreamReader;
043 import java.io.OutputStream;
044 import java.util.List;
045
046 /**
047 * @author Mike Perham
048 * @author Olivier Lamy
049 *
050 */
051 public class PerforceTagCommand
052 extends AbstractTagCommand
053 implements PerforceCommand
054 {
055 private String actualRepoLocation = null;
056
057
058 protected ScmResult executeTagCommand( ScmProviderRepository repo, ScmFileSet files, String tag, String message )
059 throws ScmException
060 {
061 return executeTagCommand( repo, files, tag, new ScmTagParameters( message ) );
062 }
063
064 /**
065 * {@inheritDoc}
066 */
067 protected ScmResult executeTagCommand( ScmProviderRepository repo, ScmFileSet files, String tag,
068 ScmTagParameters scmTagParameters )
069 throws ScmException
070 {
071 PerforceScmProviderRepository prepo = (PerforceScmProviderRepository) repo;
072 actualRepoLocation = PerforceScmProvider.getRepoPath( getLogger(), prepo, files.getBasedir() );
073
074 PerforceTagConsumer consumer = new PerforceTagConsumer();
075 createLabel( repo, files, tag, consumer, false );
076 if ( consumer.isSuccess() )
077 {
078 syncLabel( repo, files, tag, consumer );
079 }
080 if ( consumer.isSuccess() )
081 {
082 // Now update the label if we need to lock it
083 if ( shouldLock() )
084 {
085 consumer = new PerforceTagConsumer();
086 createLabel( repo, files, tag, consumer, true );
087 }
088 }
089
090 if ( consumer.isSuccess() )
091 {
092 // Unclear what to pass as the first arg
093 return new TagScmResult( "p4 label -i", consumer.getTagged() );
094 }
095
096 // Unclear what to pass as the first arg
097 return new TagScmResult( "p4 label -i", "Tag failed", consumer.getOutput(), false );
098 }
099
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 }