package hudson.plugins.doxygen;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.tasks.*;
import hudson.util.FormValidation;
import hudson.model.AbstractBuild;
import hudson.model.AbstractItem;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.BuildListener;
import hudson.model.DirectoryBrowserSupport;
import hudson.model.ProminentProjectAction;
import hudson.model.Result;
import hudson.model.Run;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import javax.servlet.ServletException;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.*;
/**
*
* @author Gregory Boissinot
*/
public class DoxygenArchiver extends Recorder implements Serializable {
private static final long serialVersionUID = 1L;
@Extension
public static final DoxygenArchiverDescriptor DESCRIPTOR = new DoxygenArchiverDescriptor();
/**
* Path to the Doxyfile file.
*/
private final String doxyfilePath;
/**
* If true, retain doxygen for all the successful builds.
*/
private final boolean keepAll;
/**
* The publishing type : with the doxyfile or directly the html directory
*/
private transient String publishType;
/**
* The doxygen html directory
*/
private transient String doxygenHtmlDirectory;
public String getDoxyfilePath() {
return doxyfilePath;
}
public boolean isKeepAll() {
return keepAll;
}
@Deprecated
public String getPublishType() {
return publishType;
}
@Deprecated
public String getDoxygenHtmlDirectory() {
return doxygenHtmlDirectory;
}
public static final class DoxygenArchiverDescriptor extends
BuildStepDescriptor<Publisher> {
public static final String DOXYGEN_DOXYFILE_PUBLISHTYPE = "DoxyFile";
public static final String DOXYGEN_HTMLDIRECTORY_PUBLISHTYPE = "HtmlDirectory";
public static final String DEFAULT_DOXYGEN_PUBLISHTYPE = DOXYGEN_DOXYFILE_PUBLISHTYPE;
public DoxygenArchiverDescriptor() {
super(DoxygenArchiver.class);
}
@Override
public String getDisplayName() {
return "Publish Doxygen";
}
@Override
public Publisher newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return req.bindJSON(DoxygenArchiver.class, formData);
}
public FormValidation doCheckDoxyfilePath(@AncestorInPath AbstractProject project, @QueryParameter String value) throws IOException {
FilePath ws = project.getSomeWorkspace();
return ws!=null ? ws.validateFileMask(value, true) : FormValidation.ok();
}
@Override
public String getHelpFile() {
return "/plugin/doxygen/help.html";
}
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}
}
@DataBoundConstructor
public DoxygenArchiver(String doxyfilePath, boolean keepAll) {
this.doxyfilePath = doxyfilePath.trim();
this.keepAll = keepAll;
}
@Override
public boolean prebuild(AbstractBuild<?, ?> build, BuildListener listener) {
return true;
}
/**
* Gets the directory where the Doxygen is stored for the given project.
*/
private static File getDoxygenDir(AbstractItem project) {
return new File(project.getRootDir(), "doxygen/html");
}
/**
* Gets the directory where the Doxygen is stored for the given build.
*/
private static File getDoxygenDir(Run run) {
return new File(run.getRootDir(), "doxygen/html");
}
@SuppressWarnings("unchecked")
@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher,
BuildListener listener) throws InterruptedException, IOException {
if ((build.getResult().equals(Result.SUCCESS))
|| (build.getResult().equals(Result.UNSTABLE))) {
listener.getLogger().println("Publishing Doxygen HTML results.");
try {
DoxygenDirectoryParser parser = new DoxygenDirectoryParser(
publishType, doxyfilePath, doxygenHtmlDirectory);
FilePath doxygenGeneratedDir = build.getWorkspace().act(parser);
listener.getLogger().println(
"The determined Doxygen directory is '"
+ doxygenGeneratedDir + "'.");
// Determine the future stored doxygen directory
FilePath target = new FilePath(keepAll ? getDoxygenDir(build)
: getDoxygenDir(build.getProject()));
if (doxygenGeneratedDir.copyRecursiveTo("**/*", target) == 0) {
if (build.getResult().isBetterOrEqualTo(Result.UNSTABLE)) {
// If the build failed, don't complain that there was no
// javadoc.
// The build probably didn't even get to the point where
// it produces javadoc.
}
listener.getLogger().println(
"Failure to copy the generated doxygen html documentation at '"
+ doxygenHtmlDirectory + "' to '" + target
+ "'");
build.setResult(Result.FAILURE);
return true;
}
// add build action, if doxygen is recorded for each build
if (keepAll)
build.addAction(new DoxygenBuildAction(build));
} catch (Exception e) {
e.printStackTrace(listener.fatalError("error"));
build.setResult(Result.FAILURE);
return true;
}
listener.getLogger().println("End publishing Doxygen HTML results.");
}
else{
listener.getLogger().println("Build failed. Publishing Doxygen skipped.");
}
return true;
}
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.STEP;
}
@Override
public DoxygenArchiverDescriptor getDescriptor() {
return DESCRIPTOR;
}
@Override
public Action getProjectAction(AbstractProject<?, ?> project) {
return new DoxygenAction(project);
}
protected static abstract class BaseDoxygenAction implements Action {
public String getUrlName() {
return "doxygen";
}
public String getDisplayName() {
return "DoxyGen HTML";
}
public String getIconFileName() {
if (dir().exists())
return "help.gif";
else
// hide it since we don't have doxygen yet.
return null;
}
public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
DirectoryBrowserSupport dbs = new DirectoryBrowserSupport(this, new FilePath(this.dir()), this.getTitle(), "graph.gif", false);
dbs.generateResponse(req, rsp, this);
}
protected abstract String getTitle();
protected abstract File dir();
}
public static class DoxygenAction extends BaseDoxygenAction implements
ProminentProjectAction {
private final AbstractItem project;
public DoxygenAction(AbstractItem project) {
this.project = project;
}
protected File dir() {
if (project instanceof AbstractProject) {
AbstractProject abstractProject = (AbstractProject) project;
Run run = abstractProject.getLastSuccessfulBuild();
if (run != null) {
File doxygenDir = getDoxygenDir(run);
if (doxygenDir.exists())
return doxygenDir;
}
}
return getDoxygenDir(project);
}
protected String getTitle() {
return project.getDisplayName() + " doxygen";
}
}
public static class DoxygenBuildAction extends BaseDoxygenAction {
private final AbstractBuild<?, ?> build;
public DoxygenBuildAction(AbstractBuild<?, ?> build) {
this.build = build;
}
protected String getTitle() {
return build.getDisplayName() + " doxygen/html";
}
protected File dir() {
return new File(build.getRootDir(), "doxygen/html");
}
}
}