001package 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
022import org.apache.maven.scm.ScmException;
023import org.apache.maven.scm.ScmFileSet;
024import org.apache.maven.scm.log.ScmLogger;
025import org.apache.maven.scm.provider.starteam.repository.StarteamScmProviderRepository;
026import org.apache.maven.scm.provider.starteam.util.StarteamUtil;
027import org.apache.maven.scm.providers.starteam.settings.Settings;
028import org.codehaus.plexus.util.cli.CommandLineException;
029import org.codehaus.plexus.util.cli.CommandLineUtils;
030import org.codehaus.plexus.util.cli.Commandline;
031import org.codehaus.plexus.util.cli.StreamConsumer;
032
033import java.io.File;
034import java.io.IOException;
035import java.util.List;
036
037/**
038 * Command line construction utility.
039 *
040 * @author Dan T. Tran
041 *
042 */
043public 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}