1 18 19 package org.apache.tools.ant.taskdefs; 20 21 import java.io.BufferedOutputStream ; 22 import java.io.File ; 23 import java.io.FileOutputStream ; 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.io.OutputStream ; 27 import java.util.Enumeration ; 28 import java.util.HashMap ; 29 import java.util.HashSet ; 30 import java.util.Iterator ; 31 import java.util.Vector ; 32 import java.util.zip.GZIPOutputStream ; 33 import org.apache.tools.ant.BuildException; 34 import org.apache.tools.ant.DirectoryScanner; 35 import org.apache.tools.ant.Project; 36 import org.apache.tools.ant.types.ArchiveFileSet; 37 import org.apache.tools.ant.types.EnumeratedAttribute; 38 import org.apache.tools.ant.types.FileSet; 39 import org.apache.tools.ant.types.Resource; 40 import org.apache.tools.ant.types.ResourceCollection; 41 import org.apache.tools.ant.types.resources.ArchiveResource; 42 import org.apache.tools.ant.types.resources.FileResource; 43 import org.apache.tools.ant.types.selectors.SelectorUtils; 44 import org.apache.tools.ant.types.resources.TarResource; 45 import org.apache.tools.ant.util.FileUtils; 46 import org.apache.tools.ant.util.MergingMapper; 47 import org.apache.tools.ant.util.SourceFileScanner; 48 import org.apache.tools.bzip2.CBZip2OutputStream; 49 import org.apache.tools.tar.TarConstants; 50 import org.apache.tools.tar.TarEntry; 51 import org.apache.tools.tar.TarOutputStream; 52 53 60 public class Tar extends MatchingTask { 61 62 67 public static final String WARN = "warn"; 68 73 public static final String FAIL = "fail"; 74 79 public static final String TRUNCATE = "truncate"; 80 85 public static final String GNU = "gnu"; 86 91 public static final String OMIT = "omit"; 92 93 File tarFile; 95 File baseDir; 96 97 private TarLongFileMode longFileMode = new TarLongFileMode(); 98 99 Vector filesets = new Vector (); 101 private Vector resourceCollections = new Vector (); 104 105 Vector fileSetFiles = new Vector (); 106 107 109 112 private boolean longWarningGiven = false; 113 114 private TarCompressionMethod compression = new TarCompressionMethod(); 115 116 120 public TarFileSet createTarFileSet() { 121 TarFileSet fs = new TarFileSet(); 122 fs.setProject(getProject()); 123 filesets.addElement(fs); 124 return fs; 125 } 126 127 132 public void add(ResourceCollection res) { 133 resourceCollections.add(res); 134 } 135 136 142 public void setTarfile(File tarFile) { 143 this.tarFile = tarFile; 144 } 145 146 151 public void setDestFile(File destFile) { 152 this.tarFile = destFile; 153 } 154 155 159 public void setBasedir(File baseDir) { 160 this.baseDir = baseDir; 161 } 162 163 182 public void setLongfile(String mode) { 183 log("DEPRECATED - The setLongfile(String) method has been deprecated." 184 + " Use setLongfile(Tar.TarLongFileMode) instead."); 185 this.longFileMode = new TarLongFileMode(); 186 longFileMode.setValue(mode); 187 } 188 189 203 public void setLongfile(TarLongFileMode mode) { 204 this.longFileMode = mode; 205 } 206 207 217 public void setCompression(TarCompressionMethod mode) { 218 this.compression = mode; 219 } 220 221 225 public void execute() throws BuildException { 226 if (tarFile == null) { 227 throw new BuildException("tarfile attribute must be set!", 228 getLocation()); 229 } 230 231 if (tarFile.exists() && tarFile.isDirectory()) { 232 throw new BuildException("tarfile is a directory!", 233 getLocation()); 234 } 235 236 if (tarFile.exists() && !tarFile.canWrite()) { 237 throw new BuildException("Can not write to the specified tarfile!", 238 getLocation()); 239 } 240 241 Vector savedFileSets = (Vector ) filesets.clone(); 242 try { 243 if (baseDir != null) { 244 if (!baseDir.exists()) { 245 throw new BuildException("basedir does not exist!", 246 getLocation()); 247 } 248 249 TarFileSet mainFileSet = new TarFileSet(fileset); 251 mainFileSet.setDir(baseDir); 252 filesets.addElement(mainFileSet); 253 } 254 255 if (filesets.size() == 0 && resourceCollections.size() == 0) { 256 throw new BuildException("You must supply either a basedir " 257 + "attribute or some nested resource" 258 + " collections.", 259 getLocation()); 260 } 261 262 boolean upToDate = true; 265 for (Enumeration e = filesets.elements(); e.hasMoreElements();) { 266 upToDate &= check((TarFileSet) e.nextElement()); 267 } 268 for (Enumeration e = resourceCollections.elements(); 269 e.hasMoreElements();) { 270 upToDate &= check((ResourceCollection) e.nextElement()); 271 } 272 273 if (upToDate) { 274 log("Nothing to do: " + tarFile.getAbsolutePath() 275 + " is up to date.", Project.MSG_INFO); 276 return; 277 } 278 279 log("Building tar: " + tarFile.getAbsolutePath(), Project.MSG_INFO); 280 281 TarOutputStream tOut = null; 282 try { 283 tOut = new TarOutputStream( 284 compression.compress( 285 new BufferedOutputStream ( 286 new FileOutputStream (tarFile)))); 287 tOut.setDebug(true); 288 if (longFileMode.isTruncateMode()) { 289 tOut.setLongFileMode(TarOutputStream.LONGFILE_TRUNCATE); 290 } else if (longFileMode.isFailMode() 291 || longFileMode.isOmitMode()) { 292 tOut.setLongFileMode(TarOutputStream.LONGFILE_ERROR); 293 } else { 294 tOut.setLongFileMode(TarOutputStream.LONGFILE_GNU); 296 } 297 298 longWarningGiven = false; 299 for (Enumeration e = filesets.elements(); 300 e.hasMoreElements();) { 301 tar((TarFileSet) e.nextElement(), tOut); 302 } 303 for (Enumeration e = resourceCollections.elements(); 304 e.hasMoreElements();) { 305 tar((ResourceCollection) e.nextElement(), tOut); 306 } 307 } catch (IOException ioe) { 308 String msg = "Problem creating TAR: " + ioe.getMessage(); 309 throw new BuildException(msg, ioe, getLocation()); 310 } finally { 311 FileUtils.close(tOut); 312 } 313 } finally { 314 filesets = savedFileSets; 315 } 316 } 317 318 326 protected void tarFile(File file, TarOutputStream tOut, String vPath, 327 TarFileSet tarFileSet) 328 throws IOException { 329 if (file.equals(tarFile)) { 330 return; 340 } 341 tarResource(new FileResource(file), tOut, vPath, tarFileSet); 342 } 343 344 353 protected void tarResource(Resource r, TarOutputStream tOut, String vPath, 354 TarFileSet tarFileSet) 355 throws IOException { 356 357 if (!r.isExists()) { 358 return; 359 } 360 361 if (tarFileSet != null) { 362 String fullpath = tarFileSet.getFullpath(this.getProject()); 363 if (fullpath.length() > 0) { 364 vPath = fullpath; 365 } else { 366 if (vPath.length() <= 0) { 368 return; 369 } 370 371 String prefix = tarFileSet.getPrefix(this.getProject()); 372 if (prefix.length() > 0 && !prefix.endsWith("/")) { 374 prefix = prefix + "/"; 375 } 376 vPath = prefix + vPath; 377 } 378 379 if (vPath.startsWith("/") 380 && !tarFileSet.getPreserveLeadingSlashes()) { 381 int l = vPath.length(); 382 if (l <= 1) { 383 return; 385 } 386 vPath = vPath.substring(1, l); 387 } 388 } 389 390 if (r.isDirectory() && !vPath.endsWith("/")) { 391 vPath += "/"; 392 } 393 394 if (vPath.length() >= TarConstants.NAMELEN) { 395 if (longFileMode.isOmitMode()) { 396 log("Omitting: " + vPath, Project.MSG_INFO); 397 return; 398 } else if (longFileMode.isWarnMode()) { 399 log("Entry: " + vPath + " longer than " 400 + TarConstants.NAMELEN + " characters.", 401 Project.MSG_WARN); 402 if (!longWarningGiven) { 403 log("Resulting tar file can only be processed " 404 + "successfully by GNU compatible tar commands", 405 Project.MSG_WARN); 406 longWarningGiven = true; 407 } 408 } else if (longFileMode.isFailMode()) { 409 throw new BuildException("Entry: " + vPath 410 + " longer than " + TarConstants.NAMELEN 411 + "characters.", getLocation()); 412 } 413 } 414 415 TarEntry te = new TarEntry(vPath); 416 te.setModTime(r.getLastModified()); 417 if (r instanceof ArchiveResource) { 419 ArchiveResource ar = (ArchiveResource) r; 420 te.setMode(ar.getMode()); 421 if (r instanceof TarResource) { 422 TarResource tr = (TarResource) r; 423 te.setUserName(tr.getUserName()); 424 te.setUserId(tr.getUid()); 425 te.setGroupName(tr.getGroup()); 426 te.setGroupId(tr.getGid()); 427 } 428 } 429 430 if (!r.isDirectory()) { 431 if (r.size() > TarConstants.MAXSIZE) { 432 throw new BuildException( 433 "Resource: " + r + " larger than " 434 + TarConstants.MAXSIZE + " bytes."); 435 } 436 te.setSize(r.getSize()); 437 if (tarFileSet != null && tarFileSet.hasFileModeBeenSet()) { 439 te.setMode(tarFileSet.getMode()); 440 } 441 } else if (tarFileSet != null && tarFileSet.hasDirModeBeenSet()) { 442 te.setMode(tarFileSet.getDirMode(this.getProject())); 444 } 445 446 if (tarFileSet != null) { 447 if (tarFileSet.hasUserNameBeenSet()) { 449 te.setUserName(tarFileSet.getUserName()); 450 } 451 if (tarFileSet.hasGroupBeenSet()) { 452 te.setGroupName(tarFileSet.getGroup()); 453 } 454 if (tarFileSet.hasUserIdBeenSet()) { 455 te.setUserId(tarFileSet.getUid()); 456 } 457 if (tarFileSet.hasGroupIdBeenSet()) { 458 te.setGroupId(tarFileSet.getGid()); 459 } 460 } 461 462 InputStream in = null; 463 try { 464 tOut.putNextEntry(te); 465 466 if (!r.isDirectory()) { 467 in = r.getInputStream(); 468 469 byte[] buffer = new byte[8 * 1024]; 470 int count = 0; 471 do { 472 tOut.write(buffer, 0, count); 473 count = in.read(buffer, 0, buffer.length); 474 } while (count != -1); 475 } 476 477 tOut.closeEntry(); 478 } finally { 479 FileUtils.close(in); 480 } 481 } 482 483 490 protected boolean archiveIsUpToDate(String [] files) { 491 return archiveIsUpToDate(files, baseDir); 492 } 493 494 501 protected boolean archiveIsUpToDate(String [] files, File dir) { 502 SourceFileScanner sfs = new SourceFileScanner(this); 503 MergingMapper mm = new MergingMapper(); 504 mm.setTo(tarFile.getAbsolutePath()); 505 return sfs.restrict(files, dir, null, mm).length == 0; 506 } 507 508 514 protected boolean archiveIsUpToDate(Resource r) { 515 return SelectorUtils.isOutOfDate(new FileResource(tarFile), r, 516 FileUtils.getFileUtils() 517 .getFileTimestampGranularity()); 518 } 519 520 531 protected boolean supportsNonFileResources() { 532 return getClass().equals(Tar.class); 533 } 534 535 549 protected boolean check(ResourceCollection rc) { 550 boolean upToDate = true; 551 if (isFileFileSet(rc)) { 552 FileSet fs = (FileSet) rc; 553 upToDate = check(fs.getDir(getProject()), getFileNames(fs)); 554 } else if (!rc.isFilesystemOnly() && !supportsNonFileResources()) { 555 throw new BuildException("only filesystem resources are supported"); 556 } else if (rc.isFilesystemOnly()) { 557 HashSet basedirs = new HashSet (); 558 HashMap basedirToFilesMap = new HashMap (); 559 Iterator iter = rc.iterator(); 560 while (iter.hasNext()) { 561 FileResource r = (FileResource) iter.next(); 562 File base = r.getBaseDir(); 563 if (base == null) { 564 base = Copy.NULL_FILE_PLACEHOLDER; 565 } 566 basedirs.add(base); 567 Vector files = (Vector ) basedirToFilesMap.get(base); 568 if (files == null) { 569 files = new Vector (); 570 basedirToFilesMap.put(base, new Vector ()); 571 } 572 files.add(r.getName()); 573 } 574 iter = basedirs.iterator(); 575 while (iter.hasNext()) { 576 File base = (File ) iter.next(); 577 Vector f = (Vector ) basedirToFilesMap.get(base); 578 String [] files = (String []) f.toArray(new String [f.size()]); 579 upToDate &= 580 check(base == Copy.NULL_FILE_PLACEHOLDER ? null : base, 581 files); 582 } 583 } else { Iterator iter = rc.iterator(); 585 while (upToDate && iter.hasNext()) { 586 Resource r = (Resource) iter.next(); 587 upToDate &= archiveIsUpToDate(r); 588 } 589 } 590 591 return upToDate; 592 } 593 594 603 protected boolean check(File basedir, String [] files) { 604 boolean upToDate = true; 605 if (!archiveIsUpToDate(files, basedir)) { 606 upToDate = false; 607 } 608 609 for (int i = 0; i < files.length; ++i) { 610 if (tarFile.equals(new File (basedir, files[i]))) { 611 throw new BuildException("A tar file cannot include " 612 + "itself", getLocation()); 613 } 614 } 615 return upToDate; 616 } 617 618 629 protected void tar(ResourceCollection rc, TarOutputStream tOut) 630 throws IOException { 631 ArchiveFileSet afs = null; 632 if (rc instanceof ArchiveFileSet) { 633 afs = (ArchiveFileSet) rc; 634 } 635 if (afs != null && afs.size() > 1 636 && afs.getFullpath(this.getProject()).length() > 0) { 637 throw new BuildException("fullpath attribute may only " 638 + "be specified for " 639 + "filesets that specify a " 640 + "single file."); 641 } 642 TarFileSet tfs = asTarFileSet(afs); 643 644 if (isFileFileSet(rc)) { 645 FileSet fs = (FileSet) rc; 646 String [] files = getFileNames(fs); 647 for (int i = 0; i < files.length; i++) { 648 File f = new File (fs.getDir(getProject()), files[i]); 649 String name = files[i].replace(File.separatorChar, '/'); 650 tarFile(f, tOut, name, tfs); 651 } 652 } else if (rc.isFilesystemOnly()) { 653 Iterator iter = rc.iterator(); 654 while (iter.hasNext()) { 655 FileResource r = (FileResource) iter.next(); 656 File f = r.getFile(); 657 if (f == null) { 658 f = new File (r.getBaseDir(), r.getName()); 659 } 660 tarFile(f, tOut, f.getName(), tfs); 661 } 662 } else { Iterator iter = rc.iterator(); 664 while (iter.hasNext()) { 665 Resource r = (Resource) iter.next(); 666 tarResource(r, tOut, r.getName(), tfs); 667 } 668 } 669 } 670 671 678 protected static final boolean isFileFileSet(ResourceCollection rc) { 679 return rc instanceof FileSet && rc.isFilesystemOnly(); 680 } 681 682 689 protected static final String [] getFileNames(FileSet fs) { 690 DirectoryScanner ds = fs.getDirectoryScanner(fs.getProject()); 691 String [] directories = ds.getIncludedDirectories(); 692 String [] filesPerSe = ds.getIncludedFiles(); 693 String [] files = new String [directories.length + filesPerSe.length]; 694 System.arraycopy(directories, 0, files, 0, directories.length); 695 System.arraycopy(filesPerSe, 0, files, directories.length, 696 filesPerSe.length); 697 return files; 698 } 699 700 709 protected TarFileSet asTarFileSet(ArchiveFileSet archiveFileSet) { 710 TarFileSet tfs = null; 711 if (archiveFileSet != null && archiveFileSet instanceof TarFileSet) { 712 tfs = (TarFileSet) archiveFileSet; 713 } else { 714 tfs = new TarFileSet(); 715 tfs.setProject(getProject()); 716 if (archiveFileSet != null) { 717 tfs.setPrefix(archiveFileSet.getPrefix(getProject())); 718 tfs.setFullpath(archiveFileSet.getFullpath(getProject())); 719 if (archiveFileSet.hasFileModeBeenSet()) { 720 tfs.integerSetFileMode(archiveFileSet 721 .getFileMode(getProject())); 722 } 723 if (archiveFileSet.hasDirModeBeenSet()) { 724 tfs.integerSetDirMode(archiveFileSet 725 .getDirMode(getProject())); 726 } 727 728 if (archiveFileSet 729 instanceof org.apache.tools.ant.types.TarFileSet) { 730 org.apache.tools.ant.types.TarFileSet t = 731 (org.apache.tools.ant.types.TarFileSet) archiveFileSet; 732 if (t.hasUserNameBeenSet()) { 733 tfs.setUserName(t.getUserName()); 734 } 735 if (t.hasGroupBeenSet()) { 736 tfs.setGroup(t.getGroup()); 737 } 738 if (t.hasUserIdBeenSet()) { 739 tfs.setUid(t.getUid()); 740 } 741 if (t.hasGroupIdBeenSet()) { 742 tfs.setGid(t.getGid()); 743 } 744 } 745 } 746 } 747 return tfs; 748 } 749 750 754 public static class TarFileSet 755 extends org.apache.tools.ant.types.TarFileSet { 756 private String [] files = null; 757 758 private boolean preserveLeadingSlashes = false; 759 760 766 public TarFileSet(FileSet fileset) { 767 super(fileset); 768 } 769 770 774 public TarFileSet() { 775 super(); 776 } 777 778 784 public String [] getFiles(Project p) { 785 if (files == null) { 786 files = getFileNames(this); 787 } 788 789 return files; 790 } 791 792 798 public void setMode(String octalString) { 799 setFileMode(octalString); 800 } 801 802 805 public int getMode() { 806 return getFileMode(this.getProject()); 807 } 808 809 815 public void setPreserveLeadingSlashes(boolean b) { 816 this.preserveLeadingSlashes = b; 817 } 818 819 822 public boolean getPreserveLeadingSlashes() { 823 return preserveLeadingSlashes; 824 } 825 } 826 827 831 public static class TarLongFileMode extends EnumeratedAttribute { 832 833 834 public static final String 835 WARN = "warn", 836 FAIL = "fail", 837 TRUNCATE = "truncate", 838 GNU = "gnu", 839 OMIT = "omit"; 840 841 private final String [] validModes = {WARN, FAIL, TRUNCATE, GNU, OMIT}; 842 843 844 public TarLongFileMode() { 845 super(); 846 setValue(WARN); 847 } 848 849 852 public String [] getValues() { 853 return validModes; 854 } 855 856 859 public boolean isTruncateMode() { 860 return TRUNCATE.equalsIgnoreCase(getValue()); 861 } 862 863 866 public boolean isWarnMode() { 867 return WARN.equalsIgnoreCase(getValue()); 868 } 869 870 873 public boolean isGnuMode() { 874 return GNU.equalsIgnoreCase(getValue()); 875 } 876 877 880 public boolean isFailMode() { 881 return FAIL.equalsIgnoreCase(getValue()); 882 } 883 884 887 public boolean isOmitMode() { 888 return OMIT.equalsIgnoreCase(getValue()); 889 } 890 } 891 892 896 public static final class TarCompressionMethod extends EnumeratedAttribute { 897 898 902 private static final String NONE = "none"; 903 906 private static final String GZIP = "gzip"; 907 910 private static final String BZIP2 = "bzip2"; 911 912 913 916 public TarCompressionMethod() { 917 super(); 918 setValue(NONE); 919 } 920 921 925 public String [] getValues() { 926 return new String [] {NONE, GZIP, BZIP2 }; 927 } 928 929 937 private OutputStream compress(final OutputStream ostream) 938 throws IOException { 939 final String v = getValue(); 940 if (GZIP.equals(v)) { 941 return new GZIPOutputStream (ostream); 942 } else { 943 if (BZIP2.equals(v)) { 944 ostream.write('B'); 945 ostream.write('Z'); 946 return new CBZip2OutputStream(ostream); 947 } 948 } 949 return ostream; 950 } 951 } 952 } 953 | Popular Tags |