package hudson.plugins.URLSCM;
import hudson.Extension;
import static hudson.Util.fixEmpty;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Hudson;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.scm.ChangeLogParser;
import hudson.scm.NullChangeLogParser;
import hudson.scm.SCM;
import hudson.scm.SCMDescriptor;
import hudson.util.FormValidation;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Date;
import javax.servlet.ServletException;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
public class URLSCM extends hudson.scm.SCM {
private final ArrayList<URLTuple> urls = new ArrayList<URLTuple>();
private final boolean clearWorkspace;
public URLSCM(String[] u, boolean clear) {
for(int i = 0; i < u.length; i++) {
urls.add(new URLTuple(u[i]));
}
this.clearWorkspace = clear;
}
public URLTuple[] getUrls() {
return urls.toArray(new URLTuple[urls.size()]);
}
public boolean isClearWorkspace() {
return clearWorkspace;
}
@Override
public boolean checkout(AbstractBuild build, Launcher launcher,
FilePath workspace, BuildListener listener, File changelogFile)
throws IOException, InterruptedException {
if(clearWorkspace) {
workspace.deleteContents();
}
URLDateAction dates = new URLDateAction(build);
for(URLTuple tuple : urls) {
String urlString = tuple.getUrl();
InputStream is = null;
OutputStream os = null;
try {
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
conn.setUseCaches(false);
dates.setLastModified(urlString, conn.getLastModified());
is = conn.getInputStream();
String path = new File(url.getPath()).getName();
listener.getLogger().append("Copying " + urlString + " to " + path + "\n");
os = workspace.child(path).write();
byte[] buf = new byte[8192];
int i = 0;
while ((i = is.read(buf)) != -1) {
os.write(buf, 0, i);
}
}
catch (Exception e) {
listener.error("Unable to copy " + urlString + "\n" + e.getMessage());
return false;
}
finally {
if (is != null) is.close();
if (os != null) os.close();
}
this.createEmptyChangeLog(changelogFile, listener, "log");
}
build.addAction(dates);
return true;
}
@Override
public ChangeLogParser createChangeLogParser() {
return new NullChangeLogParser();
}
@Override
public boolean requiresWorkspaceForPolling() {
// this plugin does the polling work via the data in the Run
// the data in the workspace is not used
return false;
}
@Override
public boolean pollChanges(AbstractProject project, Launcher launcher,
FilePath workspace, TaskListener listener) throws IOException,
InterruptedException {
boolean change = false;
Run lastBuild = project.getLastBuild();
if(lastBuild == null) return true;
URLDateAction dates = lastBuild.getAction(URLDateAction.class);
if(dates == null) return true;
for(URLTuple tuple : urls) {
String urlString = tuple.getUrl();
try {
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
conn.setUseCaches(false);
long lastMod = conn.getLastModified();
long lastBuildMod = dates.getLastModified(urlString);
if(lastBuildMod != lastMod) {
listener.getLogger().println(
"Found change: " + urlString + " modified " + new Date(lastMod) +
" previous modification was " + new Date(lastBuildMod));
change = true;
}
}
catch (Exception e) {
listener.error("Unable to check " + urlString + "\n" + e.getMessage());
}
}
return change;
}
public static final class URLTuple {
private String urlString;
public URLTuple(String s) {
urlString = s;
}
public String getUrl() {
return urlString;
}
}
@Extension
public static final class DescriptorImpl extends SCMDescriptor<URLSCM> {
public DescriptorImpl() {
super(URLSCM.class, null);
load();
}
public String getDisplayName() {
return "URL Copy";
}
@Override
public SCM newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return new URLSCM(req.getParameterValues("URL.url"), req.getParameter("URL.clear") != null);
}
@Override
public boolean configure(StaplerRequest req, JSONObject formData) throws FormException {
return true;
}
public FormValidation doUrlCheck(@QueryParameter final String value)
throws IOException, ServletException {
if (!Hudson.getInstance().hasPermission(Hudson.ADMINISTER)) return FormValidation.ok();
return new FormValidation.URLCheck() {
@Override
protected FormValidation check() throws IOException, ServletException {
String url = fixEmpty(value);
URL u = null;
try {
u = new URL(url);
open(u);
} catch (Exception e) {
return FormValidation.error("Cannot open " + url);
}
String path = new File(u.getPath()).getName();
if(path.length() == 0) {
return FormValidation.error("URL does not contain filename: " + url);
}
return FormValidation.ok();
}
}.check();
}
}
}