001    package org.apache.maven.scm.provider.starteam.command;
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.log.ScmLogger;
025    import org.apache.maven.scm.provider.starteam.repository.StarteamScmProviderRepository;
026    import org.apache.maven.scm.provider.starteam.util.StarteamUtil;
027    import org.apache.maven.scm.providers.starteam.settings.Settings;
028    import org.codehaus.plexus.util.cli.CommandLineException;
029    import org.codehaus.plexus.util.cli.CommandLineUtils;
030    import org.codehaus.plexus.util.cli.Commandline;
031    import org.codehaus.plexus.util.cli.StreamConsumer;
032    
033    import java.io.File;
034    import java.io.IOException;
035    import java.util.List;
036    
037    /**
038     * Command line construction utility.
039     *
040     * @author Dan T. Tran
041     * @version $Id: StarteamCommandLineUtils.java 1134992 2011-06-12 21:54:27Z godin $
042     */
043    public final class StarteamCommandLineUtils
044    {
045    
046        private StarteamCommandLineUtils()
047        {
048        }
049    
050        private static Settings settings = StarteamUtil.getSettings();
051    
052        public static Commandline createStarteamBaseCommandLine( String action, StarteamScmProviderRepository repo )
053        {
054            Commandline cl = new Commandline();
055    
056            cl.createArg().setValue( "stcmd" );
057    
058            cl.createArg().setValue( action );
059    
060            cl.createArg().setValue( "-x" );
061    
062            cl.createArg().setValue( "-nologo" );
063    
064            cl.createArg().setValue( "-stop" );
065    
066            return cl;
067        }
068    
069        private static Commandline addCommandlineArguments( Commandline cl, List<String> args )
070        {
071            if ( args == null )
072            {
073              return cl;
074            }
075            for ( String arg : args )
076            {
077                cl.createArg().setValue( arg );
078            }
079            return cl;
080        }
081    
082        public static Commandline createStarteamCommandLine( String action, List<String> args, ScmFileSet scmFileSet,
083                                                             StarteamScmProviderRepository repo )
084        {
085            Commandline cl = StarteamCommandLineUtils.createStarteamBaseCommandLine( action, repo );
086    
087            // case 1: scmFileSet has only basedir
088            if ( scmFileSet.getFileList().size() == 0 )
089            {
090                //perform an action on directory
091                cl.createArg().setValue( "-p" );
092                cl.createArg().setValue( repo.getFullUrl() );
093                cl.createArg().setValue( "-fp" );
094                cl.createArg().setValue( scmFileSet.getBasedir().getAbsolutePath().replace( '\\', '/' ) );
095    
096                cl.createArg().setValue( "-is" );
097    
098                addCompressionOption( cl );
099    
100                addCommandlineArguments( cl, args );
101    
102                return cl;
103            }
104    
105            //case 2 scmFileSet has a sub file, but we dont know if the sub file is a directory or a file
106            File fileInFileSet = (File) scmFileSet.getFileList().get( 0 );
107            File subFile = new File( scmFileSet.getBasedir(), fileInFileSet.getPath() );
108    
109            //Perform an scm action on a single file where the orignal
110            // url and local directory ( -p and -fp options ) are altered
111            // to deal with single file/subdirectory
112    
113            File workingDirectory = subFile;
114            String scmUrl = repo.getFullUrl() + "/" + fileInFileSet.getPath().replace( '\\', '/' );
115            if ( !subFile.isDirectory() )
116            {
117                workingDirectory = subFile.getParentFile();
118                if ( fileInFileSet.getParent() != null )
119                {
120                    scmUrl = repo.getFullUrl() + "/" + fileInFileSet.getParent().replace( '\\', '/' );
121                }
122                else
123                {
124                    //subFile is right under root
125                    scmUrl = repo.getFullUrl();
126                }
127            }
128    
129            cl.createArg().setValue( "-p" );
130            cl.createArg().setValue( scmUrl );
131    
132            cl.createArg().setValue( "-fp" );
133            cl.createArg().setValue( workingDirectory.getPath().replace( '\\', '/' ) );
134    
135            cl.setWorkingDirectory( workingDirectory.getPath() );
136    
137            if ( subFile.isDirectory() )
138            {
139                cl.createArg().setValue( "-is" );
140            }
141    
142            StarteamCommandLineUtils.addCompressionOption( cl );
143    
144            addCommandlineArguments( cl, args );
145    
146            if ( !subFile.isDirectory() )
147            {
148                cl.createArg().setValue( subFile.getName() );
149            }
150    
151            return cl;
152        }
153    
154        public static void addCompressionOption( Commandline cl )
155        {
156            if ( settings.isCompressionEnable() )
157            {
158                cl.createArg().setValue( "-cmp" );
159            }
160        }
161    
162        public static void addEOLOption( List<String> args )
163        {
164            if ( settings.getEol() != null  )
165            {
166                args.add( "-eol" );
167                args.add( settings.getEol() );
168            }
169        }
170    
171        public static String toJavaPath( String path )
172        {
173            return path.replace( '\\', '/' );
174        }
175    
176        /**
177         * Hellper method to display command line without password
178         *
179         * @param cl
180         * @return String
181         * @throws ScmException
182         */
183        public static String displayCommandlineWithoutPassword( Commandline cl )
184            throws ScmException
185        {
186            String retStr = "";
187    
188            String fullStr = cl.toString();
189    
190            //look for -p and take out the password arugment
191    
192            int usernamePos = fullStr.indexOf( "-p " ) + 3;
193    
194            if ( usernamePos == 2 )
195            {
196                //should never get here since all starteam command lines
197                // have -p argument
198    
199                throw new ScmException( "Invalid command line" );
200            }
201    
202            retStr = fullStr.substring( 0, usernamePos );
203    
204            int passwordStartPos = fullStr.indexOf( ':' );
205    
206            if ( passwordStartPos == -1 )
207            {
208                throw new ScmException( "Invalid command line" );
209            }
210    
211            int passwordEndPos = fullStr.indexOf( '@' );
212    
213            if ( passwordEndPos == -1 )
214            {
215                throw new ScmException( "Invalid command line" );
216            }
217    
218            retStr += fullStr.substring( usernamePos, passwordStartPos );
219    
220            retStr += fullStr.substring( passwordEndPos );
221    
222            return retStr;
223    
224        }
225    
226        public static int executeCommandline( Commandline cl, StreamConsumer consumer,
227                                              CommandLineUtils.StringStreamConsumer stderr, ScmLogger logger )
228            throws ScmException
229        {
230            if ( logger.isInfoEnabled() )
231            {
232                logger.info( "Command line: " + displayCommandlineWithoutPassword( cl ) );
233            }
234    
235            try
236            {
237                return CommandLineUtils.executeCommandLine( cl, consumer, stderr );
238            }
239            catch ( CommandLineException ex )
240            {
241                throw new ScmException( "Error while executing command.", ex );
242            }
243        }
244    
245        /**
246         * Given 2 paths, make sure parent and child are on the same tree
247         * return the port of child that not in parent
248         *
249         * @param parent
250         * @param child
251         * @return
252         */
253        public static String getRelativeChildDirectory( String parent, String child )
254        {
255            //expect parentDir contains childDir
256            try
257            {
258                String childPath = new File( child ).getCanonicalFile().getPath().replace( '\\', '/' );
259    
260                String parentPath = new File( parent ).getCanonicalFile().getPath().replace( '\\', '/' );
261    
262                if ( !childPath.startsWith( parentPath ) )
263                {
264                    throw new IllegalStateException();
265                }
266    
267                String retDir = "." + childPath.substring( parentPath.length() );
268    
269                return retDir;
270    
271            }
272            catch ( IOException e )
273            {
274                throw new IllegalStateException(
275                    "Unable to convert to canonical path of either " + parent + " or " + child );
276            }
277        }
278    
279    }