diff --git a/changelog.html b/changelog.html index 1d9e566633..d364fd33fc 100644 --- a/changelog.html +++ b/changelog.html @@ -58,6 +58,9 @@ Upcoming changes
  • Deleting an external run did not immediately remove it from build list, leading to errors from log rotation. (issue 19377) +
  • + When copying a directory from master to slave fails due to an error on the slave, properly report it. + (issue 9540)
  • Annotate the Advanced section if some fields are already customized. (issue 3107) diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 7466d9d6af..7bba63d3f7 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -1931,13 +1931,19 @@ public final class FilePath implements Serializable { } } }); - int r = writeToTar(new File(remote),fileMask,excludes,TarCompression.GZIP.compress(pipe.getOut())); + Future future2 = actAsync(new FileCallable() { + private static final long serialVersionUID = 1L; + @Override public Integer invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { + return writeToTar(new File(remote),fileMask,excludes,TarCompression.GZIP.compress(pipe.getOut())); + } + }); try { + // JENKINS-9540 in case the reading side failed, report that error first future.get(); + return future2.get(); } catch (ExecutionException e) { throw new IOException2(e); } - return r; } else { // remote -> local copy final Pipe pipe = Pipe.createRemoteToLocal(); diff --git a/core/src/test/java/hudson/FilePathTest.java b/core/src/test/java/hudson/FilePathTest.java index 04dca89a1a..762d0e7d96 100644 --- a/core/src/test/java/hudson/FilePathTest.java +++ b/core/src/test/java/hudson/FilePathTest.java @@ -206,6 +206,46 @@ public class FilePathTest extends ChannelTestCase { } } + @Bug(9540) + public void testErrorMessageInRemoteCopyRecursive() throws Exception { + File tmp = Util.createTempDir(); + try { + File src = new File(tmp, "src"); + File dst = new File(tmp, "dst"); + FilePath from = new FilePath(src); + FilePath to = new FilePath(british, dst.getAbsolutePath()); + for (int i = 0; i < 10000; i++) { + // TODO is there a simpler way to force the TarOutputStream to be flushed and the reader to start? + // Have not found a way to make the failure guaranteed. + OutputStream os = from.child("content" + i).write(); + try { + for (int j = 0; j < 1024; j++) { + os.write('.'); + } + } finally { + os.close(); + } + } + FilePath toF = to.child("content0"); + toF.write().close(); + toF.chmod(0400); + try { + from.copyRecursiveTo(to); + // on Windows this may just succeed; OK, test did not prove anything then + } catch (IOException x) { + if (Functions.printThrowable(x).contains("content0")) { + // Fine, error message talks about permission denied. + } else { + throw x; + } + } finally { + toF.chmod(700); + } + } finally { + Util.deleteRecursive(tmp); + } + } + public void testArchiveBug4039() throws Exception { File tmp = Util.createTempDir(); try {