Skip to content

Commit

Permalink
[FIXED JENKINS-21958] FilePath.copyRecursiveTo given a scanner includ…
Browse files Browse the repository at this point in the history
…ing a symlink but not any regular file in the same directory would neglect to create the parent directory on the destination and thus not copy the link.

(Util.createSymlink is partly to blame for not throwing a descriptive IOException when it fails to create a link,
but this is its historical behavior needed for compatibility.
copyRecursiveTo also continues to suppress error text from this method because there is nowhere for it to go.
Perhaps need a new variant of createSymlink that is guaranteed to either have created the link or throw an exception.)
  • Loading branch information
jglick committed Feb 26, 2014
1 parent 7b42017 commit 7c56817
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 6 deletions.
4 changes: 3 additions & 1 deletion changelog.html
Expand Up @@ -55,7 +55,9 @@
<!-- Record your changes in the trunk here. -->
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image>
<li class=>
<li class=bug>
Archiving of symlinks as artifacts did not work in some cases.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-21958">issue 21958</a>)
</ul>
</div><!--=TRUNK-END=-->

Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/hudson/FilePath.java
Expand Up @@ -1933,7 +1933,7 @@ public Integer invoke(File base, VirtualChannel channel) throws IOException {
@Override public void visit(File f, String relativePath) throws IOException {
if (f.isFile()) {
File target = new File(dest, relativePath);
target.getParentFile().mkdirs();
IOUtils.mkdirs(target.getParentFile());
Util.copyFile(f, target);
count.incrementAndGet();
}
Expand All @@ -1943,6 +1943,7 @@ public Integer invoke(File base, VirtualChannel channel) throws IOException {
}
@Override public void visitSymlink(File link, String target, String relativePath) throws IOException {
try {
IOUtils.mkdirs(new File(dest, relativePath).getParentFile());
Util.createSymlink(dest, target, relativePath, TaskListener.NULL);
} catch (InterruptedException x) {
throw (IOException) new IOException(x.toString()).initCause(x);
Expand Down
43 changes: 39 additions & 4 deletions test/src/test/java/hudson/tasks/ArtifactArchiverTest.java
Expand Up @@ -24,28 +24,32 @@

package hudson.tasks;

import hudson.model.AbstractProject;
import org.junit.Test;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Result;
import hudson.model.StreamBuildListener;
import hudson.tasks.LogRotatorTest.TestsFail;
import java.io.File;
import static hudson.tasks.LogRotatorTest.build;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import jenkins.util.VirtualFile;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.FailureBuilder;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestBuilder;
import static org.junit.Assert.*;

/**
* Verifies that artifacts from the last successful and stable builds of a job will be kept if requested.
Expand Down Expand Up @@ -167,6 +171,37 @@ public void testAllowEmptyArchive() throws Exception {
assertEquals("(no artifacts)", Result.SUCCESS, build(project));
assertFalse(project.getBuildByNumber(1).getHasArtifacts());
}

@Bug(21958)
@Test public void symlinks() throws Exception {
FreeStyleProject p = j.createFreeStyleProject();
p.getBuildersList().add(new TestBuilder() {
@Override public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
FilePath ws = build.getWorkspace();
if (ws == null) {
return false;
}
FilePath dir = ws.child("dir");
dir.mkdirs();
dir.child("fizz").write("contents", null);
dir.child("lodge").symlinkTo("fizz", listener);
return true;
}
});
p.getPublishersList().add(new ArtifactArchiver("dir/lodge", "", false, true));
FreeStyleBuild b = j.assertBuildStatusSuccess(p.scheduleBuild2(0));
FilePath ws = b.getWorkspace();
assertNotNull(ws);
assumeTrue("May not be testable on Windows:\n" + JenkinsRule.getLog(b), ws.child("dir/lodge").exists());
List<FreeStyleBuild.Artifact> artifacts = b.getArtifacts();
assertEquals(1, artifacts.size());
FreeStyleBuild.Artifact artifact = artifacts.get(0);
assertEquals("dir/lodge", artifact.relativePath);
VirtualFile[] kids = b.getArtifactManager().root().child("dir").list();
assertEquals(1, kids.length);
assertEquals("lodge", kids[0].getName());
// do not check that it .exists() since its target has not been archived
}

private void runNewBuildAndStartUnitlIsCreated(AbstractProject project) throws InterruptedException{
int buildNumber = project.getNextBuildNumber();
Expand Down

0 comments on commit 7c56817

Please sign in to comment.