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 *
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 }