diff --git a/pom.xml b/pom.xml index 448c3f9..f9462a3 100644 --- a/pom.xml +++ b/pom.xml @@ -74,9 +74,9 @@ matrix-project - com.atlassian - ant-filesystem-tasks - 0.0.5 + com.github.jnr + jnr-posix + 3.1.15 @@ -85,11 +85,6 @@ repo.jenkins-ci.org https://repo.jenkins-ci.org/public/ - - atlassian-public - https://maven.atlassian.com/repository/public - - diff --git a/src/main/java/org/jenkinsci/plugins/artifactdeployer/service/CopyWithPerms.java b/src/main/java/org/jenkinsci/plugins/artifactdeployer/service/CopyWithPerms.java new file mode 100644 index 0000000..1df1baf --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/artifactdeployer/service/CopyWithPerms.java @@ -0,0 +1,157 @@ +package org.jenkinsci.plugins.artifactdeployer.service; + +import java.io.File; +import java.io.IOException; +import java.util.Enumeration; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Copy; +import org.apache.tools.ant.types.FilterSet; +import org.apache.tools.ant.types.FilterSetCollection; + +public class CopyWithPerms extends Copy +{ + + static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + private boolean preservePermissions = true; + + public boolean isPreservePermissions() + { + return preservePermissions; + } + + public void setPreservePermissions(boolean preservePermissions) + { + this.preservePermissions = preservePermissions; + } + + /** + * Actually does the file (and possibly empty directory) copies. + * This is a good method for subclasses to override. + */ + @Override + protected void doFileOperations() { + if (fileCopyMap.size() > 0) { + log("Copying " + fileCopyMap.size() + + " file" + (fileCopyMap.size() == 1 ? "" : "s") + + " to " + destDir.getAbsolutePath()); + + Enumeration e = fileCopyMap.keys(); + while (e.hasMoreElements()) { + String fromFile = (String) e.nextElement(); + String[] toFiles = (String[]) fileCopyMap.get(fromFile); + + for (int i = 0; i < toFiles.length; i++) { + String toFile = toFiles[i]; + + if (fromFile.equals(toFile)) { + log("Skipping self-copy of " + fromFile, verbosity); + continue; + } + try { + log("Copying " + fromFile + " to " + toFile, verbosity); + + FilterSetCollection executionFilters = + new FilterSetCollection(); + if (filtering) { + executionFilters + .addFilterSet(getProject().getGlobalFilterSet()); + } + for (Enumeration filterEnum = getFilterSets().elements(); + filterEnum.hasMoreElements();) { + executionFilters + .addFilterSet((FilterSet) filterEnum.nextElement()); + } + fileUtils.copyFile(new File(fromFile), new File(toFile), + executionFilters, + getFilterChains(), forceOverwrite, + preserveLastModified, + /* append: */ false, getEncoding(), + getOutputEncoding(), getProject() + /*, getForce()*/); //ant 1.8.2 + + if (preservePermissions) { + int perms = PermissionsUtils.getPermissions(new File(fromFile)); + PermissionsUtils.setPermissions(new File(toFile), perms); + } + + } catch (IOException ioe) { + String msg = "Failed to copy " + fromFile + " to " + toFile + + " due to " + getDueTo(ioe); + File targetFile = new File(toFile); + if (targetFile.exists() && !targetFile.delete()) { + msg += " and I couldn't delete the corrupt " + toFile; + } + if (failonerror) { + throw new BuildException(msg, ioe, getLocation()); + } + log(msg, Project.MSG_ERR); + } + } + } + } + if (includeEmpty) { + Enumeration e = dirCopyMap.elements(); + int createCount = 0; + while (e.hasMoreElements()) { + String[] dirs = (String[]) e.nextElement(); + for (int i = 0; i < dirs.length; i++) { + File d = new File(dirs[i]); + if (!d.exists()) { + if (!d.mkdirs()) { + log("Unable to create directory " + + d.getAbsolutePath(), Project.MSG_ERR); + } else { + createCount++; + } + } + } + } + if (createCount > 0) { + log("Copied " + dirCopyMap.size() + + " empty director" + + (dirCopyMap.size() == 1 ? "y" : "ies") + + " to " + createCount + + " empty director" + + (createCount == 1 ? "y" : "ies") + " under " + + destDir.getAbsolutePath()); + } + } + } + + + /** + * Returns a reason for failure based on + * the exception thrown. + * If the exception is not IOException output the class name, + * output the message + * if the exception is MalformedInput add a little note. + */ + private String getDueTo(Exception ex) { + boolean baseIOException = ex.getClass() == IOException.class; + StringBuffer message = new StringBuffer(); + if (!baseIOException || ex.getMessage() == null) { + message.append(ex.getClass().getName()); + } + if (ex.getMessage() != null) { + if (!baseIOException) { + message.append(" "); + } + message.append(ex.getMessage()); + } + if (ex.getClass().getName().indexOf("MalformedInput") != -1) { + message.append(LINE_SEPARATOR); + message.append( + "This is normally due to the input file containing invalid"); + message.append(LINE_SEPARATOR); + message.append("bytes for the character encoding used : "); + message.append( + (getEncoding() == null + ? fileUtils.getDefaultEncoding() : getEncoding())); + message.append(LINE_SEPARATOR); + } + return message.toString(); + } +} diff --git a/src/main/java/org/jenkinsci/plugins/artifactdeployer/service/LocalCopy.java b/src/main/java/org/jenkinsci/plugins/artifactdeployer/service/LocalCopy.java index dc1c92f..dc13a32 100644 --- a/src/main/java/org/jenkinsci/plugins/artifactdeployer/service/LocalCopy.java +++ b/src/main/java/org/jenkinsci/plugins/artifactdeployer/service/LocalCopy.java @@ -22,7 +22,6 @@ */ package org.jenkinsci.plugins.artifactdeployer.service; -import com.atlassian.ant.tasks.CopyWithPerms; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.types.FileSet; import org.jenkinsci.plugins.artifactdeployer.ArtifactDeployerException; diff --git a/src/main/java/org/jenkinsci/plugins/artifactdeployer/service/PermissionsUtils.java b/src/main/java/org/jenkinsci/plugins/artifactdeployer/service/PermissionsUtils.java new file mode 100644 index 0000000..adba91f --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/artifactdeployer/service/PermissionsUtils.java @@ -0,0 +1,25 @@ +package org.jenkinsci.plugins.artifactdeployer.service; + +import java.io.File; + +import jnr.posix.POSIX; +import jnr.posix.POSIXFactory; +import jnr.posix.util.DefaultPOSIXHandler; + +/** + * Provides convenience methods for manipulating file permissions, as best as is achievable with the Java 6 API. + */ +public class PermissionsUtils +{ + private static POSIX posix = POSIXFactory.getPOSIX(new DefaultPOSIXHandler(), true); + + public static int getPermissions(File file) + { + return posix.stat(file.getAbsolutePath()).mode() & 0777; + } + + public static void setPermissions(File file, int perms) + { + posix.chmod(file.getAbsolutePath(), perms); + } +}