View Javadoc
1   package org.apache.maven.scm.provider.cvslib;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import org.apache.maven.scm.CommandParameters;
28  import org.apache.maven.scm.ScmException;
29  import org.apache.maven.scm.ScmFileSet;
30  import org.apache.maven.scm.ScmResult;
31  import org.apache.maven.scm.ScmTagParameters;
32  import org.apache.maven.scm.command.Command;
33  import org.apache.maven.scm.command.add.AddScmResult;
34  import org.apache.maven.scm.command.blame.BlameScmResult;
35  import org.apache.maven.scm.command.branch.BranchScmResult;
36  import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
37  import org.apache.maven.scm.command.checkin.CheckInScmResult;
38  import org.apache.maven.scm.command.checkout.CheckOutScmResult;
39  import org.apache.maven.scm.command.diff.DiffScmResult;
40  import org.apache.maven.scm.command.export.ExportScmResult;
41  import org.apache.maven.scm.command.list.ListScmResult;
42  import org.apache.maven.scm.command.login.LoginScmResult;
43  import org.apache.maven.scm.command.mkdir.MkdirScmResult;
44  import org.apache.maven.scm.command.remove.RemoveScmResult;
45  import org.apache.maven.scm.command.status.StatusScmResult;
46  import org.apache.maven.scm.command.tag.TagScmResult;
47  import org.apache.maven.scm.command.update.UpdateScmResult;
48  import org.apache.maven.scm.provider.AbstractScmProvider;
49  import org.apache.maven.scm.provider.ScmProviderRepository;
50  import org.apache.maven.scm.provider.cvslib.repository.CvsScmProviderRepository;
51  import org.apache.maven.scm.repository.ScmRepositoryException;
52  import org.apache.maven.scm.repository.UnknownRepositoryStructure;
53  import org.codehaus.plexus.util.FileUtils;
54  import org.codehaus.plexus.util.StringUtils;
55  
56  /**
57   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse </a>
58   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
59   *
60   */
61  public abstract class AbstractCvsScmProvider
62      extends AbstractScmProvider
63  {
64      /** ext transport method */
65      public static final String TRANSPORT_EXT = "ext";
66  
67      /** local transport method */
68      public static final String TRANSPORT_LOCAL = "local";
69  
70      /** lserver transport method */
71      public static final String TRANSPORT_LSERVER = "lserver";
72  
73      /** pserver transport method */
74      public static final String TRANSPORT_PSERVER = "pserver";
75  
76      /** sspi transport method */
77      public static final String TRANSPORT_SSPI = "sspi";
78  
79      // ----------------------------------------------------------------------
80      //
81      // ----------------------------------------------------------------------
82  
83      /**
84       * The current ScmUrlParserResult
85       *
86       * @since 1.1.1
87       */
88      public static class ScmUrlParserResult
89      {
90          private List<String> messages;
91  
92          private ScmProviderRepository repository;
93  
94          public ScmUrlParserResult()
95          {
96              messages = new ArrayList<String>();
97          }
98  
99          /**
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 )
203         {
204             throw new NullPointerException( "Path argument is null" );
205         }
206 
207         if ( !path.isDirectory() )
208         {
209             throw new ScmRepositoryException( path.getAbsolutePath() + " isn't a valid directory." );
210         }
211 
212         File cvsDirectory = new File( path, "CVS" );
213 
214         if ( !cvsDirectory.exists() )
215         {
216             throw new ScmRepositoryException( path.getAbsolutePath() + " isn't a cvs checkout directory." );
217         }
218 
219         File cvsRootFile = new File( cvsDirectory, "Root" );
220 
221         File moduleFile = new File( cvsDirectory, "Repository" );
222 
223         String cvsRoot;
224 
225         String module;
226 
227         try
228         {
229             cvsRoot = FileUtils.fileRead( cvsRootFile ).trim().substring( 1 );
230         }
231         catch ( IOException e )
232         {
233             throw new ScmRepositoryException( "Can't read " + cvsRootFile.getAbsolutePath() );
234         }
235         try
236         {
237             module = FileUtils.fileRead( moduleFile ).trim();
238         }
239         catch ( IOException e )
240         {
241             throw new ScmRepositoryException( "Can't read " + moduleFile.getAbsolutePath() );
242         }
243 
244         return makeProviderScmRepository( cvsRoot + ":" + module, ':' );
245     }
246 
247     /** {@inheritDoc} */
248     public List<String> validateScmUrl( String scmSpecificUrl, char delimiter )
249     {
250         ScmUrlParserResult result = parseScmUrl( scmSpecificUrl, delimiter );
251 
252         return result.getMessages();
253     }
254 
255     /** {@inheritDoc} */
256     public String getScmType()
257     {
258         return "cvs";
259     }
260 
261     /** {@inheritDoc} */
262     public AddScmResult add( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
263         throws ScmException
264     {
265         return (AddScmResult) executeCommand( getAddCommand(), repository, fileSet, parameters );
266     }
267 
268     /** {@inheritDoc} */
269     public BranchScmResult branch( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
270         throws ScmException
271     {
272         return (BranchScmResult) executeCommand( getBranchCommand(), repository, fileSet, parameters );
273     }
274 
275     /** {@inheritDoc} */
276     protected BlameScmResult blame( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
277         throws ScmException
278     {
279         return (BlameScmResult) executeCommand( getBlameCommand(), repository, fileSet, parameters );
280     }
281 
282     /** {@inheritDoc} */
283     public ChangeLogScmResult changelog( ScmProviderRepository repository, ScmFileSet fileSet,
284                                          CommandParameters parameters )
285         throws ScmException
286     {
287         return (ChangeLogScmResult) executeCommand( getChangeLogCommand(), repository, fileSet, parameters );
288     }
289 
290     /** {@inheritDoc} */
291     public CheckInScmResult checkin( ScmProviderRepository repository, ScmFileSet fileSet,
292                                      CommandParameters parameters )
293         throws ScmException
294     {
295         return (CheckInScmResult) executeCommand( getCheckInCommand(), repository, fileSet, parameters );
296     }
297 
298     /** {@inheritDoc} */
299     public CheckOutScmResult checkout( ScmProviderRepository repository, ScmFileSet fileSet,
300                                        CommandParameters parameters )
301         throws ScmException
302     {
303         return (CheckOutScmResult) executeCommand( getCheckOutCommand(), repository, fileSet, parameters );
304     }
305 
306     /** {@inheritDoc} */
307     public DiffScmResult diff( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
308         throws ScmException
309     {
310         return (DiffScmResult) executeCommand( getDiffCommand(), repository, fileSet, parameters );
311     }
312 
313     /** {@inheritDoc} */
314     protected ExportScmResult export( ScmProviderRepository repository, ScmFileSet fileSet,
315                                       CommandParameters parameters )
316         throws ScmException
317     {
318         return (ExportScmResult) executeCommand( getExportCommand(), repository, fileSet, parameters );
319     }
320 
321     /** {@inheritDoc} */
322     public LoginScmResult login( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
323         throws ScmException
324     {
325         return (LoginScmResult) executeCommand( getLoginCommand(), repository, fileSet, parameters );
326     }
327 
328     /** {@inheritDoc} */
329     public RemoveScmResult remove( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
330         throws ScmException
331     {
332         return (RemoveScmResult) executeCommand( getRemoveCommand(), repository, fileSet, parameters );
333     }
334 
335     /** {@inheritDoc} */
336     public StatusScmResult status( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
337         throws ScmException
338     {
339         return (StatusScmResult) executeCommand( getStatusCommand(), repository, fileSet, parameters );
340     }
341 
342     /** {@inheritDoc} */
343     public TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
344         throws ScmException
345     {
346         return (TagScmResult) executeCommand( getTagCommand(), repository, fileSet, parameters );
347     }
348     
349     protected TagScmResult tag( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters,
350                                 ScmTagParameters scmParameters )
351         throws ScmException
352     {
353         return (TagScmResult) getTagCommand().execute( repository, fileSet, parameters );
354     }
355     
356 
357     /** {@inheritDoc} */
358     public UpdateScmResult update( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
359         throws ScmException
360     {
361         return (UpdateScmResult) executeCommand( getUpdateCommand(), repository, fileSet, parameters );
362     }
363 
364     /** {@inheritDoc} */
365     protected ListScmResult list( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
366         throws ScmException
367     {
368         return (ListScmResult) executeCommand( getListCommand(), repository, fileSet, parameters );
369     }
370     
371     /** {@inheritDoc} */
372     protected MkdirScmResult mkdir( ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters )
373         throws ScmException
374     {
375         return (MkdirScmResult) executeCommand( getMkdirCommand(), repository, fileSet, parameters );
376     }
377 
378     /**
379      * @param basedir not null
380      * @param f not null
381      * @return the relative path
382      * @throws ScmException if any
383      * @throws IOException if any
384      */
385     public static String getRelativePath( File basedir, File f )
386         throws ScmException, IOException
387     {
388         File fileOrDir = getAbsoluteFilePath( f );
389 
390         if ( !fileOrDir.getPath().startsWith( basedir.getPath() ) )
391         {
392             throw new ScmException( fileOrDir.getPath() + " was not contained in " + basedir.getPath() );
393         }
394 
395         return fileOrDir.getPath().substring( basedir.getPath().length() + 1, fileOrDir.getPath().length() );
396     }
397 
398     // ----------------------------------------------------------------------
399     // Protected methods
400     // ----------------------------------------------------------------------
401 
402     protected ScmUrlParserResult parseScmUrl( String scmSpecificUrl, char delimiter )
403     {
404         ScmUrlParserResult result = new ScmUrlParserResult();
405 
406         String[] tokens = StringUtils.split( scmSpecificUrl, Character.toString( delimiter ) );
407 
408         if ( tokens.length < 3 )
409         {
410             result.getMessages().add( "The connection string contains too few tokens." );
411 
412             return result;
413         }
414 
415         String cvsroot;
416 
417         String transport = tokens[0];
418 
419         if ( transport.equalsIgnoreCase( TRANSPORT_LOCAL ) )
420         {
421             // use the local repository directory eg. '/home/cvspublic'
422             cvsroot = tokens[1];
423         }
424         else if ( transport.equalsIgnoreCase( TRANSPORT_PSERVER ) || transport.equalsIgnoreCase( TRANSPORT_LSERVER )
425             || transport.equalsIgnoreCase( TRANSPORT_EXT ) || transport.equalsIgnoreCase( TRANSPORT_SSPI ) )
426         {
427             if ( tokens.length != 4 && transport.equalsIgnoreCase( TRANSPORT_EXT ) )
428             {
429                 result.getMessages().add( "The connection string contains too few tokens." );
430 
431                 return result;
432             }
433             else if ( ( tokens.length < 4 || tokens.length > 6 ) && transport.equalsIgnoreCase( TRANSPORT_PSERVER ) )
434             {
435                 result.getMessages().add( "The connection string contains too few tokens." );
436 
437                 return result;
438             }
439             else if ( tokens.length < 4 || tokens.length > 5 && !transport.equalsIgnoreCase( TRANSPORT_PSERVER ) )
440             {
441                 result.getMessages().add( "The connection string contains too few tokens." );
442 
443                 return result;
444             }
445             else if ( tokens.length < 4 || tokens.length > 5 && transport.equalsIgnoreCase( TRANSPORT_SSPI ) )
446             {
447                 result.getMessages().add( "The connection string contains too few tokens." );
448 
449                 return result;
450             }
451 
452             if ( transport.equalsIgnoreCase( TRANSPORT_LSERVER ) )
453             {
454                 //create the cvsroot as the local socket cvsroot
455                 cvsroot = tokens[1] + ":" + tokens[2];
456             }
457             else
458             {
459                 //create the cvsroot as the remote cvsroot
460                 if ( tokens.length == 4 )
461                 {
462                     cvsroot = ":" + transport + ":" + tokens[1] + ":" + tokens[2];
463                 }
464                 else
465                 {
466                     cvsroot = ":" + transport + ":" + tokens[1] + ":" + tokens[2] + ":" + tokens[3];
467                 }
468             }
469         }
470         else
471         {
472             result.getMessages().add( "Unknown transport: " + transport );
473 
474             return result;
475         }
476 
477         String user = null;
478 
479         String password = null;
480 
481         String host = null;
482 
483         String path = null;
484 
485         String module = null;
486 
487         int port = -1;
488 
489         if ( transport.equalsIgnoreCase( TRANSPORT_PSERVER ) )
490         {
491             // set default port, it's necessary for checking entries in .cvspass
492             port = 2401;
493 
494             if ( tokens.length == 4 )
495             {
496                 //pserver:[username@]host:path:module
497                 String userhost = tokens[1];
498 
499                 int index = userhost.indexOf( '@' );
500 
501                 if ( index == -1 )
502                 {
503                     host = userhost;
504                 }
505                 else
506                 {
507                     user = userhost.substring( 0, index );
508 
509                     host = userhost.substring( index + 1 );
510                 }
511 
512                 path = tokens[2];
513 
514                 module = tokens[3];
515             }
516             else if ( tokens.length == 6 )
517             {
518                 //pserver:username:password@host:port:path:module
519                 user = tokens[1];
520 
521                 String passhost = tokens[2];
522 
523                 int index = passhost.indexOf( '@' );
524 
525                 if ( index == -1 )
526                 {
527                     result.getMessages()
528                         .add( "The user_password_host part must be on the form: <username>:<password>@<hostname>." );
529 
530                     return result;
531                 }
532 
533                 password = passhost.substring( 0, index );
534 
535                 host = passhost.substring( index + 1 );
536 
537                 port = Integer.valueOf( tokens[3] ).intValue();
538 
539                 path = tokens[4];
540 
541                 module = tokens[5];
542             }
543             else
544             {
545                 //tokens.length == 5
546                 if ( tokens[1].indexOf( '@' ) > 0 )
547                 {
548                     //pserver:username@host:port:path:module
549                     String userhost = tokens[1];
550 
551                     int index = userhost.indexOf( '@' );
552 
553                     user = userhost.substring( 0, index );
554 
555                     host = userhost.substring( index + 1 );
556 
557                     port = new Integer( tokens[2] ).intValue();
558                 }
559                 else if ( tokens[2].indexOf( '@' ) >= 0 )
560                 {
561                     //pserver:username:password@host:path:module
562                     //<username>:<password>@<hostname>
563                     user = tokens[1];
564 
565                     String passhost = tokens[2];
566 
567                     int index = passhost.indexOf( '@' );
568 
569                     password = passhost.substring( 0, index );
570 
571                     host = passhost.substring( index + 1 );
572                 }
573                 else
574                 {
575                     //pserver:host:port:path:module
576                     try
577                     {
578                         port = new Integer( tokens[2] ).intValue();
579                     }
580                     catch ( Exception e )
581                     {
582                         //incorrect
583                         result.getMessages().add( "Your scm url is invalid." );
584 
585                         return result;
586                     }
587 
588                     host = tokens[1];
589                 }
590 
591                 path = tokens[3];
592 
593                 module = tokens[4];
594             }
595 
596             String userHost = host;
597 
598             if ( user != null )
599             {
600                 userHost = user + "@" + host;
601             }
602 
603             // cvsroot format is :pserver:[user@]host:[port]path
604             cvsroot = ":" + transport + ":" + userHost + ":";
605 
606             if ( port != -1 )
607             {
608                 cvsroot += port;
609             }
610 
611             cvsroot += path;
612         }
613         else if ( transport.equalsIgnoreCase( TRANSPORT_SSPI ) )
614         {
615             //sspi:[username@]host:[port]path:module
616             String userhost = tokens[1];
617 
618             int index = userhost.indexOf( '@' );
619 
620             if ( index == -1 )
621             {
622                 user = "";
623 
624                 host = userhost;
625             }
626             else
627             {
628                 user = userhost.substring( 0, index );
629 
630                 host = userhost.substring( index + 1 );
631             }
632 
633             // no port specified
634             if ( tokens.length == 4 )
635             {
636                 path = tokens[2];
637                 module = tokens[3];
638             }
639             else
640             {
641                 // getting port
642                 try
643                 {
644                     port = new Integer( tokens[2] ).intValue();
645                     path = tokens[3];
646                     module = tokens[4];
647                 }
648                 catch ( Exception e )
649                 {
650                     //incorrect
651                     result.getMessages().add( "Your scm url is invalid, could not get port value." );
652 
653                     return result;
654                 }
655             }
656 
657             // cvsroot format is :sspi:host:path
658             cvsroot = ":" + transport + ":" + host + ":";
659 
660             if ( port != -1 )
661             {
662                 cvsroot += port;
663             }
664 
665             cvsroot += path;
666         }
667         else
668         {
669             if ( !transport.equalsIgnoreCase( TRANSPORT_LOCAL ) )
670             {
671                 String userhost = tokens[1];
672 
673                 int index = userhost.indexOf( '@' );
674 
675                 if ( index == -1 )
676                 {
677                     host = userhost;
678                 }
679                 else
680                 {
681                     user = userhost.substring( 0, index );
682 
683                     host = userhost.substring( index + 1 );
684                 }
685             }
686 
687             if ( transport.equals( TRANSPORT_LOCAL ) )
688             {
689                 path = tokens[1];
690 
691                 module = tokens[2];
692 
693                 if ( module != null && module.startsWith( "/" ) )
694                 {
695                     module = module.substring( 1 );
696                 }
697 
698             }
699             else
700             {
701                 if ( tokens.length == 4 )
702                 {
703                     path = tokens[2];
704 
705                     module = tokens[3];
706                 }
707                 else
708                 {
709                     port = new Integer( tokens[2] ).intValue();
710 
711                     path = tokens[3];
712 
713                     module = tokens[4];
714                 }
715             }
716         }
717 
718         if ( port == -1 )
719         {
720             result.setRepository( new CvsScmProviderRepository( cvsroot, transport, user, password, host, path,
721                                                                 module ) );
722         }
723         else
724         {
725             result.setRepository( new CvsScmProviderRepository( cvsroot, transport, user, password, host, port,
726                                                                 path, module ) );
727         }
728 
729         return result;
730     }
731 
732     protected abstract Command getAddCommand();
733 
734     protected abstract Command getBranchCommand();
735 
736     protected abstract Command getBlameCommand();
737 
738     protected abstract Command getChangeLogCommand();
739 
740     protected abstract Command getCheckInCommand();
741 
742     protected abstract Command getCheckOutCommand();
743 
744     protected abstract Command getDiffCommand();
745 
746     protected abstract Command getExportCommand();
747 
748     protected abstract Command getListCommand();
749 
750     protected abstract Command getLoginCommand();
751 
752     protected abstract Command getRemoveCommand();
753 
754     protected abstract Command getStatusCommand();
755 
756     protected abstract Command getTagCommand();
757 
758     protected abstract Command getUpdateCommand();
759     
760     protected abstract Command getMkdirCommand();
761 
762     // ----------------------------------------------------------------------
763     // Private methods
764     // ----------------------------------------------------------------------
765 
766     private ScmResult executeCommand( Command command, ScmProviderRepository repository, ScmFileSet fileSet,
767                                       CommandParameters parameters )
768         throws ScmException
769     {
770         fileSet = fixUpScmFileSetAbsoluteFilePath( fileSet );
771 
772         command.setLogger( getLogger() );
773 
774         return command.execute( repository, fileSet, parameters );
775     }
776 
777 
778     /**
779      * CVS provider requires that all files in ScmFileSet must be relative to basedir
780      * This function ensures and converts all absolute paths to relative paths
781      *
782      * @param currentFileSet
783      * @return
784      * @throws ScmException
785      */
786     private static ScmFileSet fixUpScmFileSetAbsoluteFilePath( ScmFileSet currentFileSet )
787         throws ScmException
788     {
789         ScmFileSet newFileSet = null;
790 
791         try
792         {
793             File basedir = getAbsoluteFilePath( currentFileSet.getBasedir() );
794             List<File> fixedFiles = new ArrayList<File>( currentFileSet.getFileList().size() );
795             for ( File file : currentFileSet.getFileList() )
796             {
797                 if ( file.isAbsolute() )
798                 {
799                     fixedFiles.add( new File( getRelativePath( basedir, file ) ) );
800                 }
801                 else
802                 {
803                     fixedFiles.add( file );
804                 }
805             }
806 
807             newFileSet = new ScmFileSet( basedir, fixedFiles );
808         }
809         catch ( IOException e )
810         {
811             throw new ScmException( "Invalid file set.", e );
812         }
813 
814         return newFileSet;
815     }
816 
817     private static File getAbsoluteFilePath( File fileOrDir )
818         throws IOException
819     {
820         String javaPathString = fileOrDir.getCanonicalPath().replace( '\\', '/' );
821 
822         if ( javaPathString.endsWith( "/" ) )
823         {
824             javaPathString = javaPathString.substring( 0, javaPathString.length() - 1 );
825         }
826 
827         return new File( javaPathString );
828     }
829 }