package com.redfin.hudson;
import hudson.Extension;
import hudson.Util;
import hudson.FilePath;
import static hudson.Util.*;
import hudson.model.BuildableItem;
import hudson.model.Item;
import hudson.scheduler.CronTabList;
import hudson.triggers.Trigger;
import hudson.triggers.TriggerDescriptor;
import hudson.util.FormValidation;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.apache.commons.io.FileUtils;
import antlr.ANTLRException;
/** Triggers a build when the data at a particular URL has changed. */
public class UrlChangeTrigger extends Trigger<BuildableItem> {
URL url;
public UrlChangeTrigger(String url) throws MalformedURLException {
this(new URL(url));
}
public UrlChangeTrigger(URL url) {
this.url = url;
}
@Override
public void start(BuildableItem project, boolean newInstance) {
super.start(project, newInstance);
try {
this.tabs = CronTabList.create("* * * * *");
} catch (ANTLRException e) {
throw new RuntimeException("Bug! couldn't schedule poll");
}
}
private static final Logger LOGGER =
Logger.getLogger(UrlChangeTrigger.class.getName());
private File getFingerprintFile() {
return new File(job.getRootDir(), "url-change-trigger-oldmd5");
}
@Override
public void run() {
try {
LOGGER.log(Level.FINER, "Testing the file {0}", url);
String currentMd5 = Util.getDigestOf(url.openStream());
String oldMd5;
File file = getFingerprintFile();
if (!file.exists()) {
oldMd5 = "null";
} else {
oldMd5 = new FilePath(file).readToString().trim();
}
if (!currentMd5.equalsIgnoreCase(oldMd5)) {
LOGGER.log(Level.FINE,
"Differences found in the file {0}. >{1}< != >{2}<",
new Object[]{
url, oldMd5, currentMd5,
});
FileUtils.writeStringToFile(file, currentMd5);
job.scheduleBuild(new UrlChangeCause(url));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public URL getUrl() {
return url;
}
@Extension
public static final class DescriptorImpl extends TriggerDescriptor {
public DescriptorImpl() {
super(UrlChangeTrigger.class);
}
@Override
public boolean isApplicable(Item item) {
return true;
}
@Override
public String getDisplayName() {
return "Build when a URL's content changes";
}
@Override
public String getHelpFile() {
return "/plugin/url-change-trigger/help-whatIsUrlChangeTrigger.html";
}
/**
* Performs syntax check.
*/
public FormValidation doCheck(@QueryParameter("urlChangeTrigger.url") String url) {
try {
new URL(fixNull(url));
return FormValidation.ok();
} catch (MalformedURLException e) {
return FormValidation.error(e.getMessage());
}
}
@Override
public UrlChangeTrigger newInstance(StaplerRequest req, JSONObject formData) throws FormException {
String url = formData.getString("url");
try {
return new UrlChangeTrigger(url);
} catch (MalformedURLException e) {
throw new FormException("Invalid URL: " + url, e, "");
}
}
}
}