提交 360f0950 编写于 作者: K kohsuke

[FIXED HUDSON-3153]

Added tar support

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@16172 71c3de6d-444a-0410-be80-ed276b4c234a
上级 f1dfa6ff
...@@ -39,14 +39,17 @@ import hudson.util.FormFieldValidator; ...@@ -39,14 +39,17 @@ import hudson.util.FormFieldValidator;
import hudson.util.IOException2; import hudson.util.IOException2;
import hudson.util.StreamResource; import hudson.util.StreamResource;
import hudson.util.HeadBufferingStream; import hudson.util.HeadBufferingStream;
import hudson.util.jna.GNUCLibrary;
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.util.FileUtils;
import org.apache.tools.ant.taskdefs.Copy; import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.taskdefs.Untar; import org.apache.tools.ant.taskdefs.Untar;
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.tar.TarOutputStream; import org.apache.tools.tar.TarOutputStream;
import org.apache.tools.tar.TarInputStream;
import org.apache.tools.zip.ZipOutputStream; import org.apache.tools.zip.ZipOutputStream;
import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipEntry;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
...@@ -316,6 +319,7 @@ public final class FilePath implements Serializable { ...@@ -316,6 +319,7 @@ public final class FilePath implements Serializable {
* @param target * @param target
* Target directory to expand files to. All the necessary directories will be created. * Target directory to expand files to. All the necessary directories will be created.
* @since 1.248 * @since 1.248
* @see #unzipFrom(InputStream)
*/ */
public void unzip(final FilePath target) throws IOException, InterruptedException { public void unzip(final FilePath target) throws IOException, InterruptedException {
target.act(new FileCallable<Void>() { target.act(new FileCallable<Void>() {
...@@ -327,12 +331,33 @@ public final class FilePath implements Serializable { ...@@ -327,12 +331,33 @@ public final class FilePath implements Serializable {
}); });
} }
/**
* When this {@link FilePath} represents a tar file, extracts that tar file.
*
* @param target
* Target directory to expand files to. All the necessary directories will be created.
* @param compression
* Compression mode of this tar file.
* @since 1.292
* @see #untarFrom(InputStream, TarCompression)
*/
public void untar(final FilePath target, final TarCompression compression) throws IOException, InterruptedException {
target.act(new FileCallable<Void>() {
public Void invoke(File dir, VirtualChannel channel) throws IOException {
readFromTar(FilePath.this.getName(),dir,compression.extract(FilePath.this.read()));
return null;
}
private static final long serialVersionUID = 1L;
});
}
/** /**
* Reads the given InputStream as a zip file and extracts it into this directory. * Reads the given InputStream as a zip file and extracts it into this directory.
* *
* @param _in * @param _in
* The stream will be closed by this method after it's fully read. * The stream will be closed by this method after it's fully read.
* @since 1.283 * @since 1.283
* @see #unzip(FilePath)
*/ */
public void unzipFrom(InputStream _in) throws IOException, InterruptedException { public void unzipFrom(InputStream _in) throws IOException, InterruptedException {
final InputStream in = new RemoteInputStream(_in); final InputStream in = new RemoteInputStream(_in);
...@@ -373,6 +398,62 @@ public final class FilePath implements Serializable { ...@@ -373,6 +398,62 @@ public final class FilePath implements Serializable {
} }
} }
/**
* Supported tar file compression methods.
*/
public enum TarCompression {
NONE {
public InputStream extract(InputStream in) {
return in;
}
public OutputStream compress(OutputStream out) {
return out;
}
},
GZIP {
public InputStream extract(InputStream _in) throws IOException {
HeadBufferingStream in = new HeadBufferingStream(_in,SIDE_BUFFER_SIZE);
try {
return new GZIPInputStream(in);
} catch (IOException e) {
// various people reported "java.io.IOException: Not in GZIP format" here, so diagnose this problem better
in.fillSide();
throw new IOException2(e.getMessage()+"\nstream="+Util.toHexString(in.getSideBuffer()),e);
}
}
public OutputStream compress(OutputStream out) throws IOException {
return new GZIPOutputStream(out);
}
};
public abstract InputStream extract(InputStream in) throws IOException;
public abstract OutputStream compress(OutputStream in) throws IOException;
}
/**
* Reads the given InputStream as a tar file and extracts it into this directory.
*
* @param _in
* The stream will be closed by this method after it's fully read.
* @param compression
* The compression method in use.
* @since 1.292
*/
public void untarFrom(InputStream _in, final TarCompression compression) throws IOException, InterruptedException {
try {
final InputStream in = new RemoteInputStream(_in);
act(new FileCallable<Void>() {
public Void invoke(File dir, VirtualChannel channel) throws IOException {
readFromTar("input stream",dir, compression.extract(in));
return null;
}
private static final long serialVersionUID = 1L;
});
} finally {
IOUtils.closeQuietly(_in);
}
}
/** /**
* Place the data from {@link FileItem} into the file location specified by this {@link FilePath} object. * Place the data from {@link FileItem} into the file location specified by this {@link FilePath} object.
*/ */
...@@ -959,14 +1040,14 @@ public final class FilePath implements Serializable { ...@@ -959,14 +1040,14 @@ public final class FilePath implements Serializable {
Future<Void> future = target.actAsync(new FileCallable<Void>() { Future<Void> future = target.actAsync(new FileCallable<Void>() {
public Void invoke(File f, VirtualChannel channel) throws IOException { public Void invoke(File f, VirtualChannel channel) throws IOException {
try { try {
readFromTar(remote+'/'+fileMask, f,pipe.getIn()); readFromTar(remote+'/'+fileMask, f,new GZIPInputStream(pipe.getIn()));
return null; return null;
} finally { } finally {
pipe.getIn().close(); pipe.getIn().close();
} }
} }
}); });
int r = writeToTar(new File(remote),fileMask,excludes,pipe); int r = writeToTar(new File(remote),fileMask,excludes,new GZIPOutputStream(pipe.getOut()));
try { try {
future.get(); future.get();
} catch (ExecutionException e) { } catch (ExecutionException e) {
...@@ -980,14 +1061,14 @@ public final class FilePath implements Serializable { ...@@ -980,14 +1061,14 @@ public final class FilePath implements Serializable {
Future<Integer> future = actAsync(new FileCallable<Integer>() { Future<Integer> future = actAsync(new FileCallable<Integer>() {
public Integer invoke(File f, VirtualChannel channel) throws IOException { public Integer invoke(File f, VirtualChannel channel) throws IOException {
try { try {
return writeToTar(f,fileMask,excludes,pipe); return writeToTar(f,fileMask,excludes,new GZIPOutputStream(pipe.getOut()));
} finally { } finally {
pipe.getOut().close(); pipe.getOut().close();
} }
} }
}); });
try { try {
readFromTar(remote+'/'+fileMask,new File(target.remote),pipe.getIn()); readFromTar(remote+'/'+fileMask,new File(target.remote),new GZIPInputStream(pipe.getIn()));
} catch (IOException e) {// BuildException or IOException } catch (IOException e) {// BuildException or IOException
try { try {
future.get(3,TimeUnit.SECONDS); future.get(3,TimeUnit.SECONDS);
...@@ -1014,12 +1095,12 @@ public final class FilePath implements Serializable { ...@@ -1014,12 +1095,12 @@ public final class FilePath implements Serializable {
* @return * @return
* number of files/directories that are written. * number of files/directories that are written.
*/ */
private Integer writeToTar(File baseDir, String fileMask, String excludes, Pipe pipe) throws IOException { private Integer writeToTar(File baseDir, String fileMask, String excludes, OutputStream out) throws IOException {
FileSet fs = Util.createFileSet(baseDir,fileMask,excludes); FileSet fs = Util.createFileSet(baseDir,fileMask,excludes);
byte[] buf = new byte[8192]; byte[] buf = new byte[8192];
TarOutputStream tar = new TarOutputStream(new GZIPOutputStream(new BufferedOutputStream(pipe.getOut()))); TarOutputStream tar = new TarOutputStream(new BufferedOutputStream(out));
tar.setLongFileMode(TarOutputStream.LONGFILE_GNU); tar.setLongFileMode(TarOutputStream.LONGFILE_GNU);
String[] files; String[] files;
if(baseDir.exists()) { if(baseDir.exists()) {
...@@ -1060,22 +1141,34 @@ public final class FilePath implements Serializable { ...@@ -1060,22 +1141,34 @@ public final class FilePath implements Serializable {
/** /**
* Reads from a tar stream and stores obtained files to the base dir. * Reads from a tar stream and stores obtained files to the base dir.
*/ */
private static void readFromTar(String name, File baseDir, InputStream _in) throws IOException { private static void readFromTar(String name, File baseDir, InputStream in) throws IOException {
Untar untar = new Untar(); TarInputStream t = new TarInputStream(in);
untar.setProject(new Project());
HeadBufferingStream in = new HeadBufferingStream(_in,SIDE_BUFFER_SIZE);
try { try {
untar.add(new StreamResource(name,new BufferedInputStream(new GZIPInputStream(in)))); TarEntry te;
} catch (IOException e) { while ((te = t.getNextEntry()) != null) {
// various people reported "java.io.IOException: Not in GZIP format" here, so diagnose this problem better File f = new File(baseDir,te.getName());
in.fillSide(); if(te.isDirectory()) {
throw new IOException2(e.getMessage()+"\nstream="+Util.toHexString(in.getSideBuffer()),e); f.mkdirs();
} } else {
untar.setDest(baseDir); File parent = f.getParentFile();
try { if (parent != null) parent.mkdirs();
untar.execute();
} catch (BuildException e) { OutputStream fos = new FileOutputStream(f);
throw new IOException2("Failed to read the remote stream "+name,e); try {
IOUtils.copy(t,fos);
} finally {
fos.close();
}
f.setLastModified(te.getModTime().getTime());
int mode = te.getMode()&0777;
if(mode!=0 && !Hudson.isWindows()) // be defensive
GNUCLibrary.LIBC.chmod(f.getPath(),mode);
}
}
} catch(IOException e) {
throw new IOException2("Failed to extract "+name,e);
} finally {
t.close();
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册