package com.zanox.hudson.plugins; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; import hudson.Util; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildListener; import hudson.model.Descriptor; import hudson.model.Result; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.BuildStepMonitor; import hudson.tasks.Notifier; import hudson.tasks.Publisher; import hudson.util.CopyOnWriteList; import hudson.util.FormValidation; import java.io.IOException; import java.net.URI; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; import com.jcraft.jsch.SftpException; /** * <p> * This class implements the ftp publisher process by using the {@link FTPSite}. * </p> * <p> * HeadURL: $HeadURL: http://z-bld-02:8080/zxdev/zxant_test_environment/trunk/formatting/codeTemplates.xml $<br /> * Date: $Date: 2008-04-22 11:53:34 +0200 (Di, 22 Apr 2008) $<br /> * Revision: $Revision: 2451 $<br /> * </p> * * @author $Author: ZANOX-COM\fit $ * */ public class FTPPublisher extends Notifier { /** * Hold an instance of the Descriptor implementation of this publisher. */ @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); /** * This is a SimpleDateFormat instance to get a directory name which include a time stamp. */ protected static final SimpleDateFormat ID_FORMATTER = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); private String siteName; private final List<Entry> entries = new ArrayList<Entry>(); private Boolean useTimestamps = false; private Boolean flatten = true; public void setUseTimestamps(boolean useTimestamps) { this.useTimestamps = useTimestamps; } public boolean isUseTimestamps() { return useTimestamps; } public void setFlatten(boolean flatten) { this.flatten = flatten; } public boolean isFlatten() { return flatten; } public FTPPublisher() { int a = 2; } /** * The constructor which take a configured ftp site name to publishing the artifacts. * * @param siteName * the name of the ftp site configuration to use */ public FTPPublisher(String siteName) { this.siteName = siteName; } /** * The getter for the entries field. (this field is set by the UI part of this plugin see config.jelly file) * * @return the value of the entries field */ public List<Entry> getEntries() { return entries; } /** * This method returns the configured FTPSite object which match the siteName of the FTPPublisher instance. (see Manage Hudson and System * Configuration point FTP) * * @return the matching FTPSite or null */ public FTPSite getSite() { FTPSite[] sites = DESCRIPTOR.getSites(); if (siteName == null && sites.length > 0) { // default return sites[0]; } for (FTPSite site : sites) { if (site.getName().equals(siteName)) { return site; } } return null; } public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.BUILD; } /** * {@inheritDoc} * * @param build * @param launcher * @param listener * @return * @throws InterruptedException * @throws IOException * {@inheritDoc} * @see hudson.tasks.BuildStep#perform(hudson.model.Build, hudson.Launcher, hudson.model.BuildListener) */ @Override public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { if (build.getResult() == Result.FAILURE || build.getResult() == Result.ABORTED) { // build failed. don't post return true; } FTPSite ftpsite = null; try { ftpsite = getSite(); listener.getLogger().println("Connecting to " + ftpsite.getHostname()); ftpsite.createSession(); EntryCopier copier = new EntryCopier(build, listener, ftpsite, flatten, useTimestamps); int copied = 0; for (Entry e : entries) { copied += copier.copy(e); } listener.getLogger().println("Transfered " + copied + " files."); } catch (Throwable th) { th.printStackTrace(listener.error("Failed to upload files")); build.setResult(Result.UNSTABLE); } finally { if (ftpsite != null) { ftpsite.closeSession(); } } return true; } /** * <p> * This class holds the metadata for the FTPPublisher. * </p> * * @author $Author: ZANOX-COM\fit $ * @see Descriptor */ public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> { private final CopyOnWriteList<FTPSite> sites = new CopyOnWriteList<FTPSite>(); /** * The default constructor. */ public DescriptorImpl() { super(FTPPublisher.class); load(); } /** * The name of the plugin to display them on the project configuration web page. * * {@inheritDoc} * * @return {@inheritDoc} * @see hudson.model.Descriptor#getDisplayName() */ @Override public String getDisplayName() { return "Publish artifacts to FTP"; } /** * Return the location of the help document for this publisher. * * {@inheritDoc} * * @return {@inheritDoc} * @see hudson.model.Descriptor#getHelpFile() */ @Override public String getHelpFile() { return "/plugin/ftppublisher/help.html"; } @Override public boolean isApplicable(Class<? extends AbstractProject> jobType) { return true; } /** * This method is called by hudson if the user has clicked the add button of the FTP repository hosts point in the System Configuration * web page. It's create a new instance of the {@link FTPPublisher} class and added all configured ftp sites to this instance by calling * the method {@link FTPPublisher#getEntries()} and on it's return value the addAll method is called. * * {@inheritDoc} * * @param req * {@inheritDoc} * @return {@inheritDoc} * @see hudson.model.Descriptor#newInstance(org.kohsuke.stapler.StaplerRequest) */ @Override public Publisher newInstance(StaplerRequest req, JSONObject formData) { FTPPublisher pub = new FTPPublisher(); pub.setFlatten(formData.getBoolean("flatten")); pub.setUseTimestamps(formData.getBoolean("useTimestamps")); req.bindParameters(pub, "publisher."); req.bindParameters(pub, "ftp."); pub.getEntries().addAll(req.bindParametersToList(Entry.class, "ftp.entry.")); return pub; } /** * The getter of the sites field. * * @return the value of the sites field. */ public FTPSite[] getSites() { Iterator<FTPSite> it = sites.iterator(); int size = 0; while (it.hasNext()) { it.next(); size++; } return sites.toArray(new FTPSite[size]); } /** * {@inheritDoc} * * @param req * {@inheritDoc} * @return {@inheritDoc} * @see hudson.model.Descriptor#configure(org.kohsuke.stapler.StaplerRequest) */ @Override public boolean configure(StaplerRequest req, JSONObject formData) { sites.replaceBy(req.bindParametersToList(FTPSite.class, "ftp.")); save(); return true; } /** * This method validates the current entered ftp configuration data. That is made by create a ftp connection. * * @param request * the current {@link javax.servlet.http.HttpServletRequest} */ public FormValidation doLoginCheck(StaplerRequest request) { String hostname = Util.fixEmpty(request.getParameter("hostname")); if (hostname == null) { // hosts is not entered yet return FormValidation.ok(); } FTPSite site = new FTPSite(hostname, request.getParameter("port"), request.getParameter("timeOut"), request.getParameter("user"), request.getParameter("pass")); site.setFtpDir(request.getParameter("ftpDir")); try { site.createSession(); site.closeSession(); return FormValidation.ok(); } catch (Exception e) { return FormValidation.error(e.getMessage()); } } } }