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 || !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 = Integer.valueOf( 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 }