package hudson.plugins.tfs; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.logging.Logger; import hudson.AbortException; import hudson.FilePath; import hudson.Launcher; import hudson.Proc; import hudson.model.TaskListener; import hudson.remoting.Callable; import hudson.util.ForkOutputStream; /** * Class that encapsulates the Team Foundation command client. * * @author Erik Ramfelt */ public class TfTool { static final int SUCCESS_EXIT_CODE = 0; static final int PARTIAL_SUCCESS_EXIT_CODE = 1; private Launcher launcher; private TaskListener listener; private FilePath workspace; private final String executable; private static final Logger LOGGER = Logger.getLogger(TfTool.class.getName()); public TfTool(String executable, Launcher launcher, TaskListener listener, FilePath workspace) { this.executable = executable; this.launcher = launcher; this.listener = listener; this.workspace = workspace; } public TaskListener getListener() { return listener; } /** * Returns the host name of the computer that is running the TF tool * @return the host name; or null if there was a problem looking it up */ public String getHostname() throws IOException, InterruptedException { try { return workspace.act(new Callable<String, UnknownHostException>() { private static final long serialVersionUID = 1L; public String call() throws UnknownHostException { return InetAddress.getLocalHost().getHostName(); } }); } catch (UnknownHostException e) { LOGGER.warning("Could not resolve local hostname needed to list workspaces. " + e); return null; } } /** * Execute the arguments, and return the console output as a Reader * @param arguments arguments to send to the command-line client. * @return a Reader containing the console output */ public Reader execute(String[] arguments) throws IOException, InterruptedException { return execute(arguments, null); } /** * Execute the arguments, and return the console output as a Reader * @param arguments arguments to send to the command-line client. * @param masks which of the commands that should be masked from the console. * @return a Reader containing the console output */ public Reader execute(String[] arguments, boolean[] masks) throws IOException, InterruptedException { String[] toolArguments = new String[arguments.length + 1]; toolArguments[0] = executable; for (int i = 0; i < arguments.length; i++) { toolArguments[i + 1] = arguments[i]; } boolean[] toolMasks = new boolean[arguments.length + 1]; if (masks != null) { toolMasks = new boolean[masks.length + 1]; toolMasks[0] = false; for (int i = 0; i < masks.length; i++) { toolMasks[i + 1] = masks[i]; } } ByteArrayOutputStream consoleStream = new ByteArrayOutputStream(); Proc proc = launcher.launch().cmds(toolArguments).masks(toolMasks) .stdout(new ForkOutputStream(consoleStream, listener.getLogger())) .pwd(workspace).start(); consoleStream.close(); int result = proc.join(); LOGGER.fine(String.format("The TFS command '%s' returned with an error code of %d", toolArguments[1], result)); if ((result == SUCCESS_EXIT_CODE) || (result == PARTIAL_SUCCESS_EXIT_CODE)) { return new InputStreamReader(new ByteArrayInputStream(consoleStream.toByteArray())); } else { listener.fatalError(String.format("Executable returned an unexpected result code [%d]", result)); throw new AbortException(); } } }