001package 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 022import java.io.File; 023import java.io.IOException; 024import java.util.ArrayList; 025import java.util.List; 026 027import org.apache.maven.scm.CommandParameters; 028import org.apache.maven.scm.ScmException; 029import org.apache.maven.scm.ScmFileSet; 030import org.apache.maven.scm.ScmResult; 031import org.apache.maven.scm.ScmTagParameters; 032import org.apache.maven.scm.command.Command; 033import org.apache.maven.scm.command.add.AddScmResult; 034import org.apache.maven.scm.command.blame.BlameScmResult; 035import org.apache.maven.scm.command.branch.BranchScmResult; 036import org.apache.maven.scm.command.changelog.ChangeLogScmResult; 037import org.apache.maven.scm.command.checkin.CheckInScmResult; 038import org.apache.maven.scm.command.checkout.CheckOutScmResult; 039import org.apache.maven.scm.command.diff.DiffScmResult; 040import org.apache.maven.scm.command.export.ExportScmResult; 041import org.apache.maven.scm.command.list.ListScmResult; 042import org.apache.maven.scm.command.login.LoginScmResult; 043import org.apache.maven.scm.command.mkdir.MkdirScmResult; 044import org.apache.maven.scm.command.remove.RemoveScmResult; 045import org.apache.maven.scm.command.status.StatusScmResult; 046import org.apache.maven.scm.command.tag.TagScmResult; 047import org.apache.maven.scm.command.update.UpdateScmResult; 048import org.apache.maven.scm.provider.AbstractScmProvider; 049import org.apache.maven.scm.provider.ScmProviderRepository; 050import org.apache.maven.scm.provider.cvslib.repository.CvsScmProviderRepository; 051import org.apache.maven.scm.repository.ScmRepositoryException; 052import org.apache.maven.scm.repository.UnknownRepositoryStructure; 053import org.codehaus.plexus.util.FileUtils; 054import 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øl</a> 059 * 060 */ 061public 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 = 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 } 796 else 797 { 798 fixedFiles.add( file ); 799 } 800 } 801 802 newFileSet = new ScmFileSet( basedir, fixedFiles ); 803 } 804 catch ( IOException e ) 805 { 806 throw new ScmException( "Invalid file set.", e ); 807 } 808 809 return newFileSet; 810 } 811 812 private static File getAbsoluteFilePath( File fileOrDir ) 813 throws IOException 814 { 815 String javaPathString = fileOrDir.getCanonicalPath().replace( '\\', '/' ); 816 817 if ( javaPathString.endsWith( "/" ) ) 818 { 819 javaPathString = javaPathString.substring( 0, javaPathString.length() - 1 ); 820 } 821 822 return new File( javaPathString ); 823 } 824}