diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 160dd97025..f21bea68d6 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -37,6 +37,8 @@ import hudson.remoting.Pipe; import hudson.remoting.RemoteOutputStream; import hudson.remoting.VirtualChannel; import hudson.remoting.RemoteInputStream; +import hudson.util.DirScanner; +import hudson.util.FileVisitor; import hudson.util.IOException2; import hudson.util.HeadBufferingStream; import hudson.util.FormValidation; @@ -302,6 +304,13 @@ public final class FilePath implements Serializable { archive(new ZipArchiverFactory(),os,glob); } + /** + * Uses the given scanner on 'this' directory to list up files and then archive it to a zip stream. + */ + public int zip(OutputStream out, DirScanner scanner) throws IOException, InterruptedException { + return archive(new ZipArchiverFactory(), out, scanner); + } + /** * Archives this directory into the specified archive format, to the given {@link OutputStream}, by using * {@link DirScanner} to choose what files to include. @@ -310,7 +319,7 @@ public final class FilePath implements Serializable { * number of files/directories archived. This is only really useful to check for a situation where nothing * is archived. */ - private int archive(final ArchiverFactory factory, OutputStream os, final DirScanner scanner) throws IOException, InterruptedException { + public int archive(final ArchiverFactory factory, OutputStream os, final DirScanner scanner) throws IOException, InterruptedException { final OutputStream out = (channel!=null)?new RemoteOutputStream(os):os; return act(new FileCallable() { public Integer invoke(File f, VirtualChannel channel) throws IOException { @@ -1439,128 +1448,6 @@ public final class FilePath implements Serializable { } } - private static abstract class DirScanner implements Serializable { - abstract void scan(File dir, FileVisitor visitor) throws IOException; - - /** - * Scans everything recursively. - */ - private static class Full extends DirScanner { - private void scan(File f, String path, FileVisitor visitor) throws IOException { - if (f.canRead()) { - visitor.visit(f,path+f.getName()); - if(f.isDirectory()) { - for( File child : f.listFiles() ) - scan(child,path+f.getName()+'/',visitor); - } - } - } - - void scan(File dir, FileVisitor visitor) throws IOException { - scan(dir,"",visitor); - } - - private static final long serialVersionUID = 1L; - } - - /** - * Scans by filtering things out from {@link FileFilter} - */ - private static class Filter extends Full { - private final FileFilter filter; - - Filter(FileFilter filter) { - this.filter = filter; - } - - @Override - void scan(File dir, FileVisitor visitor) throws IOException { - super.scan(dir,visitor.with(filter)); - } - - private static final long serialVersionUID = 1L; - } - - /** - * Scans by using Ant GLOB syntax. - */ - private static class Glob extends DirScanner { - private final String includes, excludes; - - private Glob(String includes, String excludes) { - this.includes = includes; - this.excludes = excludes; - } - - void scan(File dir, FileVisitor visitor) throws IOException { - if(fixEmpty(includes)==null && excludes==null) { - // optimization - new Full().scan(dir,visitor); - return; - } - - FileSet fs = Util.createFileSet(dir,includes,excludes); - - if(dir.exists()) { - DirectoryScanner ds = fs.getDirectoryScanner(new org.apache.tools.ant.Project()); - for( String f : ds.getIncludedFiles()) { - File file = new File(dir, f); - visitor.visit(file,f); - } - } - } - - private static final long serialVersionUID = 1L; - } - - private static final long serialVersionUID = 1L; - } - - /** - * Visits files in a directory recursively. - * Primarily used for building an archive with various filtering. - */ - private static abstract class FileVisitor { - /** - * Caleld for each file and directory that matches the criteria. - * - * @param relativePath - * The file/directory name in question - */ - abstract void visit(File f, String relativePath) throws IOException; - - /** - * Decorates by a given filter. - */ - FileVisitor with(FileFilter f) { - if(f==null) return this; - return new FilterFileVisitor(f,this); - } - } - - private static final class FilterFileVisitor extends FileVisitor implements Serializable { - private final FileFilter filter; - private final FileVisitor visitor; - - private FilterFileVisitor(FileFilter filter, FileVisitor visitor) { - this.filter = filter!=null ? filter : PASS_THROUGH; - this.visitor = visitor; - } - - public void visit(File f, String relativePath) throws IOException { - if(f.isDirectory() || filter.accept(f)) - visitor.visit(f,relativePath); - } - - private static final FileFilter PASS_THROUGH = new FileFilter() { - public boolean accept(File pathname) { - return true; - } - }; - - private static final long serialVersionUID = 1L; - } - private static interface ArchiverFactory extends Serializable { Archiver create(OutputStream out); } @@ -1699,6 +1586,13 @@ public final class FilePath implements Serializable { return archive(new TarArchiverFactory(), out, filter); } + /** + * Uses the given scanner on 'this' directory to list up files and then archive it to a tar stream. + */ + public int tar(OutputStream out, DirScanner scanner) throws IOException, InterruptedException { + return archive(new TarArchiverFactory(), out, scanner); + } + /** * Writes to a tar stream and stores obtained files to the base dir. * diff --git a/core/src/main/java/hudson/util/DirScanner.java b/core/src/main/java/hudson/util/DirScanner.java new file mode 100644 index 0000000000..2f7a215e87 --- /dev/null +++ b/core/src/main/java/hudson/util/DirScanner.java @@ -0,0 +1,100 @@ +package hudson.util; + +import hudson.Util; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.types.FileSet; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.io.Serializable; + +import static hudson.Util.fixEmpty; + +/** + * Visits a directory and its contents and pass them to the {@link FileVisitor}. + * + * A {@link DirScanner} encapsulates the logic of how it filters files in the directory. It is also remotable. + * + * @since 1.343 + * @see FileVisitor + */ +public abstract class DirScanner implements Serializable { + /** + * Scans the given directory and pass files onto the given visitor. + */ + public abstract void scan(File dir, FileVisitor visitor) throws IOException; + + /** + * Scans everything recursively. + */ + public static class Full extends DirScanner { + private void scan(File f, String path, FileVisitor visitor) throws IOException { + if (f.canRead()) { + visitor.visit(f,path+f.getName()); + if(f.isDirectory()) { + for( File child : f.listFiles() ) + scan(child,path+f.getName()+'/',visitor); + } + } + } + + public void scan(File dir, FileVisitor visitor) throws IOException { + scan(dir,"",visitor); + } + + private static final long serialVersionUID = 1L; + } + + /** + * Scans by filtering things out from {@link FileFilter} + */ + public static class Filter extends Full { + private final FileFilter filter; + + public Filter(FileFilter filter) { + this.filter = filter; + } + + @Override + public void scan(File dir, FileVisitor visitor) throws IOException { + super.scan(dir,visitor.with(filter)); + } + + private static final long serialVersionUID = 1L; + } + + /** + * Scans by using Ant GLOB syntax. + */ + public static class Glob extends DirScanner { + private final String includes, excludes; + + public Glob(String includes, String excludes) { + this.includes = includes; + this.excludes = excludes; + } + + public void scan(File dir, FileVisitor visitor) throws IOException { + if(fixEmpty(includes)==null && excludes==null) { + // optimization + new Full().scan(dir,visitor); + return; + } + + FileSet fs = Util.createFileSet(dir,includes,excludes); + + if(dir.exists()) { + DirectoryScanner ds = fs.getDirectoryScanner(new org.apache.tools.ant.Project()); + for( String f : ds.getIncludedFiles()) { + File file = new File(dir, f); + visitor.visit(file,f); + } + } + } + + private static final long serialVersionUID = 1L; + } + + private static final long serialVersionUID = 1L; +} diff --git a/core/src/main/java/hudson/util/FileVisitor.java b/core/src/main/java/hudson/util/FileVisitor.java new file mode 100644 index 0000000000..e9ee7c8b25 --- /dev/null +++ b/core/src/main/java/hudson/util/FileVisitor.java @@ -0,0 +1,55 @@ +package hudson.util; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.io.Serializable; + +/** + * Visits files in a directory recursively. + + * @since 1.343 + * @see DirScanner + */ +public abstract class FileVisitor { + /** + * Called for each file and directory that matches the criteria implied by {@link DirScanner} + * + * @param f + * Either a file or a directory. + * @param relativePath + * The file/directory name in question + */ + public abstract void visit(File f, String relativePath) throws IOException; + + /** + * Decorates a visitor by a given filter. + */ + public final FileVisitor with(FileFilter f) { + if(f==null) return this; + return new FilterFileVisitor(f,this); + } + + private static final class FilterFileVisitor extends FileVisitor implements Serializable { + private final FileFilter filter; + private final FileVisitor visitor; + + private FilterFileVisitor(FileFilter filter, FileVisitor visitor) { + this.filter = filter!=null ? filter : PASS_THROUGH; + this.visitor = visitor; + } + + public void visit(File f, String relativePath) throws IOException { + if(f.isDirectory() || filter.accept(f)) + visitor.visit(f,relativePath); + } + + private static final FileFilter PASS_THROUGH = new FileFilter() { + public boolean accept(File pathname) { + return true; + } + }; + + private static final long serialVersionUID = 1L; + } +}