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     * @version $Id: PerforceTagCommand.java 1306867 2012-03-29 13:45:10Z olamy $
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    }