package hudson.plugins.copyartifact;
import hudson.ExtensionPoint;
import hudson.FilePath;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.Run;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Extension point for how files are copied.
* CopyArtifact plugin provides a default implementation using methods
* available in the Jenkins FilePath class.
*
* <p>
* A copier instance
*
* @author Alan Harder
* @author Kohsuke Kawaguchi
* @see "JENKINS-7753"
*/
public abstract class Copier implements ExtensionPoint {
private static Logger LOG = Logger.getLogger(Copier.class.getName());
/**
* Called before copy-artifact operation.
*
* @param src
* The build record from which we are copying artifacts.
* @param dst
* The built into which we are copying artifacts.
* @param srcDir Source for upcoming file copy
* @param baseTargetDir Base target dir for upcoming file copy (the copy-artifact
* build step may later specify a deeper target dir)
*
* @throws IOException if an error occurs while performing the operation.
* @throws InterruptedException if any thread interrupts the current thread.
* @since TODO ?
*/
public void initialize(Run<?, ?> src, Run<?, ?> dst, FilePath srcDir, FilePath baseTargetDir) throws IOException, InterruptedException {
if (dst instanceof AbstractBuild && Util.isOverridden(Copier.class, getClass(), "init", Run.class, AbstractBuild.class, FilePath.class, FilePath.class)) {
init(src, (AbstractBuild<?,?>) dst, srcDir, baseTargetDir);
} else {
throw new AbstractMethodError(String.format("Invalid call to Copier.initialize(Run src, Run dst, FilePath, FilePath), passing an AbstractBuild " +
"instance for the 'dst' arg when %s does not implement the deprecated version of 'init' that takes an AbstractBuild. Please supply a " +
"Run instance for the 'dst' arg.", getClass().getName()));
}
}
/**
* Called before copy-artifact operation.
*
* @param src
* The build record from which we are copying artifacts.
* @param dst
* The built into which we are copying artifacts.
* @param srcDir Source for upcoming file copy
* @param baseTargetDir Base target dir for upcoming file copy (the copy-artifact
* build step may later specify a deeper target dir)
*
* @throws IOException if an error occurs while performing the operation.
* @throws InterruptedException if any thread interrupts the current thread.
* @deprecated Please use {@link #initialize(hudson.model.Run, hudson.model.Run, hudson.FilePath, hudson.FilePath)}
*/
@Deprecated
public void init(Run src, AbstractBuild<?,?> dst, FilePath srcDir, FilePath baseTargetDir) throws IOException, InterruptedException {
if (Util.isOverridden(Copier.class, getClass(), "initialize", Run.class, Run.class, FilePath.class, FilePath.class)) {
initialize((Run<?, ?>)src, dst, srcDir, baseTargetDir);
} else {
// Is near impossible for this to happen. Copier impl would need to not implement the newer version of the initialize method, while at
// the same time be changed to call super with a Run instance for dst, which would be bizarre because that could only have been done
// after the initialize method was changed to not be abstract.
throw new AbstractMethodError(String.format("Invalid call to Copier.init(Run src, AbstractBuild dst, FilePath, FilePath). " +
"%s implements the newer version of 'initialize' that takes a Run instance for the 'dst' arg. Please call that implementation.", getClass().getName()));
}
}
/**
* Copy files matching the given file mask to the specified target.
*
* @param srcDir Source directory
* @param filter Ant GLOB pattern
* @param targetDir Target directory
* @return Number of files that were copied
* @throws IOException if an error occurs while performing the operation.
* @throws InterruptedException if any thread interrupts the current thread.
* @deprecated
* call/override {@link #copyAll(FilePath srcDir, String filter, String excludes, FilePath targetDir, boolean fingerprintArtifacts)} instead.
*/
@Deprecated
public int copyAll(FilePath srcDir, String filter, FilePath targetDir) throws IOException, InterruptedException {
return copyAll(srcDir, filter, null, targetDir, true);
}
/**
* Copy files matching the given file mask to the specified target.
*
* @param srcDir Source directory
* @param filter Ant GLOB pattern
* @param targetDir Target directory
* @param fingerprintArtifacts boolean controlling if the copy should also fingerprint the artifacts
* @return Number of files that were copied
* @throws IOException if an error occurs while performing the operation.
* @throws InterruptedException if any thread interrupts the current thread.
* @deprecated
* call/override {@link #copyAll(FilePath, String, String, FilePath, boolean)} instead.
*/
@Deprecated
public int copyAll(FilePath srcDir, String filter, FilePath targetDir, boolean fingerprintArtifacts) throws IOException, InterruptedException {
return copyAll(srcDir, filter, null, targetDir, fingerprintArtifacts);
}
/**
* Copy files matching the given file mask to the specified target.
*
* You must override this when deriving {@link Copier}.
*
* @param srcDir Source directory
* @param filter Ant GLOB pattern
* @param excludes Ant GLOB pattern. Can be null.
* @param targetDir Target directory
* @param fingerprintArtifacts boolean controlling if the copy should also fingerprint the artifacts
* @throws IOException if an error occurs while performing the operation.
* @throws InterruptedException if any thread interrupts the current thread.
* @return Number of files that were copied
* @see FilePath#copyRecursiveTo(String,FilePath)
*/
public int copyAll(FilePath srcDir, String filter, String excludes, FilePath targetDir, boolean fingerprintArtifacts) throws IOException, InterruptedException {
try {
Class<?> classOfCopyAll = getClass().getMethod("copyAll", FilePath.class, String.class, FilePath.class, boolean.class).getDeclaringClass();
if (!Copier.class.equals(classOfCopyAll)) {
// For backward compatibility.
// avoid cyclic invocation.
return copyAll(srcDir, filter, targetDir, fingerprintArtifacts);
}
} catch(SecurityException e) {
LOG.log(Level.WARNING, "Unexpected exception in copyartifact-plugin", e);
} catch(NoSuchMethodException e) {
LOG.log(Level.WARNING, "Unexpected exception in copyartifact-plugin", e);
}
throw new AbstractMethodError("You need override Copier#copyAll(FilePath, String, String, FilePath, boolean)");
}
/**
* Copy a single file.
* @param source Source file
* @param target Target file (includes filename; this is not the target directory).
* Directory for target should already exist (copy-artifact build step calls mkdirs).
* @throws IOException if an error occurs while performing the operation.
* @throws InterruptedException if any thread interrupts the current thread.
* @deprecated
* call/override {@link #copyOne(FilePath source, FilePath target, boolean fingerprintArtifacts)} instead.
*/
@Deprecated
public void copyOne(FilePath source, FilePath target) throws IOException, InterruptedException {
copyOne(source, target, true);
}
/**
* Copy a single file.
* @param source Source file
* @param target Target file (includes filename; this is not the target directory).
* Directory for target should already exist (copy-artifact build step calls mkdirs).
* @param fingerprintArtifacts boolean controlling if the copy should also fingerprint the artifacts
* @throws IOException if an error occurs while performing the operation.
* @throws InterruptedException if any thread interrupts the current thread.
* @see FilePath#copyTo(FilePath)
*/
public abstract void copyOne(FilePath source, FilePath target, boolean fingerprintArtifacts) throws IOException, InterruptedException;
/**
* Ends what's started by the {@link #init(Run, AbstractBuild, FilePath, FilePath)} method.
* @throws IOException if an error occurs while performing the operation.
*/
public void end() throws IOException, InternalError {}
/**
* Creates a clone.
*
* This method is only called before the {@link #init(Run, AbstractBuild, FilePath, FilePath)} method
* to allow each initialize-end session to run against different objects, so you need not copy any state
* that your {@link Copier} might maintain.
*
* This is a cheap hack to implement a factory withot breaking backward compatibility.
*
* If you maintain no state, this method can return {@code this} without creating a copy.
*/
@Override
public abstract Copier clone();
}