001    package org.apache.maven.scm.provider.starteam;
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 java.io.File;
023    import java.io.IOException;
024    import java.util.ArrayList;
025    import java.util.List;
026    
027    import org.apache.maven.scm.CommandParameters;
028    import org.apache.maven.scm.ScmException;
029    import org.apache.maven.scm.ScmFileSet;
030    import org.apache.maven.scm.command.add.AddScmResult;
031    import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
032    import org.apache.maven.scm.command.checkin.CheckInScmResult;
033    import org.apache.maven.scm.command.checkout.CheckOutScmResult;
034    import org.apache.maven.scm.command.diff.DiffScmResult;
035    import org.apache.maven.scm.command.edit.EditScmResult;
036    import org.apache.maven.scm.command.remove.RemoveScmResult;
037    import org.apache.maven.scm.command.status.StatusScmResult;
038    import org.apache.maven.scm.command.tag.TagScmResult;
039    import org.apache.maven.scm.command.unedit.UnEditScmResult;
040    import org.apache.maven.scm.command.update.UpdateScmResult;
041    import org.apache.maven.scm.provider.AbstractScmProvider;
042    import org.apache.maven.scm.provider.ScmProviderRepository;
043    import org.apache.maven.scm.provider.starteam.command.add.StarteamAddCommand;
044    import org.apache.maven.scm.provider.starteam.command.changelog.StarteamChangeLogCommand;
045    import org.apache.maven.scm.provider.starteam.command.checkin.StarteamCheckInCommand;
046    import org.apache.maven.scm.provider.starteam.command.checkout.StarteamCheckOutCommand;
047    import org.apache.maven.scm.provider.starteam.command.diff.StarteamDiffCommand;
048    import org.apache.maven.scm.provider.starteam.command.edit.StarteamEditCommand;
049    import org.apache.maven.scm.provider.starteam.command.remove.StarteamRemoveCommand;
050    import org.apache.maven.scm.provider.starteam.command.status.StarteamStatusCommand;
051    import org.apache.maven.scm.provider.starteam.command.tag.StarteamTagCommand;
052    import org.apache.maven.scm.provider.starteam.command.unedit.StarteamUnEditCommand;
053    import org.apache.maven.scm.provider.starteam.command.update.StarteamUpdateCommand;
054    import org.apache.maven.scm.provider.starteam.repository.StarteamScmProviderRepository;
055    import org.apache.maven.scm.repository.ScmRepositoryException;
056    import org.codehaus.plexus.util.StringUtils;
057    
058    /**
059     * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
060     *
061     * @plexus.component role="org.apache.maven.scm.provider.ScmProvider" role-hint="starteam"
062     */
063    public class StarteamScmProvider
064        extends AbstractScmProvider
065    {
066        public static final String STARTEAM_URL_FORMAT =
067            "[username[:password]@]hostname:port:/projectName/[viewName/][folderHiearchy/]";
068    
069        // ----------------------------------------------------------------------
070        // ScmProvider Implementation
071        // ----------------------------------------------------------------------
072    
073        /** {@inheritDoc} */
074        public ScmProviderRepository makeProviderScmRepository( String scmSpecificUrl, char delimiter )
075            throws ScmRepositoryException
076        {
077            String user = null;
078    
079            String password = null;
080    
081            int index = scmSpecificUrl.indexOf( '@' );
082    
083            String rest = scmSpecificUrl;
084    
085            if ( index != -1 )
086            {
087                String userAndPassword = scmSpecificUrl.substring( 0, index );
088    
089                rest = scmSpecificUrl.substring( index + 1 );
090    
091                index = userAndPassword.indexOf( ':' );
092    
093                if ( index != -1 )
094                {
095                    user = userAndPassword.substring( 0, index );
096    
097                    password = userAndPassword.substring( index + 1 );
098                }
099                else
100                {
101                    user = userAndPassword;
102                }
103            }
104    
105            String[] tokens = StringUtils.split( rest, Character.toString( delimiter ) );
106    
107            String host;
108    
109            int port;
110    
111            String path;
112    
113            if ( tokens.length == 3 )
114            {
115                host = tokens[0];
116    
117                port = new Integer( tokens[1] ).intValue();
118    
119                path = tokens[2];
120            }
121            else if ( tokens.length == 2 )
122            {
123                if ( getLogger().isWarnEnabled() )
124                {
125                    getLogger().warn(
126                                      "Your scm URL use a deprecated format. The new format is :"
127                                          + STARTEAM_URL_FORMAT );
128                }
129    
130                host = tokens[0];
131    
132                if ( tokens[1].indexOf( '/' ) == -1 )
133                {
134                    throw new ScmRepositoryException(
135                        "Invalid SCM URL: The url has to be on the form: " + STARTEAM_URL_FORMAT );
136                }
137    
138                int at = tokens[1].indexOf( '/' );
139    
140                port = new Integer( tokens[1].substring( 0, at ) ).intValue();
141    
142                path = tokens[1].substring( at );
143            }
144            else
145            {
146                throw new ScmRepositoryException(
147                    "Invalid SCM URL: The url has to be on the form: " + STARTEAM_URL_FORMAT );
148            }
149    
150            try
151            {
152                return new StarteamScmProviderRepository( user, password, host, port, path );
153            }
154            catch ( Exception e )
155            {
156                throw new ScmRepositoryException(
157                    "Invalid SCM URL: The url has to be on the form: " + STARTEAM_URL_FORMAT );
158            }
159        }
160    
161        public String getScmType()
162        {
163            return "starteam";
164        }
165    
166        /** {@inheritDoc} */
167        public AddScmResult add( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
168            throws ScmException
169        {
170            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
171    
172            StarteamAddCommand command = new StarteamAddCommand();
173    
174            command.setLogger( getLogger() );
175    
176            return (AddScmResult) command.execute( repository, fileSet, parameters );
177        }
178    
179        /** {@inheritDoc} */
180        public ChangeLogScmResult changelog( ScmProviderRepository repository, ScmFileSet fileSet,
181                                             CommandParameters parameters )
182            throws ScmException
183        {
184            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
185    
186            StarteamChangeLogCommand command = new StarteamChangeLogCommand();
187    
188            command.setLogger( getLogger() );
189    
190            return (ChangeLogScmResult) command.execute( repository, fileSet, parameters );
191        }
192    
193        /** {@inheritDoc} */
194        public CheckInScmResult checkin( ScmProviderRepository repository, ScmFileSet fileSet,
195                                         CommandParameters parameters )
196            throws ScmException
197        {
198            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
199    
200            StarteamCheckInCommand command = new StarteamCheckInCommand();
201    
202            command.setLogger( getLogger() );
203    
204            return (CheckInScmResult) command.execute( repository, fileSet, parameters );
205        }
206    
207        /** {@inheritDoc} */
208        public CheckOutScmResult checkout( ScmProviderRepository repository, ScmFileSet fileSet,
209                                           CommandParameters parameters )
210            throws ScmException
211        {
212            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
213    
214            StarteamCheckOutCommand command = new StarteamCheckOutCommand();
215    
216            command.setLogger( getLogger() );
217    
218            return (CheckOutScmResult) command.execute( repository, fileSet, parameters );
219        }
220    
221        /** {@inheritDoc} */
222        public DiffScmResult diff( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
223            throws ScmException
224        {
225            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
226    
227            StarteamDiffCommand command = new StarteamDiffCommand();
228    
229            command.setLogger( getLogger() );
230    
231            return (DiffScmResult) command.execute( repository, fileSet, parameters );
232        }
233    
234        /** {@inheritDoc} */
235        public StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
236            throws ScmException
237        {
238            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
239    
240            StarteamStatusCommand command = new StarteamStatusCommand();
241    
242            command.setLogger( getLogger() );
243    
244            return (StatusScmResult) command.execute( repository, fileSet, parameters );
245        }
246    
247        /** {@inheritDoc} */
248        public TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
249            throws ScmException
250        {
251            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
252    
253            StarteamTagCommand command = new StarteamTagCommand();
254    
255            command.setLogger( getLogger() );
256    
257            return (TagScmResult) command.execute( repository, fileSet, parameters );
258        }
259    
260        /** {@inheritDoc} */
261        public UpdateScmResult update( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
262            throws ScmException
263        {
264            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
265    
266            StarteamUpdateCommand command = new StarteamUpdateCommand();
267    
268            command.setLogger( getLogger() );
269    
270            return (UpdateScmResult) command.execute( repository, fileSet, parameters );
271        }
272    
273        /** {@inheritDoc} */
274        protected EditScmResult edit( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
275            throws ScmException
276        {
277            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
278    
279            StarteamEditCommand command = new StarteamEditCommand();
280    
281            command.setLogger( getLogger() );
282    
283            return (EditScmResult) command.execute( repository, fileSet, parameters );
284        }
285    
286        /** {@inheritDoc} */
287        protected UnEditScmResult unedit( ScmProviderRepository repository, ScmFileSet fileSet,
288                                          CommandParameters parameters )
289            throws ScmException
290        {
291            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
292    
293            StarteamUnEditCommand command = new StarteamUnEditCommand();
294    
295            command.setLogger( getLogger() );
296    
297            return (UnEditScmResult) command.execute( repository, fileSet, parameters );
298        }
299    
300        /** {@inheritDoc} */
301        public RemoveScmResult remove( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
302            throws ScmException
303        {
304            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
305    
306            StarteamRemoveCommand command = new StarteamRemoveCommand();
307    
308            command.setLogger( getLogger() );
309    
310            return (RemoveScmResult) command.execute( repository, fileSet, parameters );
311        }
312    
313        /**
314         * Starteam provider requires that all files in ScmFileSet must be relative to basedir
315         * This function ensures and converts all absolute paths to relative paths
316         *
317         * @param currentFileSet
318         * @return
319         * @throws ScmException
320         */
321        private static ScmFileSet fixUpScmFileSetAbsoluteFilePath( ScmFileSet currentFileSet )
322            throws ScmException
323        {
324            ScmFileSet newFileSet = null;
325            
326            try
327            {
328                File basedir = getAbsoluteFilePath( currentFileSet.getBasedir() );
329    
330                List<File> files = currentFileSet.getFileList();
331    
332                List<File> relPathFiles = new ArrayList<File>(files.size());
333                
334                for ( File file : files )
335                {
336                    if ( file.isAbsolute() )
337                    {
338                        relPathFiles.add( new File( getRelativePath( basedir, file ) ));
339                    } else {
340                        relPathFiles.add( file );
341                    }
342                    
343                }
344    
345                newFileSet = new ScmFileSet( basedir, relPathFiles );
346            }
347            catch ( IOException e )
348            {
349                throw new ScmException( "Invalid file set.", e );
350            }
351    
352            return newFileSet;
353        }
354    
355        public static String getRelativePath( File basedir, File f )
356            throws ScmException, IOException
357        {
358            File fileOrDir = getAbsoluteFilePath( f );
359    
360            if ( !fileOrDir.getCanonicalPath().startsWith( basedir.getCanonicalPath() ) )
361            {
362                throw new ScmException( fileOrDir.getPath() + " was not contained in " + basedir.getPath() );
363            }
364    
365            if ( basedir.getCanonicalFile().equals(basedir.getAbsoluteFile()) )
366            {
367                return fileOrDir.getPath().substring( basedir.getPath().length() + 1, fileOrDir.getPath().length() );
368            }
369            return fileOrDir.getPath().substring( basedir.getCanonicalPath().length() + 1, fileOrDir.getPath().length() );
370        }
371    
372        private static File getAbsoluteFilePath( File fileOrDir )
373            throws IOException
374        {
375            String javaPathString = fileOrDir.getCanonicalPath().replace( '\\', '/' );
376    
377            if ( javaPathString.endsWith( "/" ) )
378            {
379                javaPathString = javaPathString.substring( 0, javaPathString.length() - 1 );
380            }
381    
382            return new File( javaPathString );
383        }
384    }