001    package org.apache.maven.scm.provider.perforce.command.checkin;
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.ScmVersion;
025    import org.apache.maven.scm.command.checkin.AbstractCheckInCommand;
026    import org.apache.maven.scm.command.checkin.CheckInScmResult;
027    import org.apache.maven.scm.provider.ScmProviderRepository;
028    import org.apache.maven.scm.provider.perforce.PerforceScmProvider;
029    import org.apache.maven.scm.provider.perforce.command.PerforceCommand;
030    import org.apache.maven.scm.provider.perforce.repository.PerforceScmProviderRepository;
031    import org.codehaus.plexus.util.cli.CommandLineException;
032    import org.codehaus.plexus.util.cli.CommandLineUtils;
033    import org.codehaus.plexus.util.cli.Commandline;
034    
035    import java.io.ByteArrayInputStream;
036    import java.io.File;
037    import java.io.IOException;
038    import java.util.HashSet;
039    import java.util.List;
040    import java.util.Set;
041    
042    /**
043     * @author Mike Perham
044     * @version $Id: PerforceCheckInCommand.java 1352065 2012-06-20 12:36:08Z olamy $
045     */
046    public class PerforceCheckInCommand
047        extends AbstractCheckInCommand
048        implements PerforceCommand
049    {
050        /**
051         * {@inheritDoc}
052         */
053        @Override
054        protected CheckInScmResult executeCheckInCommand( ScmProviderRepository repo, ScmFileSet files, String message,
055                                                          ScmVersion version )
056            throws ScmException
057        {
058            Commandline cl = createCommandLine( (PerforceScmProviderRepository) repo, files.getBasedir() );
059            PerforceCheckInConsumer consumer = new PerforceCheckInConsumer();
060            try
061            {
062                String jobs = System.getProperty( "maven.scm.jobs" );
063    
064                if ( getLogger().isDebugEnabled() )
065                {
066                    getLogger().debug( PerforceScmProvider.clean( "Executing " + cl.toString() ) );
067                }
068    
069                PerforceScmProviderRepository prepo = (PerforceScmProviderRepository) repo;
070                String changes = createChangeListSpecification( prepo, files, message,
071                                                                PerforceScmProvider.getRepoPath( getLogger(), prepo,
072                                                                                                 files.getBasedir() ),
073                                                                jobs );
074    
075                if ( getLogger().isDebugEnabled() )
076                {
077                    getLogger().debug( "Sending changelist:\n" + changes );
078                }
079    
080                CommandLineUtils.StringStreamConsumer err = new CommandLineUtils.StringStreamConsumer();
081                int exitCode =
082                    CommandLineUtils.executeCommandLine( cl, new ByteArrayInputStream( changes.getBytes() ), consumer,
083                                                         err );
084    
085                if ( exitCode != 0 )
086                {
087                    String cmdLine = CommandLineUtils.toString( cl.getCommandline() );
088    
089                    StringBuilder msg = new StringBuilder( "Exit code: " + exitCode + " - " + err.getOutput() );
090                    msg.append( '\n' );
091                    msg.append( "Command line was:" + cmdLine );
092    
093                    throw new CommandLineException( msg.toString() );
094                }
095            }
096            catch ( CommandLineException e )
097            {
098                if ( getLogger().isErrorEnabled() )
099                {
100                    getLogger().error( "CommandLineException " + e.getMessage(), e );
101                }
102            }
103    
104            return new CheckInScmResult( cl.toString(), consumer.isSuccess() ? "Checkin successful" : "Unable to submit",
105                                         consumer.getOutput(), consumer.isSuccess() );
106        }
107    
108        public static Commandline createCommandLine( PerforceScmProviderRepository repo, File workingDirectory )
109        {
110            Commandline command = PerforceScmProvider.createP4Command( repo, workingDirectory );
111    
112            command.createArg().setValue( "submit" );
113            command.createArg().setValue( "-i" );
114            return command;
115        }
116    
117        private static final String NEWLINE = "\r\n";
118    
119        public static String createChangeListSpecification( PerforceScmProviderRepository repo, ScmFileSet files,
120                                                            String msg, String canonicalPath, String jobs )
121        {
122            StringBuilder buf = new StringBuilder();
123            buf.append( "Change: new" ).append( NEWLINE ).append( NEWLINE );
124            buf.append( "Description:" ).append( NEWLINE ).append( "\t" ).append( msg ).append( NEWLINE ).append( NEWLINE );
125            if ( jobs != null && jobs.length() != 0 )
126            {
127                // Multiple jobs are not handled with this implementation
128                buf.append( "Jobs:" ).append( NEWLINE ).append( "\t" ).append( jobs ).append( NEWLINE ).append( NEWLINE );
129            }
130    
131            buf.append( "Files:" ).append( NEWLINE );
132            try
133            {
134                Set<String> dupes = new HashSet<String>();
135                File workingDir = files.getBasedir();
136                String candir = workingDir.getCanonicalPath();
137                List<File> fs = files.getFileList();
138                for ( int i = 0; i < fs.size(); i++ )
139                {
140                    File file = null;
141                    if ( fs.get( i ).isAbsolute() )
142                    {
143                        file = new File( fs.get( i ).getPath() );
144                    }
145                    else
146                    {
147                        file = new File( workingDir, fs.get( i ).getPath() );
148                    }
149                    // XXX Submit requires the canonical repository path for each
150                    // file.
151                    // It is unclear how to get that from a File object.
152                    // We assume the repo object has the relative prefix
153                    // "//depot/some/project"
154                    // and canfile has the relative path "src/foo.xml" to be added
155                    // to that prefix.
156                    // "//depot/some/project/src/foo.xml"
157                    String canfile = file.getCanonicalPath();
158                    if ( dupes.contains( canfile ) )
159                    {
160                        // XXX I am seeing duplicate files in the ScmFileSet.
161                        // I don't know why this is but we have to weed them out
162                        // or Perforce will barf
163                        System.err.println( "Skipping duplicate file: " + file );
164                        continue;
165                    }
166                    dupes.add( canfile );
167                    if ( canfile.startsWith( candir ) )
168                    {
169                        canfile = canfile.substring( candir.length() + 1 );
170                    }
171                    buf.append( "\t" ).append( canonicalPath ).append( "/" ).append( canfile.replace( '\\', '/' ) ).append(
172                        NEWLINE );
173                }
174            }
175            catch ( IOException e )
176            {
177                e.printStackTrace();
178            }
179            return buf.toString();
180        }
181    }