package hudson.plugins.perforce;
import java.io.*;
import java.util.Map;
import java.util.Set;
import com.tek42.perforce.PerforceException;
import com.tek42.perforce.process.Executor;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Proc;
import hudson.model.Hudson;
import hudson.util.StreamTaskListener;
/**
* Implementation of the P4Java Executor interface that provides support for
* remotely executing Perforce commands.
* <p/>
* User contract: Use this class only once to execute a command. ,to execute
* another command, spawn another Exector using the Exector Factory
*
* @author Victor Szoltysek
*/
public class HudsonP4Executor implements Executor {
private BufferedReader reader;
private BufferedWriter writer;
private Launcher hudsonLauncher;
private String[] env;
private FilePath filePath;
/**
* Constructor that takes Hudson specific details for launching the
* Perforce commands.
*
* @param hudsonLauncher
* @param envMap
* @param filePath
*/
HudsonP4Executor(Launcher hudsonLauncher, Map<String, String> envMap, FilePath filePath) {
this.hudsonLauncher = hudsonLauncher;
this.env = convertEnvMaptoArray(envMap);
this.filePath = filePath;
}
public void close() {
// Need to close writer
// (reader gets closed in HudsonPipedOutputStream)
try {
writer.close();
} catch(IOException e) {
// Do nothing
}
}
public void exec(String[] cmd) throws PerforceException {
try {
// ensure we actually have a valid hudson launcher
if (null == hudsonLauncher) {
hudsonLauncher = Hudson.getInstance().createLauncher(new StreamTaskListener(System.out));
}
// hudsonOut->p4in->reader
HudsonPipedOutputStream hudsonOut = new HudsonPipedOutputStream();
PipedInputStream p4in = new PipedInputStream(hudsonOut);
reader = new BufferedReader(new InputStreamReader(p4in));
// hudsonIn<-p4Out<-writer
PipedInputStream hudsonIn = new PipedInputStream();
PipedOutputStream p4out = new PipedOutputStream(hudsonIn);
writer = new BufferedWriter(new OutputStreamWriter(p4out));
Proc process = hudsonLauncher.launch().cmds(cmd).envs(env).stdin(hudsonIn).stdout(hudsonOut).pwd(filePath).start();
// Required to close hudsonOut stream
hudsonOut.closeOnProcess(process);
} catch(IOException e) {
//try to close all the pipes before throwing an exception
closeBuffers();
throw new PerforceException("Could not run perforce command.", e);
}
}
/**
* Function for converting map of environment variables to a String
* array as hudson does not provide a launcher method that takes
* <p/>
* (1) Environment Map (2) InputStream (3) OutputStream
* <p> .. at the same time
*
* @param envMap
*
* @return
*/
private String[] convertEnvMaptoArray(Map<String, String> envMap) {
Set<String> keySet = envMap.keySet();
String[] keys = keySet.toArray(new String[0]);
String[] result = new String[keys.length];
for (int i = 0; i < keys.length; i++)
result[i] = keys[i] + "=" + envMap.get(keys[i]);
return result;
}
public BufferedReader getReader() {
return reader;
}
public BufferedWriter getWriter() {
return writer;
}
private void closeBuffers(){
try {
reader.close();
} catch(IOException ignoredException) {};
try {
writer.close();
} catch(IOException ignoredException) {};
}
}