提交 4e72f92b 编写于 作者: K kohsuke

Refactored FilePath to expose the archive handling code.



git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@31064 71c3de6d-444a-0410-be80-ed276b4c234a
上级 d82b8571
...@@ -39,7 +39,6 @@ import hudson.remoting.RemoteOutputStream; ...@@ -39,7 +39,6 @@ import hudson.remoting.RemoteOutputStream;
import hudson.remoting.VirtualChannel; import hudson.remoting.VirtualChannel;
import hudson.remoting.RemoteInputStream; import hudson.remoting.RemoteInputStream;
import hudson.util.DirScanner; import hudson.util.DirScanner;
import hudson.util.FileVisitor;
import hudson.util.IOException2; import hudson.util.IOException2;
import hudson.util.HeadBufferingStream; import hudson.util.HeadBufferingStream;
import hudson.util.FormValidation; import hudson.util.FormValidation;
...@@ -48,16 +47,15 @@ import static hudson.util.jna.GNUCLibrary.LIBC; ...@@ -48,16 +47,15 @@ import static hudson.util.jna.GNUCLibrary.LIBC;
import static hudson.Util.fixEmpty; import static hudson.Util.fixEmpty;
import static hudson.FilePath.TarCompression.GZIP; import static hudson.FilePath.TarCompression.GZIP;
import hudson.os.PosixAPI; import hudson.os.PosixAPI;
import hudson.org.apache.tools.tar.TarOutputStream;
import hudson.org.apache.tools.tar.TarInputStream; import hudson.org.apache.tools.tar.TarInputStream;
import hudson.util.io.Archiver;
import hudson.util.io.ArchiverFactory;
import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Copy; import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.FileSet;
import org.apache.tools.tar.TarEntry; import org.apache.tools.tar.TarEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.apache.tools.zip.ZipEntry;
import org.apache.commons.io.input.CountingInputStream; import org.apache.commons.io.input.CountingInputStream;
import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItem;
import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.Stapler;
...@@ -78,7 +76,6 @@ import java.io.OutputStream; ...@@ -78,7 +76,6 @@ import java.io.OutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.io.Writer; import java.io.Writer;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.Closeable;
import java.net.URI; import java.net.URI;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
...@@ -335,7 +332,7 @@ public final class FilePath implements Serializable { ...@@ -335,7 +332,7 @@ public final class FilePath implements Serializable {
* @since 1.315 * @since 1.315
*/ */
public void zip(OutputStream os, FileFilter filter) throws IOException, InterruptedException { public void zip(OutputStream os, FileFilter filter) throws IOException, InterruptedException {
archive(new ZipArchiverFactory(),os,filter); archive(ArchiverFactory.ZIP,os,filter);
} }
/** /**
...@@ -350,7 +347,7 @@ public final class FilePath implements Serializable { ...@@ -350,7 +347,7 @@ public final class FilePath implements Serializable {
* Use {@link #zip(OutputStream,String)} that has more consistent name. * Use {@link #zip(OutputStream,String)} that has more consistent name.
*/ */
public void createZipArchive(OutputStream os, final String glob) throws IOException, InterruptedException { public void createZipArchive(OutputStream os, final String glob) throws IOException, InterruptedException {
archive(new ZipArchiverFactory(),os,glob); archive(ArchiverFactory.ZIP,os,glob);
} }
/** /**
...@@ -363,14 +360,14 @@ public final class FilePath implements Serializable { ...@@ -363,14 +360,14 @@ public final class FilePath implements Serializable {
* @since 1.315 * @since 1.315
*/ */
public void zip(OutputStream os, final String glob) throws IOException, InterruptedException { public void zip(OutputStream os, final String glob) throws IOException, InterruptedException {
archive(new ZipArchiverFactory(),os,glob); archive(ArchiverFactory.ZIP,os,glob);
} }
/** /**
* Uses the given scanner on 'this' directory to list up files and then archive it to a zip stream. * 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 { public int zip(OutputStream out, DirScanner scanner) throws IOException, InterruptedException {
return archive(new ZipArchiverFactory(), out, scanner); return archive(ArchiverFactory.ZIP, out, scanner);
} }
/** /**
...@@ -1512,132 +1509,6 @@ public final class FilePath implements Serializable { ...@@ -1512,132 +1509,6 @@ public final class FilePath implements Serializable {
} }
} }
private static interface ArchiverFactory extends Serializable {
Archiver create(OutputStream out);
}
private static final class TarArchiverFactory implements ArchiverFactory, Serializable {
public Archiver create(OutputStream out) {
return new TarWriter(out);
}
private static final long serialVersionUID = 1L;
}
private static final class ZipArchiverFactory implements ArchiverFactory, Serializable {
public Archiver create(OutputStream out) {
return new ZipWriter(out);
}
private static final long serialVersionUID = 1L;
}
/**
* Base for {@link TarWriter} and {@link ZipWriter}.
*/
private static abstract class Archiver extends FileVisitor implements Closeable {
protected int entriesWritten =0;
/**
* Number of files/directories archived.
*/
public int countEntries() {
return entriesWritten;
}
}
/**
* {@link FileVisitor} that creates a tar archive.
*/
private static final class TarWriter extends Archiver {
private final byte[] buf = new byte[8192];
private final TarOutputStream tar;
private TarWriter(OutputStream out) {
tar = new TarOutputStream(new BufferedOutputStream(out) {
// TarOutputStream uses TarBuffer internally,
// which flushes the stream for each block. this creates unnecessary
// data stream fragmentation, and flush request to a remote, which slows things down.
@Override
public void flush() throws IOException {
// so don't do anything in flush
}
});
tar.setLongFileMode(TarOutputStream.LONGFILE_GNU);
}
public void visit(File file, String relativePath) throws IOException {
if(Functions.isWindows())
relativePath = relativePath.replace('\\','/');
if(file.isDirectory())
relativePath+='/';
TarEntry te = new TarEntry(relativePath);
te.setModTime(file.lastModified());
if(!file.isDirectory())
te.setSize(file.length());
tar.putNextEntry(te);
if (!file.isDirectory()) {
FileInputStream in = new FileInputStream(file);
try {
int len;
while((len=in.read(buf))>=0)
tar.write(buf,0,len);
} finally {
in.close();
}
}
tar.closeEntry();
entriesWritten++;
}
public void close() throws IOException {
tar.close();
}
}
/**
* {@link FileVisitor} that creates a zip archive.
*/
private static final class ZipWriter extends Archiver {
private final byte[] buf = new byte[8192];
private final ZipOutputStream zip;
private ZipWriter(OutputStream out) {
zip = new ZipOutputStream(out);
zip.setEncoding(System.getProperty("file.encoding"));
}
public void visit(File f, String relativePath) throws IOException {
if(f.isDirectory()) {
ZipEntry dirZipEntry = new ZipEntry(relativePath+'/');
// Setting this bit explicitly is needed by some unzipping applications (see HUDSON-3294).
dirZipEntry.setExternalAttributes(BITMASK_IS_DIRECTORY);
zip.putNextEntry(dirZipEntry);
zip.closeEntry();
} else {
zip.putNextEntry(new ZipEntry(relativePath));
FileInputStream in = new FileInputStream(f);
int len;
while((len=in.read(buf))>0)
zip.write(buf,0,len);
in.close();
zip.closeEntry();
}
entriesWritten++;
}
public void close() throws IOException {
zip.close();
}
// Bitmask indicating directories in 'external attributes' of a ZIP archive entry.
private static final long BITMASK_IS_DIRECTORY = 1<<4;
}
/** /**
* Writes files in 'this' directory to a tar stream. * Writes files in 'this' directory to a tar stream.
...@@ -1646,18 +1517,18 @@ public final class FilePath implements Serializable { ...@@ -1646,18 +1517,18 @@ public final class FilePath implements Serializable {
* Ant file pattern mask, like "**&#x2F;*.java". * Ant file pattern mask, like "**&#x2F;*.java".
*/ */
public int tar(OutputStream out, final String glob) throws IOException, InterruptedException { public int tar(OutputStream out, final String glob) throws IOException, InterruptedException {
return archive(new TarArchiverFactory(), out, glob); return archive(ArchiverFactory.TAR, out, glob);
} }
public int tar(OutputStream out, FileFilter filter) throws IOException, InterruptedException { public int tar(OutputStream out, FileFilter filter) throws IOException, InterruptedException {
return archive(new TarArchiverFactory(), out, filter); return archive(ArchiverFactory.TAR, out, filter);
} }
/** /**
* Uses the given scanner on 'this' directory to list up files and then archive it to a tar stream. * 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 { public int tar(OutputStream out, DirScanner scanner) throws IOException, InterruptedException {
return archive(new TarArchiverFactory(), out, scanner); return archive(ArchiverFactory.TAR, out, scanner);
} }
/** /**
...@@ -1667,13 +1538,13 @@ public final class FilePath implements Serializable { ...@@ -1667,13 +1538,13 @@ public final class FilePath implements Serializable {
* number of files/directories that are written. * number of files/directories that are written.
*/ */
private Integer writeToTar(File baseDir, String fileMask, String excludes, OutputStream out) throws IOException { private Integer writeToTar(File baseDir, String fileMask, String excludes, OutputStream out) throws IOException {
TarWriter tw = new TarWriter(out); Archiver tw = ArchiverFactory.TAR.create(out);
try { try {
new DirScanner.Glob(fileMask,excludes).scan(baseDir,tw); new DirScanner.Glob(fileMask,excludes).scan(baseDir,tw);
} finally { } finally {
tw.close(); tw.close();
} }
return tw.entriesWritten; return tw.countEntries();
} }
/** /**
......
...@@ -7,7 +7,7 @@ import java.io.Serializable; ...@@ -7,7 +7,7 @@ import java.io.Serializable;
/** /**
* Visits files in a directory recursively. * Visits files in a directory recursively.
*
* @since 1.343 * @since 1.343
* @see DirScanner * @see DirScanner
*/ */
......
/*
* The MIT License
*
* Copyright (c) 2010, InfraDNA, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.util.io;
import hudson.util.FileVisitor;
import java.io.Closeable;
/**
* {@link FileVisitor} that creates archive files.
*
* @since 1.359
* @see ArchiverFactory
*/
public abstract class Archiver extends FileVisitor implements Closeable {
protected int entriesWritten =0;
/**
* Number of files/directories archived.
*/
public int countEntries() {
return entriesWritten;
}
}
/*
* The MIT License
*
* Copyright (c) 2010, InfraDNA, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.util.io;
import hudson.FilePath.TarCompression;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
/**
* Creates {@link Archiver} on top of a stream.
*
* @author Kohsuke Kawaguchi
* @since 1.359
*/
public abstract class ArchiverFactory implements Serializable {
/**
* Creates an archiver on top of the given stream.
*/
public abstract Archiver create(OutputStream out) throws IOException;
/**
* Uncompressed tar format.
*/
public static ArchiverFactory TAR = new TarArchiverFactory(TarCompression.NONE);
/**
* tar+gz
*/
public static ArchiverFactory TARGZ = new TarArchiverFactory(TarCompression.GZIP);
/**
* Zip format.
*/
public static ArchiverFactory ZIP = new ZipArchiverFactory();
private static final class TarArchiverFactory extends ArchiverFactory {
private final TarCompression method;
private TarArchiverFactory(TarCompression method) {
this.method = method;
}
public Archiver create(OutputStream out) throws IOException {
return new TarArchiver(method.compress(out));
}
private static final long serialVersionUID = 1L;
}
private static final class ZipArchiverFactory extends ArchiverFactory {
public Archiver create(OutputStream out) {
return new ZipArchiver(out);
}
private static final long serialVersionUID = 1L;
}
private static final long serialVersionUID = 1L;
}
/*
* The MIT License
*
* Copyright (c) 2010, InfraDNA, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.util.io;
import hudson.Functions;
import hudson.org.apache.tools.tar.TarOutputStream;
import hudson.util.FileVisitor;
import org.apache.tools.tar.TarEntry;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* {@link FileVisitor} that creates a tar archive.
*
* @see ArchiverFactory#TAR
*/
final class TarArchiver extends Archiver {
private final byte[] buf = new byte[8192];
private final TarOutputStream tar;
TarArchiver(OutputStream out) {
tar = new TarOutputStream(new BufferedOutputStream(out) {
// TarOutputStream uses TarBuffer internally,
// which flushes the stream for each block. this creates unnecessary
// data stream fragmentation, and flush request to a remote, which slows things down.
@Override
public void flush() throws IOException {
// so don't do anything in flush
}
});
tar.setLongFileMode(TarOutputStream.LONGFILE_GNU);
}
public void visit(File file, String relativePath) throws IOException {
if(Functions.isWindows())
relativePath = relativePath.replace('\\','/');
if(file.isDirectory())
relativePath+='/';
TarEntry te = new TarEntry(relativePath);
te.setModTime(file.lastModified());
if(!file.isDirectory())
te.setSize(file.length());
tar.putNextEntry(te);
if (!file.isDirectory()) {
FileInputStream in = new FileInputStream(file);
try {
int len;
while((len=in.read(buf))>=0)
tar.write(buf,0,len);
} finally {
in.close();
}
}
tar.closeEntry();
entriesWritten++;
}
public void close() throws IOException {
tar.close();
}
}
/*
* The MIT License
*
* Copyright (c) 2010, InfraDNA, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.util.io;
import hudson.util.FileVisitor;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* {@link FileVisitor} that creates a zip archive.
*
* @see ArchiverFactory#ZIP
*/
final class ZipArchiver extends Archiver {
private final byte[] buf = new byte[8192];
private final ZipOutputStream zip;
ZipArchiver(OutputStream out) {
zip = new ZipOutputStream(out);
zip.setEncoding(System.getProperty("file.encoding"));
}
public void visit(File f, String relativePath) throws IOException {
if(f.isDirectory()) {
ZipEntry dirZipEntry = new ZipEntry(relativePath+'/');
// Setting this bit explicitly is needed by some unzipping applications (see HUDSON-3294).
dirZipEntry.setExternalAttributes(BITMASK_IS_DIRECTORY);
zip.putNextEntry(dirZipEntry);
zip.closeEntry();
} else {
zip.putNextEntry(new ZipEntry(relativePath));
FileInputStream in = new FileInputStream(f);
int len;
while((len=in.read(buf))>0)
zip.write(buf,0,len);
in.close();
zip.closeEntry();
}
entriesWritten++;
}
public void close() throws IOException {
zip.close();
}
// Bitmask indicating directories in 'external attributes' of a ZIP archive entry.
private static final long BITMASK_IS_DIRECTORY = 1<<4;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册