001    package org.apache.maven.scm.provider.cvslib;
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.ScmResult;
031    import org.apache.maven.scm.ScmTagParameters;
032    import org.apache.maven.scm.command.Command;
033    import org.apache.maven.scm.command.add.AddScmResult;
034    import org.apache.maven.scm.command.blame.BlameScmResult;
035    import org.apache.maven.scm.command.branch.BranchScmResult;
036    import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
037    import org.apache.maven.scm.command.checkin.CheckInScmResult;
038    import org.apache.maven.scm.command.checkout.CheckOutScmResult;
039    import org.apache.maven.scm.command.diff.DiffScmResult;
040    import org.apache.maven.scm.command.export.ExportScmResult;
041    import org.apache.maven.scm.command.list.ListScmResult;
042    import org.apache.maven.scm.command.login.LoginScmResult;
043    import org.apache.maven.scm.command.mkdir.MkdirScmResult;
044    import org.apache.maven.scm.command.remove.RemoveScmResult;
045    import org.apache.maven.scm.command.status.StatusScmResult;
046    import org.apache.maven.scm.command.tag.TagScmResult;
047    import org.apache.maven.scm.command.update.UpdateScmResult;
048    import org.apache.maven.scm.provider.AbstractScmProvider;
049    import org.apache.maven.scm.provider.ScmProviderRepository;
050    import org.apache.maven.scm.provider.cvslib.repository.CvsScmProviderRepository;
051    import org.apache.maven.scm.repository.ScmRepositoryException;
052    import org.apache.maven.scm.repository.UnknownRepositoryStructure;
053    import org.codehaus.plexus.util.FileUtils;
054    import org.codehaus.plexus.util.StringUtils;
055    
056    /**
057     * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse </a>
058     * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
059     * @version $Id: AbstractCvsScmProvider.java 1134851 2011-06-12 01:24:05Z godin $
060     */
061    public abstract class AbstractCvsScmProvider
062        extends AbstractScmProvider
063    {
064        /** ext transport method */
065        public static final String TRANSPORT_EXT = "ext";
066    
067        /** local transport method */
068        public static final String TRANSPORT_LOCAL = "local";
069    
070        /** lserver transport method */
071        public static final String TRANSPORT_LSERVER = "lserver";
072    
073        /** pserver transport method */
074        public static final String TRANSPORT_PSERVER = "pserver";
075    
076        /** sspi transport method */
077        public static final String TRANSPORT_SSPI = "sspi";
078    
079        // ----------------------------------------------------------------------
080        //
081        // ----------------------------------------------------------------------
082    
083        /**
084         * The current ScmUrlParserResult
085         *
086         * @since 1.1.1
087         */
088        public static class ScmUrlParserResult
089        {
090            private List<String> messages;
091    
092            private ScmProviderRepository repository;
093    
094            public ScmUrlParserResult()
095            {
096                messages = new ArrayList<String>();
097            }
098    
099            /**
100             * @return the messages
101             */
102            public List<String> getMessages()
103            {
104                return messages;
105            }
106    
107            /**
108             * @param messages the messages to set
109             */
110            public void setMessages( List<String> messages )
111            {
112                this.messages = messages;
113            }
114    
115            /**
116             * @return the repository
117             */
118            public ScmProviderRepository getRepository()
119            {
120                return repository;
121            }
122    
123            /**
124             * @param repository the repository to set
125             */
126            public void setRepository( ScmProviderRepository repository )
127            {
128                this.repository = repository;
129            }
130    
131            /**
132             * Reset messages.
133             */
134            public void resetMessages()
135            {
136                this.messages = new ArrayList<String>();
137            }
138        }
139    
140        // ----------------------------------------------------------------------
141        // ScmProvider Implementation
142        // ----------------------------------------------------------------------
143    
144        /** {@inheritDoc} */
145        public String getScmSpecificFilename()
146        {
147            return "CVS";
148        }
149    
150        /* From the Cederqvist:
151        *
152        * "Tag names must start with an uppercase or lowercase letter and can
153        * contain uppercase and lowercase letters, digits, `-', and `_'. The
154        * two tag names BASE and HEAD are reserved for use by CVS. It is expected
155        * that future names which are special to CVS will be specially named,
156        * for example by starting with `.', rather than being named analogously
157        * to BASE and HEAD, to avoid conflicts with actual tag names."
158        */
159        /** {@inheritDoc} */
160        public String sanitizeTagName( String arg0 )
161        {
162            if ( validateTagName( arg0 ) )
163            {
164                return arg0;
165            }
166    
167            if ( arg0.equals( "HEAD" ) || arg0.equals( "BASE" ) || !arg0.matches( "[A-Za-z].*" ) )
168                /* we don't even bother to sanitize these, they're just silly */
169            {
170                throw new RuntimeException(
171                    "Unable to sanitize tag " + arg0 + ": must begin with a letter" + "and not be HEAD or BASE" );
172            }
173    
174            /* swap all illegal characters for a _ */
175            return arg0.replaceAll( "[^A-Za-z0-9_-]", "_" );
176        }
177    
178        /** {@inheritDoc} */
179        public boolean validateTagName( String arg0 )
180        {
181            return ( arg0.matches( "[A-Za-z][A-Za-z0-9_-]*" ) && !arg0.equals( "HEAD" ) && !arg0.equals( "BASE" ) );
182        }
183    
184        /** {@inheritDoc} */
185        public ScmProviderRepository makeProviderScmRepository( String scmSpecificUrl, char delimiter )
186            throws ScmRepositoryException
187        {
188            ScmUrlParserResult result = parseScmUrl( scmSpecificUrl, delimiter );
189    
190            if ( result.getMessages().size() > 0 )
191            {
192                throw new ScmRepositoryException( "The scm url is invalid.", result.getMessages() );
193            }
194    
195            return result.getRepository();
196        }
197    
198        /** {@inheritDoc} */
199        public ScmProviderRepository makeProviderScmRepository( File path )
200            throws ScmRepositoryException, UnknownRepositoryStructure
201        {
202            if ( path == null || !path.isDirectory() )
203            {
204                throw new ScmRepositoryException( path.getAbsolutePath() + " isn't a valid directory." );
205            }
206    
207            File cvsDirectory = new File( path, "CVS" );
208    
209            if ( !cvsDirectory.exists() )
210            {
211                throw new ScmRepositoryException( path.getAbsolutePath() + " isn't a cvs checkout directory." );
212            }
213    
214            File cvsRootFile = new File( cvsDirectory, "Root" );
215    
216            File moduleFile = new File( cvsDirectory, "Repository" );
217    
218            String cvsRoot;
219    
220            String module;
221    
222            try
223            {
224                cvsRoot = FileUtils.fileRead( cvsRootFile ).trim().substring( 1 );
225            }
226            catch ( IOException e )
227            {
228                throw new ScmRepositoryException( "Can't read " + cvsRootFile.getAbsolutePath() );
229            }
230            try
231            {
232                module = FileUtils.fileRead( moduleFile ).trim();
233            }
234            catch ( IOException e )
235            {
236                throw new ScmRepositoryException( "Can't read " + moduleFile.getAbsolutePath() );
237            }
238    
239            return makeProviderScmRepository( cvsRoot + ":" + module, ':' );
240        }
241    
242        /** {@inheritDoc} */
243        public List<String> validateScmUrl( String scmSpecificUrl, char delimiter )
244        {
245            ScmUrlParserResult result = parseScmUrl( scmSpecificUrl, delimiter );
246    
247            return result.getMessages();
248        }
249    
250        /** {@inheritDoc} */
251        public String getScmType()
252        {
253            return "cvs";
254        }
255    
256        /** {@inheritDoc} */
257        public AddScmResult add( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
258            throws ScmException
259        {
260            return (AddScmResult) executeCommand( getAddCommand(), repository, fileSet, parameters );
261        }
262    
263        /** {@inheritDoc} */
264        public BranchScmResult branch( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
265            throws ScmException
266        {
267            return (BranchScmResult) executeCommand( getBranchCommand(), repository, fileSet, parameters );
268        }
269    
270        /** {@inheritDoc} */
271        protected BlameScmResult blame( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
272            throws ScmException
273        {
274            return (BlameScmResult) executeCommand( getBlameCommand(), repository, fileSet, parameters );
275        }
276    
277        /** {@inheritDoc} */
278        public ChangeLogScmResult changelog( ScmProviderRepository repository, ScmFileSet fileSet,
279                                             CommandParameters parameters )
280            throws ScmException
281        {
282            return (ChangeLogScmResult) executeCommand( getChangeLogCommand(), repository, fileSet, parameters );
283        }
284    
285        /** {@inheritDoc} */
286        public CheckInScmResult checkin( ScmProviderRepository repository, ScmFileSet fileSet,
287                                         CommandParameters parameters )
288            throws ScmException
289        {
290            return (CheckInScmResult) executeCommand( getCheckInCommand(), repository, fileSet, parameters );
291        }
292    
293        /** {@inheritDoc} */
294        public CheckOutScmResult checkout( ScmProviderRepository repository, ScmFileSet fileSet,
295                                           CommandParameters parameters )
296            throws ScmException
297        {
298            return (CheckOutScmResult) executeCommand( getCheckOutCommand(), repository, fileSet, parameters );
299        }
300    
301        /** {@inheritDoc} */
302        public DiffScmResult diff( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
303            throws ScmException
304        {
305            return (DiffScmResult) executeCommand( getDiffCommand(), repository, fileSet, parameters );
306        }
307    
308        /** {@inheritDoc} */
309        protected ExportScmResult export( ScmProviderRepository repository, ScmFileSet fileSet,
310                                          CommandParameters parameters )
311            throws ScmException
312        {
313            return (ExportScmResult) executeCommand( getExportCommand(), repository, fileSet, parameters );
314        }
315    
316        /** {@inheritDoc} */
317        public LoginScmResult login( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
318            throws ScmException
319        {
320            return (LoginScmResult) executeCommand( getLoginCommand(), repository, fileSet, parameters );
321        }
322    
323        /** {@inheritDoc} */
324        public RemoveScmResult remove( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
325            throws ScmException
326        {
327            return (RemoveScmResult) executeCommand( getRemoveCommand(), repository, fileSet, parameters );
328        }
329    
330        /** {@inheritDoc} */
331        public StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
332            throws ScmException
333        {
334            return (StatusScmResult) executeCommand( getStatusCommand(), repository, fileSet, parameters );
335        }
336    
337        /** {@inheritDoc} */
338        public TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
339            throws ScmException
340        {
341            return (TagScmResult) executeCommand( getTagCommand(), repository, fileSet, parameters );
342        }
343        
344        protected TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters,
345                                    ScmTagParameters scmParameters )
346            throws ScmException
347        {
348            return (TagScmResult) getTagCommand().execute( repository, fileSet, parameters );
349        }
350        
351    
352        /** {@inheritDoc} */
353        public UpdateScmResult update( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
354            throws ScmException
355        {
356            return (UpdateScmResult) executeCommand( getUpdateCommand(), repository, fileSet, parameters );
357        }
358    
359        /** {@inheritDoc} */
360        protected ListScmResult list( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
361            throws ScmException
362        {
363            return (ListScmResult) executeCommand( getListCommand(), repository, fileSet, parameters );
364        }
365        
366        /** {@inheritDoc} */
367        protected MkdirScmResult mkdir( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
368            throws ScmException
369        {
370            return (MkdirScmResult) executeCommand( getMkdirCommand(), repository, fileSet, parameters );
371        }
372    
373        /**
374         * @param basedir not null
375         * @param f not null
376         * @return the relative path
377         * @throws ScmException if any
378         * @throws IOException if any
379         */
380        public static String getRelativePath( File basedir, File f )
381            throws ScmException, IOException
382        {
383            File fileOrDir = getAbsoluteFilePath( f );
384    
385            if ( !fileOrDir.getPath().startsWith( basedir.getPath() ) )
386            {
387                throw new ScmException( fileOrDir.getPath() + " was not contained in " + basedir.getPath() );
388            }
389    
390            return fileOrDir.getPath().substring( basedir.getPath().length() + 1, fileOrDir.getPath().length() );
391        }
392    
393        // ----------------------------------------------------------------------
394        // Protected methods
395        // ----------------------------------------------------------------------
396    
397        protected ScmUrlParserResult parseScmUrl( String scmSpecificUrl, char delimiter )
398        {
399            ScmUrlParserResult result = new ScmUrlParserResult();
400    
401            String[] tokens = StringUtils.split( scmSpecificUrl, Character.toString( delimiter ) );
402    
403            if ( tokens.length < 3 )
404            {
405                result.getMessages().add( "The connection string contains too few tokens." );
406    
407                return result;
408            }
409    
410            String cvsroot;
411    
412            String transport = tokens[0];
413    
414            if ( transport.equalsIgnoreCase( TRANSPORT_LOCAL ) )
415            {
416                // use the local repository directory eg. '/home/cvspublic'
417                cvsroot = tokens[1];
418            }
419            else if ( transport.equalsIgnoreCase( TRANSPORT_PSERVER ) || transport.equalsIgnoreCase( TRANSPORT_LSERVER )
420                || transport.equalsIgnoreCase( TRANSPORT_EXT ) || transport.equalsIgnoreCase( TRANSPORT_SSPI ) )
421            {
422                if ( tokens.length != 4 && transport.equalsIgnoreCase( TRANSPORT_EXT ) )
423                {
424                    result.getMessages().add( "The connection string contains too few tokens." );
425    
426                    return result;
427                }
428                else if ( ( tokens.length < 4 || tokens.length > 6 ) && transport.equalsIgnoreCase( TRANSPORT_PSERVER ) )
429                {
430                    result.getMessages().add( "The connection string contains too few tokens." );
431    
432                    return result;
433                }
434                else if ( tokens.length < 4 || tokens.length > 5 && !transport.equalsIgnoreCase( TRANSPORT_PSERVER ) )
435                {
436                    result.getMessages().add( "The connection string contains too few tokens." );
437    
438                    return result;
439                }
440                else if ( tokens.length < 4 || tokens.length > 5 && transport.equalsIgnoreCase( TRANSPORT_SSPI ) )
441                {
442                    result.getMessages().add( "The connection string contains too few tokens." );
443    
444                    return result;
445                }
446    
447                if ( transport.equalsIgnoreCase( TRANSPORT_LSERVER ) )
448                {
449                    //create the cvsroot as the local socket cvsroot
450                    cvsroot = tokens[1] + ":" + tokens[2];
451                }
452                else
453                {
454                    //create the cvsroot as the remote cvsroot
455                    if ( tokens.length == 4 )
456                    {
457                        cvsroot = ":" + transport + ":" + tokens[1] + ":" + tokens[2];
458                    }
459                    else
460                    {
461                        cvsroot = ":" + transport + ":" + tokens[1] + ":" + tokens[2] + ":" + tokens[3];
462                    }
463                }
464            }
465            else
466            {
467                result.getMessages().add( "Unknown transport: " + transport );
468    
469                return result;
470            }
471    
472            String user = null;
473    
474            String password = null;
475    
476            String host = null;
477    
478            String path = null;
479    
480            String module = null;
481    
482            int port = -1;
483    
484            if ( transport.equalsIgnoreCase( TRANSPORT_PSERVER ) )
485            {
486                // set default port, it's necessary for checking entries in .cvspass
487                port = 2401;
488    
489                if ( tokens.length == 4 )
490                {
491                    //pserver:[username@]host:path:module
492                    String userhost = tokens[1];
493    
494                    int index = userhost.indexOf( '@' );
495    
496                    if ( index == -1 )
497                    {
498                        host = userhost;
499                    }
500                    else
501                    {
502                        user = userhost.substring( 0, index );
503    
504                        host = userhost.substring( index + 1 );
505                    }
506    
507                    path = tokens[2];
508    
509                    module = tokens[3];
510                }
511                else if ( tokens.length == 6 )
512                {
513                    //pserver:username:password@host:port:path:module
514                    user = tokens[1];
515    
516                    String passhost = tokens[2];
517    
518                    int index = passhost.indexOf( '@' );
519    
520                    if ( index == -1 )
521                    {
522                        result.getMessages()
523                            .add( "The user_password_host part must be on the form: <username>:<password>@<hostname>." );
524    
525                        return result;
526                    }
527    
528                    password = passhost.substring( 0, index );
529    
530                    host = passhost.substring( index + 1 );
531    
532                    port = new Integer( tokens[3] ).intValue();
533    
534                    path = tokens[4];
535    
536                    module = tokens[5];
537                }
538                else
539                {
540                    //tokens.length == 5
541                    if ( tokens[1].indexOf( '@' ) > 0 )
542                    {
543                        //pserver:username@host:port:path:module
544                        String userhost = tokens[1];
545    
546                        int index = userhost.indexOf( '@' );
547    
548                        user = userhost.substring( 0, index );
549    
550                        host = userhost.substring( index + 1 );
551    
552                        port = new Integer( tokens[2] ).intValue();
553                    }
554                    else if ( tokens[2].indexOf( '@' ) >= 0 )
555                    {
556                        //pserver:username:password@host:path:module
557                        //<username>:<password>@<hostname>
558                        user = tokens[1];
559    
560                        String passhost = tokens[2];
561    
562                        int index = passhost.indexOf( '@' );
563    
564                        password = passhost.substring( 0, index );
565    
566                        host = passhost.substring( index + 1 );
567                    }
568                    else
569                    {
570                        //pserver:host:port:path:module
571                        try
572                        {
573                            port = new Integer( tokens[2] ).intValue();
574                        }
575                        catch ( Exception e )
576                        {
577                            //incorrect
578                            result.getMessages().add( "Your scm url is invalid." );
579    
580                            return result;
581                        }
582    
583                        host = tokens[1];
584                    }
585    
586                    path = tokens[3];
587    
588                    module = tokens[4];
589                }
590    
591                String userHost = host;
592    
593                if ( user != null )
594                {
595                    userHost = user + "@" + host;
596                }
597    
598                // cvsroot format is :pserver:[user@]host:[port]path
599                cvsroot = ":" + transport + ":" + userHost + ":";
600    
601                if ( port != -1 )
602                {
603                    cvsroot += port;
604                }
605    
606                cvsroot += path;
607            }
608            else if ( transport.equalsIgnoreCase( TRANSPORT_SSPI ) )
609            {
610                //sspi:[username@]host:[port]path:module
611                String userhost = tokens[1];
612    
613                int index = userhost.indexOf( '@' );
614    
615                if ( index == -1 )
616                {
617                    user = "";
618    
619                    host = userhost;
620                }
621                else
622                {
623                    user = userhost.substring( 0, index );
624    
625                    host = userhost.substring( index + 1 );
626                }
627    
628                // no port specified
629                if ( tokens.length == 4 )
630                {
631                    path = tokens[2];
632                    module = tokens[3];
633                }
634                else
635                {
636                    // getting port
637                    try
638                    {
639                        port = new Integer( tokens[2] ).intValue();
640                        path = tokens[3];
641                        module = tokens[4];
642                    }
643                    catch ( Exception e )
644                    {
645                        //incorrect
646                        result.getMessages().add( "Your scm url is invalid, could not get port value." );
647    
648                        return result;
649                    }
650                }
651    
652                // cvsroot format is :sspi:host:path
653                cvsroot = ":" + transport + ":" + host + ":";
654    
655                if ( port != -1 )
656                {
657                    cvsroot += port;
658                }
659    
660                cvsroot += path;
661            }
662            else
663            {
664                if ( !transport.equalsIgnoreCase( TRANSPORT_LOCAL ) )
665                {
666                    String userhost = tokens[1];
667    
668                    int index = userhost.indexOf( '@' );
669    
670                    if ( index == -1 )
671                    {
672                        host = userhost;
673                    }
674                    else
675                    {
676                        user = userhost.substring( 0, index );
677    
678                        host = userhost.substring( index + 1 );
679                    }
680                }
681    
682                if ( transport.equals( TRANSPORT_LOCAL ) )
683                {
684                    path = tokens[1];
685    
686                    module = tokens[2];
687    
688                    if ( module != null && module.startsWith( "/" ) )
689                    {
690                        module = module.substring( 1 );
691                    }
692    
693                }
694                else
695                {
696                    if ( tokens.length == 4 )
697                    {
698                        path = tokens[2];
699    
700                        module = tokens[3];
701                    }
702                    else
703                    {
704                        port = new Integer( tokens[2] ).intValue();
705    
706                        path = tokens[3];
707    
708                        module = tokens[4];
709                    }
710                }
711            }
712    
713            if ( port == -1 )
714            {
715                result.setRepository( new CvsScmProviderRepository( cvsroot, transport, user, password, host, path,
716                                                                    module ) );
717            }
718            else
719            {
720                result.setRepository( new CvsScmProviderRepository( cvsroot, transport, user, password, host, port,
721                                                                    path, module ) );
722            }
723    
724            return result;
725        }
726    
727        protected abstract Command getAddCommand();
728    
729        protected abstract Command getBranchCommand();
730    
731        protected abstract Command getBlameCommand();
732    
733        protected abstract Command getChangeLogCommand();
734    
735        protected abstract Command getCheckInCommand();
736    
737        protected abstract Command getCheckOutCommand();
738    
739        protected abstract Command getDiffCommand();
740    
741        protected abstract Command getExportCommand();
742    
743        protected abstract Command getListCommand();
744    
745        protected abstract Command getLoginCommand();
746    
747        protected abstract Command getRemoveCommand();
748    
749        protected abstract Command getStatusCommand();
750    
751        protected abstract Command getTagCommand();
752    
753        protected abstract Command getUpdateCommand();
754        
755        protected abstract Command getMkdirCommand();
756    
757        // ----------------------------------------------------------------------
758        // Private methods
759        // ----------------------------------------------------------------------
760    
761        private ScmResult executeCommand( Command command, ScmProviderRepository repository, ScmFileSet fileSet,
762                                          CommandParameters parameters )
763            throws ScmException
764        {
765            fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
766    
767            command.setLogger( getLogger() );
768    
769            return command.execute( repository, fileSet, parameters );
770        }
771    
772    
773        /**
774         * CVS provider requires that all files in ScmFileSet must be relative to basedir
775         * This function ensures and converts all absolute paths to relative paths
776         *
777         * @param currentFileSet
778         * @return
779         * @throws ScmException
780         */
781        private static ScmFileSet fixUpScmFileSetAbsoluteFilePath( ScmFileSet currentFileSet )
782            throws ScmException
783        {
784            ScmFileSet newFileSet = null;
785    
786            try
787            {
788                File basedir = getAbsoluteFilePath( currentFileSet.getBasedir() );
789                List<File> fixedFiles = new ArrayList<File>(currentFileSet.getFileList().size());
790                for ( File file : currentFileSet.getFileList() )
791                {
792                    if ( file.isAbsolute() )
793                    {
794                        fixedFiles.add( new File( getRelativePath( basedir, file ) ) );
795                    } else {
796                        fixedFiles.add( file );
797                    }
798                }
799    
800                newFileSet = new ScmFileSet( basedir, fixedFiles );
801            }
802            catch ( IOException e )
803            {
804                throw new ScmException( "Invalid file set.", e );
805            }
806    
807            return newFileSet;
808        }
809    
810        private static File getAbsoluteFilePath( File fileOrDir )
811            throws IOException
812        {
813            String javaPathString = fileOrDir.getCanonicalPath().replace( '\\', '/' );
814    
815            if ( javaPathString.endsWith( "/" ) )
816            {
817                javaPathString = javaPathString.substring( 0, javaPathString.length() - 1 );
818            }
819    
820            return new File( javaPathString );
821        }
822    }