package com.tombrus.hudson.dostrigger;
import antlr.ANTLRException;
import hudson.EnvVars;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Util;
import hudson.model.BuildableItem;
import hudson.model.Cause;
import hudson.model.Hudson;
import hudson.model.Item;
import hudson.model.TaskListener;
import hudson.model.TopLevelItem;
import hudson.tasks.Messages;
import hudson.triggers.Trigger;
import hudson.triggers.TriggerDescriptor;
import hudson.util.LogTaskListener;
import org.kohsuke.stapler.DataBoundConstructor;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DosTrigger extends Trigger<BuildableItem> {
private static final Logger LOGGER = Logger.getLogger(DosTrigger.class.getName());
private final String script;
private static final String MARKER = "#:#:#";
private static final String CAUSE_VAR = "CAUSE";
private static final String CRLF = "\r\n";
@DataBoundConstructor
public DosTrigger(String schedule, String script) throws ANTLRException {
super(schedule);
this.script = script;
}
@SuppressWarnings({"UnusedDeclaration"})
public String getScript() {
return script;
}
@SuppressWarnings({"UnusedDeclaration"})
public String getSchedule() {
return spec;
}
public void run() {
if (!Hudson.getInstance().isQuietingDown()) {
try {
String output = runScript();
String cause = output == null ? "" : getVar(CAUSE_VAR, output);
if (cause.length()>0) {
job.scheduleBuild(0, new MyCause(cause));
}
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Problem while executing DosTrigger.run()", e);
}
}
}
private String getVar(final String var, final String output) {
Matcher matcher = Pattern.compile("(?s).*"+MARKER + var +MARKER + "([^\n\r]*)"+MARKER+".*").matcher(output);
String description = null;
if (matcher.matches()) {
description = matcher.group(1).trim();
}
if (description == null || description.length() == 0) {
description = "";
}
return description;
}
@Extension
public static final class DescriptorImpl extends TriggerDescriptor {
public String getDisplayName() {
return "Poll with a Windows Batch Command";
}
public boolean isApplicable(Item item) {
return item instanceof TopLevelItem;
}
}
private String runScript() throws InterruptedException {
final TaskListener listener = new LogTaskListener(LOGGER, Level.INFO);
try {
final FilePath ws = Hudson.getInstance().getWorkspaceFor((TopLevelItem) job);
final FilePath batchFile = ws.createTextTempFile("hudson", ".bat", makeScript(), false);
final FilePath logFile = ws.child("dos-trigger.log");
final LogStream logStream = new LogStream(logFile);
try {
final Launcher launcher = Hudson.getInstance().createLauncher(listener);
final String[] cmd = new String[]{"cmd", "/c", "call", batchFile.getRemote()};
final EnvVars envVars = new EnvVars(EnvVars.masterEnvVars);
launcher.launch().cmds(cmd).envs(envVars).stdout(logStream).pwd(ws).join();
return logStream.toString();
} catch (IOException e) {
Util.displayIOException(e, listener);
e.printStackTrace(listener.fatalError(Messages.CommandInterpreter_CommandFailed()));
return null;
} finally {
try {
batchFile.delete();
} catch (IOException e) {
Util.displayIOException(e, listener);
e.printStackTrace(listener.fatalError(Messages.CommandInterpreter_UnableToDelete(batchFile)));
}
logStream.close();
}
} catch (IOException e) {
Util.displayIOException(e, listener);
e.printStackTrace(listener.fatalError(Messages.CommandInterpreter_UnableToProduceScript()));
return null;
}
}
private String makeScript() {
return ""
+ "@set "+ CAUSE_VAR +"=" +CRLF
+ "@echo off" + CRLF
+ "call :TheActualScript" + CRLF
+ "@echo off" + CRLF
+ "echo " + MARKER + CAUSE_VAR + MARKER + "%" + CAUSE_VAR + "%" + MARKER + CRLF
+ "goto :EOF" + CRLF
+ ":TheActualScript" + CRLF
+ script + CRLF;
}
private static class MyCause extends Cause {
private final String description;
public MyCause(String description) {
this.description = description;
}
public String getShortDescription() {
return description;
}
}
private static class LogStream extends OutputStream {
private final StringBuilder log = new StringBuilder();
private final OutputStream logStream;
public LogStream(FilePath logFile) throws IOException, InterruptedException {
logStream = logFile.write();
}
public void write(int b) throws IOException {
log.append((char) b);
logStream.write(b);
}
public void close() throws IOException {
super.close();
logStream.close();
}
public String toString() {
return log.toString();
}
}
}