diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 81a7c52479..a4a704cc7c 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -2347,6 +2347,19 @@ public final class FilePath implements SerializableOnlyOverRemoting { * @since 1.532 */ public int copyRecursiveTo(final DirScanner scanner, final FilePath target, final String description) throws IOException, InterruptedException { + return copyRecursiveTo(scanner, target, description, GZIP); + } + + /** + * Copies files according to a specified scanner to a target node. + * @param scanner a way of enumerating some files (must be serializable for possible delivery to remote side) + * @param target the destination basedir + * @param description a description of the fileset, for logging purposes + * @param compression compression to use + * @return the number of files copied + * @since TODO + */ + public int copyRecursiveTo(final DirScanner scanner, final FilePath target, final String description, @Nonnull TarCompression compression) throws IOException, InterruptedException { if(this.channel==target.channel) { // local to local copy. return act(new CopyRecursiveLocal(target, scanner)); @@ -2355,8 +2368,8 @@ public final class FilePath implements SerializableOnlyOverRemoting { // local -> remote copy final Pipe pipe = Pipe.createLocalToRemote(); - Future future = target.actAsync(new ReadToTar(pipe, description)); - Future future2 = actAsync(new WriteToTar(scanner, pipe)); + Future future = target.actAsync(new ReadToTar(pipe, description, compression)); + Future future2 = actAsync(new WriteToTar(scanner, pipe, compression)); try { // JENKINS-9540 in case the reading side failed, report that error first future.get(); @@ -2368,9 +2381,9 @@ public final class FilePath implements SerializableOnlyOverRemoting { // remote -> local copy final Pipe pipe = Pipe.createRemoteToLocal(); - Future future = actAsync(new CopyRecursiveRemoteToLocal(pipe, scanner)); + Future future = actAsync(new CopyRecursiveRemoteToLocal(pipe, scanner, compression)); try { - readFromTar(remote + '/' + description,new File(target.remote),TarCompression.GZIP.extract(pipe.getIn())); + readFromTar(remote + '/' + description,new File(target.remote),compression.extract(pipe.getIn())); } catch (IOException e) {// BuildException or IOException try { future.get(3,TimeUnit.SECONDS); @@ -2471,15 +2484,18 @@ public final class FilePath implements SerializableOnlyOverRemoting { private class ReadToTar extends SecureFileCallable { private final Pipe pipe; private final String description; - ReadToTar(Pipe pipe, String description) { + private final TarCompression compression; + + ReadToTar(Pipe pipe, String description, @Nonnull TarCompression compression) { this.pipe = pipe; this.description = description; + this.compression = compression; } private static final long serialVersionUID = 1L; @Override public Void invoke(File f, VirtualChannel channel) throws IOException { try (InputStream in = pipe.getIn()) { - readFromTar(remote + '/' + description, f, TarCompression.GZIP.extract(in)); + readFromTar(remote + '/' + description, f, compression.extract(in)); return null; } } @@ -2487,28 +2503,32 @@ public final class FilePath implements SerializableOnlyOverRemoting { private class WriteToTar extends SecureFileCallable { private final DirScanner scanner; private final Pipe pipe; - WriteToTar(DirScanner scanner, Pipe pipe) { + private final TarCompression compression; + WriteToTar(DirScanner scanner, Pipe pipe, @Nonnull TarCompression compression) { this.scanner = scanner; this.pipe = pipe; + this.compression = compression; } private static final long serialVersionUID = 1L; @Override public Integer invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { - return writeToTar(new File(remote), scanner, TarCompression.GZIP.compress(pipe.getOut())); + return writeToTar(new File(remote), scanner, compression.compress(pipe.getOut())); } } private class CopyRecursiveRemoteToLocal extends SecureFileCallable { private static final long serialVersionUID = 1L; private final Pipe pipe; private final DirScanner scanner; - CopyRecursiveRemoteToLocal(Pipe pipe, DirScanner scanner) { + private final TarCompression compression; + CopyRecursiveRemoteToLocal(Pipe pipe, DirScanner scanner, @Nonnull TarCompression compression) { this.pipe = pipe; this.scanner = scanner; + this.compression = compression; } @Override public Integer invoke(File f, VirtualChannel channel) throws IOException { try (OutputStream out = pipe.getOut()) { - return writeToTar(f, scanner, TarCompression.GZIP.compress(out)); + return writeToTar(f, scanner, compression.compress(out)); } } } diff --git a/core/src/main/java/jenkins/model/StandardArtifactManager.java b/core/src/main/java/jenkins/model/StandardArtifactManager.java index a4f8b9df8d..33b53db5aa 100644 --- a/core/src/main/java/jenkins/model/StandardArtifactManager.java +++ b/core/src/main/java/jenkins/model/StandardArtifactManager.java @@ -24,6 +24,7 @@ package jenkins.model; +import com.google.common.annotations.VisibleForTesting; import hudson.FilePath; import hudson.Launcher; import hudson.Util; @@ -35,6 +36,8 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import jenkins.util.VirtualFile; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; /** * Default artifact manager which transfers files over the remoting channel and stores them inside the build directory. @@ -45,6 +48,12 @@ public class StandardArtifactManager extends ArtifactManager { private static final Logger LOG = Logger.getLogger(StandardArtifactManager.class.getName()); + @Restricted(NoExternalUse.class) + @VisibleForTesting + public static FilePath.TarCompression TAR_COMPRESSION = Boolean.getBoolean(StandardArtifactManager.class.getName() + ".disableTrafficCompression") + ? FilePath.TarCompression.NONE + : FilePath.TarCompression.GZIP; + protected transient Run build; public StandardArtifactManager(Run build) { @@ -58,7 +67,7 @@ public class StandardArtifactManager extends ArtifactManager { @Override public void archive(FilePath workspace, Launcher launcher, BuildListener listener, final Map artifacts) throws IOException, InterruptedException { File dir = getArtifactsDir(); String description = "transfer of " + artifacts.size() + " files"; // TODO improve when just one file - workspace.copyRecursiveTo(new FilePath.ExplicitlySpecifiedDirScanner(artifacts), new FilePath(dir), description); + workspace.copyRecursiveTo(new FilePath.ExplicitlySpecifiedDirScanner(artifacts), new FilePath(dir), description, TAR_COMPRESSION); } @Override public final boolean delete() throws IOException, InterruptedException { diff --git a/test/src/test/java/hudson/tasks/ArtifactArchiverTest.java b/test/src/test/java/hudson/tasks/ArtifactArchiverTest.java index 80501f9cb9..5e126c821a 100644 --- a/test/src/test/java/hudson/tasks/ArtifactArchiverTest.java +++ b/test/src/test/java/hudson/tasks/ArtifactArchiverTest.java @@ -47,6 +47,7 @@ import hudson.model.Run; import hudson.remoting.VirtualChannel; import hudson.slaves.DumbSlave; import jenkins.MasterToSlaveFileCallable; +import jenkins.model.StandardArtifactManager; import jenkins.util.VirtualFile; import org.hamcrest.Matchers; import org.jenkinsci.plugins.structs.describable.DescribableModel; @@ -69,6 +70,22 @@ public class ArtifactArchiverTest { @ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); @Rule public JenkinsRule j = new JenkinsRule(); + @Test + @Issue("JENKINS-26008") + public void testNoneCompression() throws Exception { + final FilePath.TarCompression prevCompression = StandardArtifactManager.TAR_COMPRESSION; + StandardArtifactManager.TAR_COMPRESSION = FilePath.TarCompression.NONE; + try { + final FreeStyleProject project = j.createFreeStyleProject(); + project.getBuildersList().add(new CreateArtifact()); + project.getPublishersList().add(new ArtifactArchiver("f")); + assertEquals(Result.SUCCESS, build(project)); + assertTrue(project.getBuildByNumber(1).getHasArtifacts()); + } finally { + StandardArtifactManager.TAR_COMPRESSION = prevCompression; + } + } + @Test @Issue("JENKINS-3227") public void testEmptyDirectories() throws Exception {