1 18 19 package org.apache.tools.ant.taskdefs; 20 21 import java.io.File ; 22 import java.io.IOException ; 23 import java.util.ArrayList ; 24 import java.util.Enumeration ; 25 import java.util.HashMap ; 26 import java.util.HashSet ; 27 import java.util.Hashtable ; 28 import java.util.Iterator ; 29 import java.util.List ; 30 import java.util.Map ; 31 import java.util.Vector ; 32 import org.apache.tools.ant.Task; 33 import org.apache.tools.ant.Project; 34 import org.apache.tools.ant.BuildException; 35 import org.apache.tools.ant.DirectoryScanner; 36 import org.apache.tools.ant.types.Mapper; 37 import org.apache.tools.ant.types.FileSet; 38 import org.apache.tools.ant.types.FilterSet; 39 import org.apache.tools.ant.types.FilterChain; 40 import org.apache.tools.ant.types.FilterSetCollection; 41 import org.apache.tools.ant.types.Resource; 42 import org.apache.tools.ant.types.ResourceCollection; 43 import org.apache.tools.ant.types.ResourceFactory; 44 import org.apache.tools.ant.types.resources.FileResource; 45 import org.apache.tools.ant.util.FileUtils; 46 import org.apache.tools.ant.util.FileNameMapper; 47 import org.apache.tools.ant.util.IdentityMapper; 48 import org.apache.tools.ant.util.ResourceUtils; 49 import org.apache.tools.ant.util.SourceFileScanner; 50 import org.apache.tools.ant.util.FlatFileNameMapper; 51 52 67 public class Copy extends Task { 68 static final File NULL_FILE_PLACEHOLDER = new File ("/NULL_FILE"); 69 static final String LINE_SEPARATOR = System.getProperty("line.separator"); 70 protected File file = null; protected File destFile = null; protected File destDir = null; protected Vector rcs = new Vector (); 75 76 private boolean enableMultipleMappings = false; 77 protected boolean filtering = false; 78 protected boolean preserveLastModified = false; 79 protected boolean forceOverwrite = false; 80 protected boolean flatten = false; 81 protected int verbosity = Project.MSG_VERBOSE; 82 protected boolean includeEmpty = true; 83 protected boolean failonerror = true; 84 85 protected Hashtable fileCopyMap = new Hashtable (); 86 protected Hashtable dirCopyMap = new Hashtable (); 87 protected Hashtable completeDirMap = new Hashtable (); 88 89 protected Mapper mapperElement = null; 90 protected FileUtils fileUtils; 91 private Vector filterChains = new Vector (); 92 private Vector filterSets = new Vector (); 93 private String inputEncoding = null; 94 private String outputEncoding = null; 95 private long granularity = 0; 96 98 101 public Copy() { 102 fileUtils = FileUtils.getFileUtils(); 103 granularity = fileUtils.getFileTimestampGranularity(); 104 } 105 106 110 protected FileUtils getFileUtils() { 111 return fileUtils; 112 } 113 114 118 public void setFile(File file) { 119 this.file = file; 120 } 121 122 126 public void setTofile(File destFile) { 127 this.destFile = destFile; 128 } 129 130 134 public void setTodir(File destDir) { 135 this.destDir = destDir; 136 } 137 138 142 public FilterChain createFilterChain() { 143 FilterChain filterChain = new FilterChain(); 144 filterChains.addElement(filterChain); 145 return filterChain; 146 } 147 148 152 public FilterSet createFilterSet() { 153 FilterSet filterSet = new FilterSet(); 154 filterSets.addElement(filterSet); 155 return filterSet; 156 } 157 158 166 public void setPreserveLastModified(String preserve) { 167 setPreserveLastModified(Project.toBoolean(preserve)); 168 } 169 170 174 public void setPreserveLastModified(boolean preserve) { 175 preserveLastModified = preserve; 176 } 177 178 185 public boolean getPreserveLastModified() { 186 return preserveLastModified; 187 } 188 189 194 protected Vector getFilterSets() { 195 return filterSets; 196 } 197 198 203 protected Vector getFilterChains() { 204 return filterChains; 205 } 206 207 211 public void setFiltering(boolean filtering) { 212 this.filtering = filtering; 213 } 214 215 221 public void setOverwrite(boolean overwrite) { 222 this.forceOverwrite = overwrite; 223 } 224 225 234 public void setFlatten(boolean flatten) { 235 this.flatten = flatten; 236 } 237 238 243 public void setVerbose(boolean verbose) { 244 this.verbosity = verbose ? Project.MSG_INFO : Project.MSG_VERBOSE; 245 } 246 247 251 public void setIncludeEmptyDirs(boolean includeEmpty) { 252 this.includeEmpty = includeEmpty; 253 } 254 255 266 public void setEnableMultipleMappings(boolean enableMultipleMappings) { 267 this.enableMultipleMappings = enableMultipleMappings; 268 } 269 270 274 public boolean isEnableMultipleMapping() { 275 return enableMultipleMappings; 276 } 277 278 283 public void setFailOnError(boolean failonerror) { 284 this.failonerror = failonerror; 285 } 286 287 291 public void addFileset(FileSet set) { 292 add(set); 293 } 294 295 300 public void add(ResourceCollection res) { 301 rcs.add(res); 302 } 303 304 309 public Mapper createMapper() throws BuildException { 310 if (mapperElement != null) { 311 throw new BuildException("Cannot define more than one mapper", 312 getLocation()); 313 } 314 mapperElement = new Mapper(getProject()); 315 return mapperElement; 316 } 317 318 323 public void add(FileNameMapper fileNameMapper) { 324 createMapper().add(fileNameMapper); 325 } 326 327 332 public void setEncoding(String encoding) { 333 this.inputEncoding = encoding; 334 if (outputEncoding == null) { 335 outputEncoding = encoding; 336 } 337 } 338 339 345 public String getEncoding() { 346 return inputEncoding; 347 } 348 349 354 public void setOutputEncoding(String encoding) { 355 this.outputEncoding = encoding; 356 } 357 358 365 public String getOutputEncoding() { 366 return outputEncoding; 367 } 368 369 378 public void setGranularity(long granularity) { 379 this.granularity = granularity; 380 } 381 382 386 public void execute() throws BuildException { 387 File savedFile = file; File savedDestFile = destFile; 389 File savedDestDir = destDir; 390 ResourceCollection savedRc = null; 391 if (file == null && destFile != null && rcs.size() == 1) { 392 savedRc = (ResourceCollection) rcs.elementAt(0); 394 } 395 validateAttributes(); 397 398 try { 399 if (file != null) { 401 if (file.exists()) { 402 if (destFile == null) { 403 destFile = new File (destDir, file.getName()); 404 } 405 if (forceOverwrite || !destFile.exists() 406 || (file.lastModified() - granularity 407 > destFile.lastModified())) { 408 fileCopyMap.put(file.getAbsolutePath(), 409 new String [] {destFile.getAbsolutePath()}); 410 } else { 411 log(file + " omitted as " + destFile 412 + " is up to date.", Project.MSG_VERBOSE); 413 } 414 } else { 415 String message = "Warning: Could not find file " 416 + file.getAbsolutePath() + " to copy."; 417 if (!failonerror) { 418 log(message, Project.MSG_ERR); 419 } else { 420 throw new BuildException(message); 421 } 422 } 423 } 424 426 440 441 HashMap filesByBasedir = new HashMap (); 442 HashMap dirsByBasedir = new HashMap (); 443 HashSet baseDirs = new HashSet (); 444 ArrayList nonFileResources = new ArrayList (); 445 for (int i = 0; i < rcs.size(); i++) { 446 ResourceCollection rc = (ResourceCollection) rcs.elementAt(i); 447 448 if (rc instanceof FileSet && rc.isFilesystemOnly()) { 450 FileSet fs = (FileSet) rc; 451 DirectoryScanner ds = null; 452 try { 453 ds = fs.getDirectoryScanner(getProject()); 454 } catch (BuildException e) { 455 if (failonerror 456 || !getMessage(e).endsWith(" not found.")) { 457 throw e; 458 } else { 459 log("Warning: " + getMessage(e), Project.MSG_ERR); 460 continue; 461 } 462 } 463 File fromDir = fs.getDir(getProject()); 464 465 String [] srcFiles = ds.getIncludedFiles(); 466 String [] srcDirs = ds.getIncludedDirectories(); 467 if (!flatten && mapperElement == null 468 && ds.isEverythingIncluded() && !fs.hasPatterns()) { 469 completeDirMap.put(fromDir, destDir); 470 } 471 add(fromDir, srcFiles, filesByBasedir); 472 add(fromDir, srcDirs, dirsByBasedir); 473 baseDirs.add(fromDir); 474 } else { 476 if (!rc.isFilesystemOnly() && !supportsNonFileResources()) { 477 throw new BuildException( 478 "Only FileSystem resources are supported."); 479 } 480 481 Iterator resources = rc.iterator(); 482 while (resources.hasNext()) { 483 Resource r = (Resource) resources.next(); 484 if (!r.isExists()) { 485 continue; 486 } 487 488 File baseDir = NULL_FILE_PLACEHOLDER; 489 String name = r.getName(); 490 if (r instanceof FileResource) { 491 FileResource fr = (FileResource) r; 492 baseDir = getKeyFile(fr.getBaseDir()); 493 if (fr.getBaseDir() == null) { 494 name = fr.getFile().getAbsolutePath(); 495 } 496 } 497 498 if (r.isDirectory() || r instanceof FileResource) { 502 add(baseDir, name, 503 r.isDirectory() ? dirsByBasedir 504 : filesByBasedir); 505 baseDirs.add(baseDir); 506 } else { nonFileResources.add(r); 509 } 510 } 511 } 512 } 513 514 Iterator iter = baseDirs.iterator(); 515 while (iter.hasNext()) { 516 File f = (File ) iter.next(); 517 List files = (List ) filesByBasedir.get(f); 518 List dirs = (List ) dirsByBasedir.get(f); 519 520 String [] srcFiles = new String [0]; 521 if (files != null) { 522 srcFiles = (String []) files.toArray(srcFiles); 523 } 524 String [] srcDirs = new String [0]; 525 if (dirs != null) { 526 srcDirs = (String []) dirs.toArray(srcDirs); 527 } 528 scan(f == NULL_FILE_PLACEHOLDER ? null : f, destDir, srcFiles, 529 srcDirs); 530 } 531 532 try { 534 doFileOperations(); 535 } catch (BuildException e) { 536 if (!failonerror) { 537 log("Warning: " + getMessage(e), Project.MSG_ERR); 538 } else { 539 throw e; 540 } 541 } 542 543 if (nonFileResources.size() > 0) { 544 Resource[] nonFiles = 545 (Resource[]) nonFileResources.toArray(new Resource[nonFileResources.size()]); 546 Map map = scan(nonFiles, destDir); 548 try { 549 doResourceOperations(map); 550 } catch (BuildException e) { 551 if (!failonerror) { 552 log("Warning: " + getMessage(e), Project.MSG_ERR); 553 } else { 554 throw e; 555 } 556 } 557 } 558 } finally { 559 file = savedFile; 562 destFile = savedDestFile; 563 destDir = savedDestDir; 564 if (savedRc != null) { 565 rcs.insertElementAt(savedRc, 0); 566 } 567 fileCopyMap.clear(); 568 dirCopyMap.clear(); 569 completeDirMap.clear(); 570 } 571 } 572 573 576 577 583 protected void validateAttributes() throws BuildException { 584 if (file == null && rcs.size() == 0) { 585 throw new BuildException( 586 "Specify at least one source--a file or a resource collection."); 587 } 588 if (destFile != null && destDir != null) { 589 throw new BuildException( 590 "Only one of tofile and todir may be set."); 591 } 592 if (destFile == null && destDir == null) { 593 throw new BuildException("One of tofile or todir must be set."); 594 } 595 if (file != null && file.isDirectory()) { 596 throw new BuildException("Use a resource collection to copy directories."); 597 } 598 if (destFile != null && rcs.size() > 0) { 599 if (rcs.size() > 1) { 600 throw new BuildException( 601 "Cannot concatenate multiple files into a single file."); 602 } else { 603 ResourceCollection rc = (ResourceCollection) rcs.elementAt(0); 604 if (!rc.isFilesystemOnly()) { 605 throw new BuildException("Only FileSystem resources are" 606 + " supported when concatenating" 607 + " files."); 608 } 609 if (rc.size() == 0) { 610 throw new BuildException( 611 "Cannot perform operation from directory to file."); 612 } else if (rc.size() == 1) { 613 FileResource r = (FileResource) rc.iterator().next(); 614 if (file == null) { 615 file = r.getFile(); 616 rcs.removeElementAt(0); 617 } else { 618 throw new BuildException( 619 "Cannot concatenate multiple files into a single file."); 620 } 621 } else { 622 throw new BuildException( 623 "Cannot concatenate multiple files into a single file."); 624 } 625 } 626 } 627 if (destFile != null) { 628 destDir = destFile.getParentFile(); 629 } 630 } 631 632 641 protected void scan(File fromDir, File toDir, String [] files, 642 String [] dirs) { 643 FileNameMapper mapper = getMapper(); 644 buildMap(fromDir, toDir, files, mapper, fileCopyMap); 645 646 if (includeEmpty) { 647 buildMap(fromDir, toDir, dirs, mapper, dirCopyMap); 648 } 649 } 650 651 663 protected Map scan(Resource[] fromResources, File toDir) { 664 return buildMap(fromResources, toDir, getMapper()); 665 } 666 667 676 protected void buildMap(File fromDir, File toDir, String [] names, 677 FileNameMapper mapper, Hashtable map) { 678 String [] toCopy = null; 679 if (forceOverwrite) { 680 Vector v = new Vector (); 681 for (int i = 0; i < names.length; i++) { 682 if (mapper.mapFileName(names[i]) != null) { 683 v.addElement(names[i]); 684 } 685 } 686 toCopy = new String [v.size()]; 687 v.copyInto(toCopy); 688 } else { 689 SourceFileScanner ds = new SourceFileScanner(this); 690 toCopy = ds.restrict(names, fromDir, toDir, mapper, granularity); 691 } 692 for (int i = 0; i < toCopy.length; i++) { 693 File src = new File (fromDir, toCopy[i]); 694 String [] mappedFiles = mapper.mapFileName(toCopy[i]); 695 696 if (!enableMultipleMappings) { 697 map.put(src.getAbsolutePath(), 698 new String [] {new File (toDir, mappedFiles[0]).getAbsolutePath()}); 699 } else { 700 for (int k = 0; k < mappedFiles.length; k++) { 702 mappedFiles[k] = new File (toDir, mappedFiles[k]).getAbsolutePath(); 703 } 704 map.put(src.getAbsolutePath(), mappedFiles); 705 } 706 } 707 } 708 709 718 protected Map buildMap(Resource[] fromResources, final File toDir, 719 FileNameMapper mapper) { 720 HashMap map = new HashMap (); 721 Resource[] toCopy = null; 722 if (forceOverwrite) { 723 Vector v = new Vector (); 724 for (int i = 0; i < fromResources.length; i++) { 725 if (mapper.mapFileName(fromResources[i].getName()) != null) { 726 v.addElement(fromResources[i]); 727 } 728 } 729 toCopy = new Resource[v.size()]; 730 v.copyInto(toCopy); 731 } else { 732 toCopy = 733 ResourceUtils.selectOutOfDateSources(this, fromResources, 734 mapper, 735 new ResourceFactory() { 736 public Resource getResource(String name) { 737 return new FileResource(toDir, name); 738 } 739 }, 740 granularity); 741 } 742 for (int i = 0; i < toCopy.length; i++) { 743 String [] mappedFiles = mapper.mapFileName(toCopy[i].getName()); 744 745 if (!enableMultipleMappings) { 746 map.put(toCopy[i], 747 new String [] {new File (toDir, mappedFiles[0]).getAbsolutePath()}); 748 } else { 749 for (int k = 0; k < mappedFiles.length; k++) { 751 mappedFiles[k] = new File (toDir, mappedFiles[k]).getAbsolutePath(); 752 } 753 map.put(toCopy[i], mappedFiles); 754 } 755 } 756 return map; 757 } 758 759 763 protected void doFileOperations() { 764 if (fileCopyMap.size() > 0) { 765 log("Copying " + fileCopyMap.size() 766 + " file" + (fileCopyMap.size() == 1 ? "" : "s") 767 + " to " + destDir.getAbsolutePath()); 768 769 Enumeration e = fileCopyMap.keys(); 770 while (e.hasMoreElements()) { 771 String fromFile = (String ) e.nextElement(); 772 String [] toFiles = (String []) fileCopyMap.get(fromFile); 773 774 for (int i = 0; i < toFiles.length; i++) { 775 String toFile = toFiles[i]; 776 777 if (fromFile.equals(toFile)) { 778 log("Skipping self-copy of " + fromFile, verbosity); 779 continue; 780 } 781 try { 782 log("Copying " + fromFile + " to " + toFile, verbosity); 783 784 FilterSetCollection executionFilters = 785 new FilterSetCollection(); 786 if (filtering) { 787 executionFilters 788 .addFilterSet(getProject().getGlobalFilterSet()); 789 } 790 for (Enumeration filterEnum = filterSets.elements(); 791 filterEnum.hasMoreElements();) { 792 executionFilters 793 .addFilterSet((FilterSet) filterEnum.nextElement()); 794 } 795 fileUtils.copyFile(fromFile, toFile, executionFilters, 796 filterChains, forceOverwrite, 797 preserveLastModified, inputEncoding, 798 outputEncoding, getProject()); 799 } catch (IOException ioe) { 800 String msg = "Failed to copy " + fromFile + " to " + toFile 801 + " due to " + getDueTo(ioe); 802 File targetFile = new File (toFile); 803 if (targetFile.exists() && !targetFile.delete()) { 804 msg += " and I couldn't delete the corrupt " + toFile; 805 } 806 if (failonerror) { 807 throw new BuildException(msg, ioe, getLocation()); 808 } 809 log(msg, Project.MSG_ERR); 810 } 811 } 812 } 813 } 814 if (includeEmpty) { 815 Enumeration e = dirCopyMap.elements(); 816 int createCount = 0; 817 while (e.hasMoreElements()) { 818 String [] dirs = (String []) e.nextElement(); 819 for (int i = 0; i < dirs.length; i++) { 820 File d = new File (dirs[i]); 821 if (!d.exists()) { 822 if (!d.mkdirs()) { 823 log("Unable to create directory " 824 + d.getAbsolutePath(), Project.MSG_ERR); 825 } else { 826 createCount++; 827 } 828 } 829 } 830 } 831 if (createCount > 0) { 832 log("Copied " + dirCopyMap.size() 833 + " empty director" 834 + (dirCopyMap.size() == 1 ? "y" : "ies") 835 + " to " + createCount 836 + " empty director" 837 + (createCount == 1 ? "y" : "ies") + " under " 838 + destDir.getAbsolutePath()); 839 } 840 } 841 } 842 843 849 protected void doResourceOperations(Map map) { 850 if (map.size() > 0) { 851 log("Copying " + map.size() 852 + " resource" + (map.size() == 1 ? "" : "s") 853 + " to " + destDir.getAbsolutePath()); 854 855 Iterator iter = map.keySet().iterator(); 856 while (iter.hasNext()) { 857 Resource fromResource = (Resource) iter.next(); 858 String [] toFiles = (String []) map.get(fromResource); 859 860 for (int i = 0; i < toFiles.length; i++) { 861 String toFile = toFiles[i]; 862 863 try { 864 log("Copying " + fromResource + " to " + toFile, 865 verbosity); 866 867 FilterSetCollection executionFilters = 868 new FilterSetCollection(); 869 if (filtering) { 870 executionFilters 871 .addFilterSet(getProject().getGlobalFilterSet()); 872 } 873 for (Enumeration filterEnum = filterSets.elements(); 874 filterEnum.hasMoreElements();) { 875 executionFilters 876 .addFilterSet((FilterSet) filterEnum.nextElement()); 877 } 878 ResourceUtils.copyResource(fromResource, 879 new FileResource(destDir, 880 toFile), 881 executionFilters, 882 filterChains, 883 forceOverwrite, 884 preserveLastModified, 885 inputEncoding, 886 outputEncoding, 887 getProject()); 888 } catch (IOException ioe) { 889 String msg = "Failed to copy " + fromResource 890 + " to " + toFile 891 + " due to " + getDueTo(ioe); 892 File targetFile = new File (toFile); 893 if (targetFile.exists() && !targetFile.delete()) { 894 msg += " and I couldn't delete the corrupt " + toFile; 895 } 896 if (failonerror) { 897 throw new BuildException(msg, ioe, getLocation()); 898 } 899 log(msg, Project.MSG_ERR); 900 } 901 } 902 } 903 } 904 } 905 906 920 protected boolean supportsNonFileResources() { 921 return getClass().equals(Copy.class); 922 } 923 924 928 private static void add(File baseDir, String [] names, Map m) { 929 if (names != null) { 930 baseDir = getKeyFile(baseDir); 931 List l = (List ) m.get(baseDir); 932 if (l == null) { 933 l = new ArrayList (names.length); 934 m.put(baseDir, l); 935 } 936 l.addAll(java.util.Arrays.asList(names)); 937 } 938 } 939 940 944 private static void add(File baseDir, String name, Map m) { 945 if (name != null) { 946 add(baseDir, new String [] {name}, m); 947 } 948 } 949 950 953 private static File getKeyFile(File f) { 954 return f == null ? NULL_FILE_PLACEHOLDER : f; 955 } 956 957 961 private FileNameMapper getMapper() { 962 FileNameMapper mapper = null; 963 if (mapperElement != null) { 964 mapper = mapperElement.getImplementation(); 965 } else if (flatten) { 966 mapper = new FlatFileNameMapper(); 967 } else { 968 mapper = new IdentityMapper(); 969 } 970 return mapper; 971 } 972 973 979 private String getMessage(Exception ex) { 980 return ex.getMessage() == null ? ex.toString() : ex.getMessage(); 981 } 982 983 990 private String getDueTo(Exception ex) { 991 boolean baseIOException = ex.getClass() == IOException .class; 992 StringBuffer message = new StringBuffer (); 993 if (!baseIOException || ex.getMessage() == null) { 994 message.append(ex.getClass().getName()); 995 } 996 if (ex.getMessage() != null) { 997 if (!baseIOException) { 998 message.append(" "); 999 } 1000 message.append(ex.getMessage()); 1001 } 1002 if (ex.getClass().getName().indexOf("MalformedInput") != -1) { 1003 message.append(LINE_SEPARATOR); 1004 message.append( 1005 "This is normally due to the input file containing invalid"); 1006 message.append(LINE_SEPARATOR); 1007 message.append("bytes for the character encoding used : "); 1008 message.append( 1009 (inputEncoding == null 1010 ? fileUtils.getDefaultEncoding() : inputEncoding)); 1011 message.append(LINE_SEPARATOR); 1012 } 1013 return message.toString(); 1014 } 1015} 1016 | Popular Tags |