Skip to content

Commit

Permalink
[FIXED JENKINS-13126] [FIXED JENKINS-13831] Option to create empty di…
Browse files Browse the repository at this point in the history
…rectories
  • Loading branch information
bap2000 committed Sep 28, 2012
1 parent 95f510a commit d2b08c1
Show file tree
Hide file tree
Showing 12 changed files with 405 additions and 98 deletions.
19 changes: 12 additions & 7 deletions src/main/java/jenkins/plugins/publish_over/BPBuildInfo.java
Expand Up @@ -108,20 +108,25 @@ public byte[] readFileFromMaster(final String filePath) {
}
}

public String getRelativePath(final FilePath filePath, final String removePrefix) throws IOException, InterruptedException {
final String normalizedPathToFile = filePath.toURI().normalize().getPath();
String relativePathToFile = normalizedPathToFile.replace(getNormalizedBaseDirectory(), "");
if (Util.fixEmptyAndTrim(removePrefix) != null) {
final String expanded = Util.fixEmptyAndTrim(Util.replaceMacro(removePrefix.trim(), getEnvVars()));
relativePathToFile = removePrefix(relativePathToFile, expanded);
}
public String getRelativePathToFile(final FilePath filePath, final String removePrefix) throws IOException, InterruptedException {
final String relativePathToFile = getRelativeDir(filePath, removePrefix);
final int lastDirIdx = relativePathToFile.lastIndexOf('/');
if (lastDirIdx == -1)
return "";
else
return relativePathToFile.substring(0, lastDirIdx);
}

public String getRelativeDir(final FilePath filePath, final String removePrefix) throws IOException, InterruptedException {
final String normalizedPath = filePath.toURI().normalize().getPath();
String relativePath = normalizedPath.replace(getNormalizedBaseDirectory(), "");
if (Util.fixEmptyAndTrim(removePrefix) != null) {
final String expanded = Util.fixEmptyAndTrim(Util.replaceMacro(removePrefix.trim(), getEnvVars()));
relativePath = removePrefix(relativePath, expanded);
}
return relativePath;
}

private String removePrefix(final String relativePathToFile, final String expandedPrefix) {
if (expandedPrefix == null) return relativePathToFile;
String toRemove = Util.fixEmptyAndTrim(FilenameUtils.separatorsToUnix(FilenameUtils.normalize(expandedPrefix + "/")));
Expand Down
136 changes: 49 additions & 87 deletions src/main/java/jenkins/plugins/publish_over/BPTransfer.java
Expand Up @@ -37,8 +37,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.LinkedHashSet;
import java.util.Locale;
Expand All @@ -50,77 +48,41 @@ public class BPTransfer implements Serializable {
private static final long serialVersionUID = 1L;
private static final Log LOG = LogFactory.getLog(BPTransfer.class);

@SuppressWarnings("PMD.PreserveStackTrace") // coz the ITE itself is not interesting!
private static FilePath[] listWithExcludes(final FilePath base, final String includes, final String excludes) {
final Method list = listWithExcludesMethod();
private static FileFinderResult list(final FilePath base, final String includes, final String excludes,
final boolean noDefaultExcludes, final boolean makeEmptyDirs) {
try {
return (FilePath[]) list.invoke(base, includes, excludes);
} catch (IllegalAccessException iae) {
throw new BapPublisherException("No chance!", iae);
} catch (InvocationTargetException ite) {
throw new BapPublisherException(Messages.exception_invokeList(includes, excludes), ite.getCause());
return base.act(new FileFinder(includes, excludes, !noDefaultExcludes, makeEmptyDirs));
} catch (IOException ioe) {
throw new BapPublisherException(Messages.exception_invokeListNoDefaultExcludes(includes, excludes, noDefaultExcludes), ioe);
} catch (InterruptedException ie) {
throw new BapPublisherException(Messages.exception_invokeListNoDefaultExcludes(includes, excludes, noDefaultExcludes), ie);
}
}

@SuppressWarnings("PMD.PreserveStackTrace") // coz the ITE itself is not interesting!
private static FilePath[] listWithNoDefaultExcludes(final FilePath base, final String includes, final String excludes, final boolean noDefaultExcludes) {
final Method list = listWithNoDefaultExcludesMethod();
try {
return (FilePath[]) list.invoke(base, includes, excludes, !noDefaultExcludes);
} catch (IllegalAccessException iae) {
throw new BapPublisherException("No chance!", iae);
} catch (InvocationTargetException ite) {
throw new BapPublisherException(Messages.exception_invokeListNoDefaultExcludes(includes, excludes, noDefaultExcludes), ite.getCause());
}
}

private static Method listWithExcludesMethod() {
try {
return FilePath.class.getMethod("list", String.class, String.class);
} catch (NoSuchMethodException nsme) {
return null;
}
}

private static Method listWithNoDefaultExcludesMethod() {
try {
return FilePath.class.getMethod("list", String.class, String.class, boolean.class);
} catch (NoSuchMethodException nsme) {
return null;
}
}

public static boolean canUseExcludes() {
return listWithExcludesMethod() != null;
}

public static boolean canUseNoDefaultExcludes() {
return listWithNoDefaultExcludesMethod() != null;
}

private String remoteDirectory;
private String sourceFiles;
private String excludes;
private String removePrefix;
private boolean remoteDirectorySDF;
private boolean flatten;
private boolean cleanRemote;
private boolean noDefaultExcludes;

// retain original constructor for testing as don't compile against new enough core to enable testing of excludes!
private final String remoteDirectory;
private final String sourceFiles;
private final String excludes;
private final String removePrefix;
private final boolean remoteDirectorySDF;
private final boolean flatten;
private final boolean cleanRemote;
private final boolean noDefaultExcludes;
private final boolean makeEmptyDirs;

// @TODO can now test excludes and default excludes
BPTransfer(final String sourceFiles, final String remoteDirectory, final String removePrefix,
final boolean remoteDirectorySDF, final boolean flatten) {
this(sourceFiles, null, remoteDirectory, removePrefix, remoteDirectorySDF, flatten, false, false);
this(sourceFiles, null, remoteDirectory, removePrefix, remoteDirectorySDF, flatten, false, false, false);
}

public BPTransfer(final String sourceFiles, final String excludes, final String remoteDirectory, final String removePrefix,
final boolean remoteDirectorySDF, final boolean flatten) {
this(sourceFiles, excludes, remoteDirectory, removePrefix, remoteDirectorySDF, flatten, false, false);
this(sourceFiles, excludes, remoteDirectory, removePrefix, remoteDirectorySDF, flatten, false, false, false);
}

public BPTransfer(final String sourceFiles, final String excludes, final String remoteDirectory, final String removePrefix,
final boolean remoteDirectorySDF, final boolean flatten, final boolean cleanRemote,
final boolean noDefaultExcludes) {
final boolean noDefaultExcludes, final boolean makeEmptyDirs) {
this.sourceFiles = sourceFiles;
this.excludes = excludes;
this.remoteDirectory = remoteDirectory;
Expand All @@ -129,51 +91,40 @@ public BPTransfer(final String sourceFiles, final String excludes, final String
this.flatten = flatten;
this.cleanRemote = cleanRemote;
this.noDefaultExcludes = noDefaultExcludes;
this.makeEmptyDirs = makeEmptyDirs;
}

public String getRemoteDirectory() { return remoteDirectory; }
public void setRemoteDirectory(final String remoteDirectory) { this.remoteDirectory = remoteDirectory; }

public String getSourceFiles() { return sourceFiles; }
public void setSourceFiles(final String sourceFiles) { this.sourceFiles = sourceFiles; }

public String getExcludes() { return excludes; }
public void setExcludes(final String excludes) { this.excludes = excludes; }

public String getRemovePrefix() { return removePrefix; }
public void setRemovePrefix(final String removePrefix) { this.removePrefix = removePrefix; }

public boolean isRemoteDirectorySDF() { return remoteDirectorySDF; }
public void setRemoteDirectorySDF(final boolean remoteDirectorySDF) { this.remoteDirectorySDF = remoteDirectorySDF; }

public boolean isFlatten() { return flatten; }
public void setFlatten(final boolean flatten) { this.flatten = flatten; }

public boolean isCleanRemote() { return cleanRemote; }
public void setCleanRemote(final boolean cleanRemote) { this.cleanRemote = cleanRemote; }

public boolean isNoDefaultExcludes() { return noDefaultExcludes; }
public void setNoDefaultExcludes(final boolean noDefaultExcludes) { this.noDefaultExcludes = noDefaultExcludes; }

public boolean isMakeEmptyDirs() { return makeEmptyDirs; }

public boolean hasConfiguredSourceFiles() {
return Util.fixEmptyAndTrim(getSourceFiles()) != null;
}

public FilePath[] getSourceFiles(final BPBuildInfo buildInfo) throws IOException, InterruptedException {
public FileFinderResult getSourceFiles(final BPBuildInfo buildInfo) throws IOException, InterruptedException {
final String expanded = Util.replaceMacro(sourceFiles, buildInfo.getEnvVars());
final String expandedExcludes = Util.fixEmptyAndTrim(Util.replaceMacro(excludes, buildInfo.getEnvVars()));
final boolean useExcludes = canUseExcludes() && expandedExcludes != null;
if (LOG.isDebugEnabled()) {
LOG.debug(Messages.log_sourceFiles(sourceFiles, expanded));
if (useExcludes)
if (expandedExcludes != null)
LOG.debug(Messages.log_excludes(excludes, expandedExcludes));
}
if (canUseNoDefaultExcludes())
return listWithNoDefaultExcludes(buildInfo.getBaseDirectory(), expanded, expandedExcludes, noDefaultExcludes);
else if (useExcludes)
return listWithExcludes(buildInfo.getBaseDirectory(), expanded, expandedExcludes);
else
return buildInfo.getBaseDirectory().list(expanded);
return list(buildInfo.getBaseDirectory(), expanded, expandedExcludes, noDefaultExcludes, makeEmptyDirs);
}

private void assertBaseDirectoryExists(final BPBuildInfo buildInfo) throws Exception {
Expand All @@ -195,10 +146,14 @@ public int transfer(final BPBuildInfo buildInfo, final BPClient client, final Tr
state.doneCleaning = true;
}
while (state.transferred < state.sourceFiles.length) {
dirMaker.changeAndMakeDirs(state.sourceFiles[state.transferred]);
dirMaker.changeAndMakeDirs(state.sourceFiles[state.transferred], false);
transferFile(client, state.sourceFiles[state.transferred]);
state.transferred++;
}
while (state.dirsMade < state.emptyDirs.length) {
dirMaker.changeAndMakeDirs(state.emptyDirs[state.dirsMade], true);
state.dirsMade++;
}
} catch (Exception e) {
throw new BapTransferException(e, state);
}
Expand Down Expand Up @@ -228,7 +183,7 @@ private class DirectoryMaker {
this.client = client;
}

public void changeAndMakeDirs(final FilePath filePath) throws IOException, InterruptedException {
public void changeAndMakeDirs(final FilePath filePath, final boolean isDirectory) throws IOException, InterruptedException {
if (flatten) {
assertNotDuplicateFileName(filePath);
if (!flattenResetCompleted) {
Expand All @@ -237,7 +192,8 @@ public void changeAndMakeDirs(final FilePath filePath) throws IOException, Inter
flattenResetCompleted = true;
}
}
final String relPath = buildInfo.getRelativePath(filePath, removePrefix);
final String relPath = isDirectory ? buildInfo.getRelativeDir(filePath, removePrefix)
: buildInfo.getRelativePathToFile(filePath, removePrefix);
if (LOG.isDebugEnabled())
LOG.debug(Messages.log_pathToFile(filePath.getName(), relPath));
if (!relPath.equals(previousPath) && !flatten) {
Expand Down Expand Up @@ -319,7 +275,7 @@ private boolean changeOrMakeAndChangeDirectory(final String directory) throws IO
private void changeToTargetDirectory(final FilePath filePath) throws IOException, InterruptedException {
if (flatten)
return;
final String relativePath = buildInfo.getRelativePath(filePath, removePrefix);
final String relativePath = buildInfo.getRelativePathToFile(filePath, removePrefix);
if (!"".equals(relativePath))
chdir(relativePath);
}
Expand All @@ -333,7 +289,8 @@ private void resetToSubDirectory() throws IOException {

protected HashCodeBuilder addToHashCode(final HashCodeBuilder builder) {
return builder.append(sourceFiles).append(removePrefix).append(remoteDirectory)
.append(remoteDirectorySDF).append(flatten).append(cleanRemote).append(excludes).append(noDefaultExcludes);
.append(remoteDirectorySDF).append(flatten).append(cleanRemote).append(excludes).append(noDefaultExcludes)
.append(makeEmptyDirs);
}

protected EqualsBuilder addToEquals(final EqualsBuilder builder, final BPTransfer that) {
Expand All @@ -344,7 +301,8 @@ protected EqualsBuilder addToEquals(final EqualsBuilder builder, final BPTransfe
.append(remoteDirectorySDF, that.remoteDirectorySDF)
.append(flatten, that.flatten)
.append(cleanRemote, that.cleanRemote)
.append(noDefaultExcludes, that.noDefaultExcludes);
.append(noDefaultExcludes, that.noDefaultExcludes)
.append(makeEmptyDirs, that.makeEmptyDirs);
}

protected ToStringBuilder addToToString(final ToStringBuilder builder) {
Expand All @@ -355,7 +313,8 @@ protected ToStringBuilder addToToString(final ToStringBuilder builder) {
.append("remoteDirectorySDF", remoteDirectorySDF)
.append("flatten", flatten)
.append("cleanRemote", cleanRemote)
.append("noDefaultExcludes", noDefaultExcludes);
.append("noDefaultExcludes", noDefaultExcludes)
.append("makeEmptyDirs", makeEmptyDirs);
}

public boolean equals(final Object that) {
Expand All @@ -376,13 +335,16 @@ public String toString() {
public static final class TransferState implements Serializable {
private static final long serialVersionUID = 1L;
private final FilePath[] sourceFiles;
private final FilePath[] emptyDirs;
private int transferred;
private int dirsMade;
private boolean doneCleaning;
private TransferState(final FilePath[] sourceFiles) {
this.sourceFiles = sourceFiles;
private TransferState(final FileFinderResult sources) {
this.sourceFiles = sources.getFiles();
this.emptyDirs = sources.getDirectories();
}
protected static TransferState create(final FilePath[] sourceFiles) {
return new TransferState(sourceFiles);
protected static TransferState create(final FileFinderResult sources) {
return new TransferState(sources);
}
}

Expand Down
103 changes: 103 additions & 0 deletions src/main/java/jenkins/plugins/publish_over/FileFinder.java
@@ -0,0 +1,103 @@
/*
* The MIT License
*
* Copyright (C) 2012 by Anthony Robinson
*
* 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 jenkins.plugins.publish_over;

import hudson.FilePath;
import hudson.remoting.VirtualChannel;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.FileSet;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;

public class FileFinder implements FilePath.FileCallable<FileFinderResult> {

private static final long serialVersionUID = 1L;

private final String includes;
private final String excludes;
private final boolean defaultExcludes;
private final boolean findEmptyDirectories;

public FileFinder(final String includes, final String excludes, final boolean defaultExcludes, final boolean findEmptyDirectories) {
this.includes = includes;
this.excludes = excludes;
this.defaultExcludes = defaultExcludes;
this.findEmptyDirectories = findEmptyDirectories;
}

public FileFinderResult invoke(final File file, final VirtualChannel virtualChannel) throws IOException, InterruptedException {
final DirectoryScanner scanner = createDirectoryScanner(file, includes, excludes, defaultExcludes);
final String[] includedFiles = scanner.getIncludedFiles();
final FilePath[] files = toFilePathArray(file, includedFiles);
FilePath[] dirs = new FilePath[0];
if (findEmptyDirectories) {
final String[] allDirs = scanner.getIncludedDirectories();
final String[] onlyLeaf = reduce(allDirs, allDirs);
dirs = toFilePathArray(file, reduce(onlyLeaf, includedFiles));
}
return new FileFinderResult(files, dirs);
}

private static DirectoryScanner createDirectoryScanner(final File dir, final String includes, final String excludes, final boolean defaultExcludes) throws IOException {
final FileSet fs = new FileSet();
fs.setDir(dir);
fs.setProject(new Project());
fs.setIncludes(includes);
if (excludes != null)
fs.setExcludes(excludes);
fs.setDefaultexcludes(defaultExcludes);
return fs.getDirectoryScanner();
}

static String[] reduce(final String[] directories, final String[] paths) {
final HashSet<String> result = new HashSet(Arrays.asList(directories));
final LinkedHashSet<String> pathSet = new LinkedHashSet(Arrays.asList(paths));
result.remove("");
pathSet.remove("");
for (final String dir : directories)
for (final String potential : pathSet)
if (potential.startsWith(dir + File.separator)) {
result.remove(dir);
pathSet.remove(dir);
break;
}
return result.toArray(new String[result.size()]);
}

private static FilePath[] toFilePathArray(final File file, final String[] includedFiles) {
final FilePath[] filePaths = new FilePath[includedFiles.length];
for (int i = 0; i < filePaths.length; i++)
filePaths[i] = new FilePath(new File(file, includedFiles[i]));
return filePaths;
}

}


0 comments on commit d2b08c1

Please sign in to comment.