diff --git a/core/src/main/java/hudson/Launcher.java b/core/src/main/java/hudson/Launcher.java index 3b3f6321dafbdc26a0822ba889d5f23c05092b15..c29dc3827ad165914a2fe7f9f21994ed04fd489b 100644 --- a/core/src/main/java/hudson/Launcher.java +++ b/core/src/main/java/hudson/Launcher.java @@ -37,6 +37,7 @@ import hudson.remoting.RemoteOutputStream; import hudson.remoting.VirtualChannel; import hudson.util.ProcessTreeKiller; import hudson.util.StreamCopyThread; +import hudson.util.ArgumentListBuilder; import java.io.BufferedOutputStream; import java.io.File; @@ -46,6 +47,7 @@ import java.io.OutputStream; import java.util.Arrays; import java.util.Map; import java.util.List; +import java.util.ArrayList; /** * Starts a process. @@ -127,14 +129,152 @@ public abstract class Launcher { return null; } + /** + * Builder pattern for configuring a process to launch. + * @since 1.311 + */ + public final class ProcStarter { + protected List commands; + protected boolean[] masks; + protected FilePath pwd; + protected OutputStream stdout,stderr; + protected InputStream stdin; + protected String[] envs; + + public ProcStarter cmds(String... args) { + return cmds(Arrays.asList(args)); + } + + public ProcStarter cmds(File program, String... args) { + commands = new ArrayList(args.length+1); + commands.add(program.getPath()); + commands.addAll(Arrays.asList(args)); + return this; + } + + public ProcStarter cmds(List args) { + commands = new ArrayList(args); + return this; + } + + public ProcStarter cmds(ArgumentListBuilder args) { + commands = args.toList(); + masks = args.toMaskArray(); + return this; + } + + public ProcStarter masks(boolean... masks) { + this.masks = masks; + return this; + } + + public ProcStarter pwd(FilePath workDir) { + this.pwd = workDir; + return this; + } + + public ProcStarter pwd(File workDir) { + return pwd(new FilePath(workDir)); + } + + public ProcStarter pwd(String workDir) { + return pwd(new File(workDir)); + } + + public ProcStarter stdout(OutputStream out) { + this.stdout = out; + return this; + } + + /** + * Sends the stdout to the given {@link TaskListener}. + */ + public ProcStarter stdout(TaskListener out) { + return stdout(out.getLogger()); + } + + /** + * Controls where the stderr of the process goes. + * By default, it's bundled into stdout. + */ + public ProcStarter stderr(OutputStream err) { + this.stderr = err; + return this; + } + + /** + * Controls where the stdin of the process comes from. + * By default, /dev/null. + */ + public ProcStarter stdin(InputStream in) { + this.stdin = in; + return this; + } + + /** + * Sets the environment variable overrides. + * + *

+ * In adition to what the current process + * is inherited (if this is going to be launched from a slave agent, that + * becomes the "current" process), these variables will be also set. + */ + public ProcStarter envs(Map overrides) { + return envs(Util.mapToEnv(overrides)); + } + + /** + * @param overrides + * List of "VAR=VALUE". See {@link #envs(Map)} for the semantics. + */ + public ProcStarter envs(String... overrides) { + this.envs = overrides; + return this; + } + + /** + * Starts the new process as configured. + */ + public Proc start() throws IOException { + return launch(this); + } + + /** + * Starts the process and waits for its completion. + */ + public int join() throws IOException, InterruptedException { + return start().join(); + } + } + + /** + * Launches a process by using a {@linkplain ProcStarter builder-pattern} to configure + * the parameters. + */ + public final ProcStarter launch() { + return new ProcStarter(); + } + + /** + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern + */ public final Proc launch(String cmd, Map env, OutputStream out, FilePath workDir) throws IOException { return launch(cmd,Util.mapToEnv(env),out,workDir); } + /** + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern + */ public final Proc launch(String[] cmd, Map env, OutputStream out, FilePath workDir) throws IOException { return launch(cmd, Util.mapToEnv(env), out, workDir); } + /** + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern + */ public final Proc launch(String[] cmd, Map env, InputStream in, OutputStream out) throws IOException { return launch(cmd, Util.mapToEnv(env), in, out); } @@ -152,6 +292,9 @@ public abstract class Launcher { * @param workDir null if the working directory could be anything. * @return The process of the command. * @throws IOException When there are IO problems. + * + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern */ public final Proc launch(String[] cmd, boolean[] mask, Map env, OutputStream out, FilePath workDir) throws IOException { return launch(cmd, mask, Util.mapToEnv(env), out, workDir); @@ -170,19 +313,34 @@ public abstract class Launcher { * @param out stdout and stderr of the process will be sent to this stream. the stream won't be closed. * @return The process of the command. * @throws IOException When there are IO problems. + * + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern */ public final Proc launch(String[] cmd, boolean[] mask, Map env, InputStream in, OutputStream out) throws IOException { return launch(cmd, mask, Util.mapToEnv(env), in, out); } + /** + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern + */ public final Proc launch(String cmd,String[] env,OutputStream out, FilePath workDir) throws IOException { return launch(Util.tokenize(cmd),env,out,workDir); } + /** + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern + */ public final Proc launch(String[] cmd, String[] env, OutputStream out, FilePath workDir) throws IOException { return launch(cmd, env, null, out, workDir); } + /** + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern + */ public final Proc launch(String[] cmd, String[] env, InputStream in, OutputStream out) throws IOException { return launch(cmd, env, in, out, null); } @@ -200,6 +358,9 @@ public abstract class Launcher { * @param workDir null if the working directory could be anything. * @return The process of the command. * @throws IOException When there are IO problems. + * + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern */ public final Proc launch(String[] cmd, boolean[] mask, String[] env, OutputStream out, FilePath workDir) throws IOException { return launch(cmd, mask, env, null, out, workDir); @@ -218,6 +379,9 @@ public abstract class Launcher { * @param out stdout and stderr of the process will be sent to this stream. the stream won't be closed. * @return The process of the command. * @throws IOException When there are IO problems. + * + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern */ public final Proc launch(String[] cmd, boolean[] mask, String[] env, InputStream in, OutputStream out) throws IOException { return launch(cmd, mask, env, in, out, null); @@ -233,8 +397,13 @@ public abstract class Launcher { * @param out * stdout and stderr of the process will be sent to this stream. * the stream won't be closed. + * + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern */ - public abstract Proc launch(String[] cmd,String[] env,InputStream in,OutputStream out, FilePath workDir) throws IOException; + public Proc launch(String[] cmd, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { + return launch(launch().cmds(cmd).envs(env).stdin(in).stdout(out).pwd(workDir)); + } /** * Launch a command with optional censoring of arguments from the listener (Note: The censored portions will @@ -250,8 +419,18 @@ public abstract class Launcher { * @param workDir null if the working directory could be anything. * @return The process of the command. * @throws IOException When there are IO problems. + * + * @deprecated as of 1.311 + * Use {@link #launch()} and its associated builder pattern */ - public abstract Proc launch(String[] cmd, boolean[] mask, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException; + public Proc launch(String[] cmd, boolean[] mask, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { + return launch(launch().cmds(cmd).masks(mask).envs(env).stdin(in).stdout(out).pwd(workDir)); + } + + /** + * Invoked from {@link ProcStarter#start()} + */ + protected abstract Proc launch(ProcStarter starter) throws IOException; /** * Launches a specified process and connects its input/output to a {@link Channel}, then @@ -288,7 +467,7 @@ public abstract class Launcher { * Prints out the command line to the listener so that users know what we are doing. */ protected final void printCommandLine(String[] cmd, FilePath workDir) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); if (workDir != null) { buf.append('['); if(showFullPath) @@ -320,18 +499,21 @@ public abstract class Launcher { * remain unmasked (false). * @param workDir The work dir. */ - protected final void maskedPrintCommandLine(final String[] cmd, final boolean[] mask, final FilePath workDir) { - assert mask.length == cmd.length; - final String[] masked = new String[cmd.length]; - for (int i = 0; i < cmd.length; i++) { + protected final void maskedPrintCommandLine(List cmd, boolean[] mask, FilePath workDir) { + assert mask.length == cmd.size(); + final String[] masked = new String[cmd.size()]; + for (int i = 0; i < cmd.size(); i++) { if (mask[i]) { masked[i] = "********"; } else { - masked[i] = cmd[i]; + masked[i] = cmd.get(i); } } printCommandLine(masked, workDir); } + protected final void maskedPrintCommandLine(String[] cmd, boolean[] mask, FilePath workDir) { + maskedPrintCommandLine(Arrays.asList(cmd),mask,workDir); + } /** * Returns a decorated {@link Launcher} for the given node. @@ -353,13 +535,10 @@ public abstract class Launcher { final Launcher outer = this; return new Launcher(outer) { @Override - public Proc launch(String[] cmd, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { - return outer.launch(prefix(cmd),env,in,out,workDir); - } - - @Override - public Proc launch(String[] cmd, boolean[] mask, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { - return outer.launch(prefix(cmd),prefix(mask),env,in,out,workDir); + protected Proc launch(ProcStarter starter) throws IOException { + starter.commands.addAll(0,Arrays.asList(prefix)); + starter.masks = prefix(starter.masks); + return outer.launch(starter); } @Override @@ -399,26 +578,18 @@ public abstract class Launcher { super(listener, channel); } - public Proc launch(String[] cmd, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { - printCommandLine(cmd, workDir); - return createLocalProc(cmd, env, in, out, workDir); - } - - public Proc launch(String[] cmd, boolean[] mask, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { - maskedPrintCommandLine(cmd, mask, workDir); - return createLocalProc(cmd, env, in, out, workDir); - } + @Override + protected Proc launch(ProcStarter ps) throws IOException { + maskedPrintCommandLine(ps.commands, ps.masks, ps.pwd); - private Proc createLocalProc(String[] cmd, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { - EnvVars jobEnv = inherit(env); + EnvVars jobEnv = inherit(ps.envs); // replace variables in command line - String[] jobCmd = new String[cmd.length]; - for ( int idx = 0 ; idx < jobCmd.length; idx++ ) { - jobCmd[idx] = jobEnv.expand(cmd[idx]); - } + String[] jobCmd = new String[ps.commands.size()]; + for ( int idx = 0 ; idx < jobCmd.length; idx++ ) + jobCmd[idx] = jobEnv.expand(ps.commands.get(idx)); - return new LocalProc(jobCmd, Util.mapToEnv(jobEnv), in, out, toFile(workDir)); + return new LocalProc(jobCmd, Util.mapToEnv(jobEnv), ps.stdin, ps.stdout, ps.stderr, toFile(ps.pwd)); } private File toFile(FilePath f) { @@ -488,22 +659,13 @@ public abstract class Launcher { this.isUnix = isUnix; } - public Proc launch(final String[] cmd, final String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { - printCommandLine(cmd, workDir); - return createRemoteProc(cmd, env, in, out, workDir); - } - - public Proc launch(String[] cmd, boolean[] mask, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { - maskedPrintCommandLine(cmd, mask, workDir); - return createRemoteProc(cmd, env, in, out, workDir); - } - - private Proc createRemoteProc(String[] cmd, String[] env, InputStream _in, OutputStream _out, FilePath _workDir) throws IOException { - final OutputStream out = new RemoteOutputStream(new CloseProofOutputStream(_out)); - final InputStream in = _in==null ? null : new RemoteInputStream(_in); - final String workDir = _workDir==null ? null : _workDir.getRemote(); + protected Proc launch(ProcStarter ps) throws IOException { + final OutputStream out = new RemoteOutputStream(new CloseProofOutputStream(ps.stdout)); + final OutputStream err = ps.stderr==null ? null : new RemoteOutputStream(new CloseProofOutputStream(ps.stderr)); + final InputStream in = ps.stdin==null ? null : new RemoteInputStream(ps.stdin); + final String workDir = ps.pwd==null ? null : ps.pwd.getRemote(); - return new RemoteProc(getChannel().callAsync(new RemoteLaunchCallable(cmd, env, in, out, workDir))); + return new RemoteProc(getChannel().callAsync(new RemoteLaunchCallable(ps.commands, ps.envs, in, out, err, workDir))); } public Channel launchChannel(String[] cmd, OutputStream err, FilePath _workDir, Map envOverrides) throws IOException, InterruptedException { @@ -545,23 +707,28 @@ public abstract class Launcher { } private static class RemoteLaunchCallable implements Callable { - private final String[] cmd; + private final List cmd; private final String[] env; private final InputStream in; private final OutputStream out; + private final OutputStream err; private final String workDir; - public RemoteLaunchCallable(String[] cmd, String[] env, InputStream in, OutputStream out, String workDir) { - this.cmd = cmd; + RemoteLaunchCallable(List cmd, String[] env, InputStream in, OutputStream out, OutputStream err, String workDir) { + this.cmd = new ArrayList(cmd); this.env = env; this.in = in; this.out = out; + this.err = err; this.workDir = workDir; } public Integer call() throws IOException { - Proc p = new LocalLauncher(TaskListener.NULL).launch(cmd, env, in, out, - workDir ==null ? null : new FilePath(new File(workDir))); + Launcher.ProcStarter ps = new LocalLauncher(TaskListener.NULL).launch(); + ps.cmds(cmd).envs(env).stdin(in).stdout(out).stderr(err); + if(workDir!=null) ps.pwd(workDir); + + Proc p = ps.start(); try { return p.join(); } catch (InterruptedException e) { diff --git a/core/src/main/java/hudson/Proc.java b/core/src/main/java/hudson/Proc.java index de954985d508be24a1fbe48ddb66deee180dd1dc..c265d5364ea3d71f780239802ffdcb1acfa62474 100644 --- a/core/src/main/java/hudson/Proc.java +++ b/core/src/main/java/hudson/Proc.java @@ -82,7 +82,7 @@ public abstract class Proc { */ public static final class LocalProc extends Proc { private final Process proc; - private final Thread copier; + private final Thread copier,copier2; private final OutputStream out; private final EnvVars cookie; @@ -107,9 +107,22 @@ public abstract class Proc { } public LocalProc(String[] cmd,String[] env,InputStream in,OutputStream out, File workDir) throws IOException { + this(cmd,env,in,out,null,workDir); + } + + /** + * @param err + * null to redirect stderr to stdout. + */ + public LocalProc(String[] cmd,String[] env,InputStream in,OutputStream out,OutputStream err,File workDir) throws IOException { this( calcName(cmd), - environment(new ProcessBuilder(cmd),env).directory(workDir).redirectErrorStream(true), - in, out ); + stderr(environment(new ProcessBuilder(cmd),env).directory(workDir),err), + in, out, err ); + } + + private static ProcessBuilder stderr(ProcessBuilder pb, OutputStream stderr) { + if(stderr==null) pb.redirectErrorStream(true); + return pb; } private static ProcessBuilder environment(ProcessBuilder pb, String[] env) { @@ -124,7 +137,7 @@ public abstract class Proc { return pb; } - private LocalProc( String name, ProcessBuilder procBuilder, InputStream in, OutputStream out ) throws IOException { + private LocalProc( String name, ProcessBuilder procBuilder, InputStream in, OutputStream out, OutputStream err ) throws IOException { Logger.getLogger(Proc.class.getName()).log(Level.FINE, "Running: {0}", name); this.out = out; this.cookie = ProcessTreeKiller.createCookie(); @@ -136,6 +149,12 @@ public abstract class Proc { new StdinCopyThread(name+": stdin copier",in,proc.getOutputStream()).start(); else proc.getOutputStream().close(); + if(err!=null) { + copier2 = new StreamCopyThread(name+": stderr copier", proc.getErrorStream(), err); + copier2.start(); + } else { + copier2 = null; + } } /** @@ -149,7 +168,8 @@ public abstract class Proc { // problems like that shows up as inifinite wait in join(), which confuses great many users. // So let's do a timed wait here and try to diagnose the problem copier.join(10*1000); - if(copier.isAlive()) { + copier2.join(10*1000); + if(copier.isAlive() || copier2.isAlive()) { // looks like handles are leaking. // closing these handles should terminate the threads. String msg = "Process leaked file descriptors. See http://hudson.gotdns.com/wiki/display/HUDSON/Spawning+processes+from+build for more information"; diff --git a/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java b/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java index 47f9edb5d5c30b5fc364007a5e972873837bb98a..7e303c46802dcc5b58abd6a94a2a95c64e7235db 100644 --- a/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java +++ b/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java @@ -127,7 +127,9 @@ public class WindowsInstallerLink extends ManagementLink { ByteArrayOutputStream baos = new ByteArrayOutputStream(); StreamTaskListener task = new StreamTaskListener(baos); task.getLogger().println("Installing a service"); - int r = new LocalLauncher(task).launch(new String[]{new File(dir, "hudson.exe").getPath(), "install"}, new String[0], task.getLogger(), new FilePath(dir)).join(); + int r = new LocalLauncher(task).launch() + .cmds(new File(dir, "hudson.exe").getPath(), "install") + .stdout(task.getLogger()).pwd(dir).join(); if(r!=0) { sendError(baos.toString(),req,rsp); return; @@ -195,7 +197,8 @@ public class WindowsInstallerLink extends ManagementLink { } LOGGER.info("Starting a Windows service"); StreamTaskListener task = new StreamTaskListener(System.out); - int r = new LocalLauncher(task).launch(new String[]{new File(installationDir, "hudson.exe").getPath(), "start"}, new String[0], task.getLogger(), new FilePath(installationDir)).join(); + int r = new LocalLauncher(task).launch().cmds(new File(installationDir, "hudson.exe"), "start") + .stdout(task).pwd(installationDir).join(); task.getLogger().println(r==0?"Successfully started":"start service failed. Exit code="+r); } catch (IOException e) { e.printStackTrace(); diff --git a/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java b/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java index a97da181a7cc84d08852d69f7fb7aa3bcbd930d7..dfbd7ef68869092416afea276fb285284d201b1a 100644 --- a/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java +++ b/core/src/main/java/hudson/lifecycle/WindowsServiceLifecycle.java @@ -103,7 +103,8 @@ public class WindowsServiceLifecycle extends Lifecycle { ByteArrayOutputStream baos = new ByteArrayOutputStream(); StreamTaskListener task = new StreamTaskListener(baos); task.getLogger().println("Restarting a service"); - int r = new LocalLauncher(task).launch(new String[]{new File(home, "hudson.exe").getPath(), "restart"}, new String[0], task.getLogger(), new FilePath(home)).join(); + int r = new LocalLauncher(task).launch().cmds(new File(home, "hudson.exe"), "restart") + .stdout(task).pwd(home).join(); if(r!=0) throw new IOException(baos.toString()); } diff --git a/core/src/main/java/hudson/lifecycle/WindowsSlaveInstaller.java b/core/src/main/java/hudson/lifecycle/WindowsSlaveInstaller.java index 75c9e8fe3ff966dc32e9259407c03af364407266..d05ab8469d6233b0802f2900fec8cffef37c4415 100644 --- a/core/src/main/java/hudson/lifecycle/WindowsSlaveInstaller.java +++ b/core/src/main/java/hudson/lifecycle/WindowsSlaveInstaller.java @@ -127,7 +127,7 @@ public class WindowsSlaveInstaller implements Callable, A // install as a service ByteArrayOutputStream baos = new ByteArrayOutputStream(); StreamTaskListener task = new StreamTaskListener(baos); - r = new LocalLauncher(task).launch(new String[]{slaveExe.getPath(), "install"}, new String[0], task.getLogger(), new FilePath(dir)).join(); + r = new LocalLauncher(task).launch().cmds(slaveExe, "install").stdout(task).pwd(dir).join(); if(r!=0) { JOptionPane.showMessageDialog( dialog,baos.toString(),"Error", @@ -147,7 +147,7 @@ public class WindowsSlaveInstaller implements Callable, A public void run() { try { StreamTaskListener task = new StreamTaskListener(System.out); - int r = new LocalLauncher(task).launch(new String[]{slaveExe.getPath(), "start"}, new String[0], task.getLogger(), new FilePath(dir)).join(); + int r = new LocalLauncher(task).launch().cmds(slaveExe, "start").stdout(task).pwd(dir).join(); task.getLogger().println(r==0?"Successfully started":"start service failed. Exit code="+r); } catch (IOException e) { e.printStackTrace(); diff --git a/core/src/main/java/hudson/model/JDK.java b/core/src/main/java/hudson/model/JDK.java index 60ac217e2cb76b0f9bec5b975c20cce115a58439..843a072b3e75c6ca338c953d7986303cc45304f5 100644 --- a/core/src/main/java/hudson/model/JDK.java +++ b/core/src/main/java/hudson/model/JDK.java @@ -133,7 +133,7 @@ public final class JDK extends ToolInstallation implements NodeSpecific, En try { TaskListener listener = new StreamTaskListener(new NullStream()); Launcher launcher = n.createLauncher(listener); - return launcher.launch("java -fullversion",new String[0],listener.getLogger(),null).join()==0; + return launcher.launch().cmds("java","-fullversion").stdout(listener).join()==0; } catch (IOException e) { return false; } catch (InterruptedException e) { diff --git a/core/src/main/java/hudson/os/solaris/ZFSInstaller.java b/core/src/main/java/hudson/os/solaris/ZFSInstaller.java index 8f43568282c784ed721d1429331fd4bde81170b0..1691403d51470e513979c0dbfa0343867f107778 100644 --- a/core/src/main/java/hudson/os/solaris/ZFSInstaller.java +++ b/core/src/main/java/hudson/os/solaris/ZFSInstaller.java @@ -25,7 +25,6 @@ package hudson.os.solaris; import com.sun.akuma.Daemon; import com.sun.akuma.JavaVMArguments; -import hudson.FilePath; import hudson.Launcher.LocalLauncher; import hudson.Util; import hudson.Extension; @@ -383,7 +382,7 @@ public class ZFSInstaller extends AdministrativeMonitor implements Serializable } private static int system(File pwd, TaskListener listener, String... args) throws IOException, InterruptedException { - return new LocalLauncher(listener).launch(args, new String[0], System.out, new FilePath(pwd)).join(); + return new LocalLauncher(listener).launch().cmds(args).stdout(System.out).pwd(pwd).join(); } private static String computeHudsonFileSystemName(LibZFS zfs, ZFSFileSystem top) { diff --git a/core/src/main/java/hudson/scm/CVSSCM.java b/core/src/main/java/hudson/scm/CVSSCM.java index 084f616484ffb76857e851b17d74ca04fef79946..4a38af704d6c8cbfe0d31a1557ba4cf38ee87c10 100644 --- a/core/src/main/java/hudson/scm/CVSSCM.java +++ b/core/src/main/java/hudson/scm/CVSSCM.java @@ -40,7 +40,6 @@ import hudson.model.ModelObject; import hudson.model.Run; import hudson.model.TaskListener; import hudson.model.TaskThread; -import hudson.model.Item; import hudson.org.apache.tools.ant.taskdefs.cvslib.ChangeLogTask; import hudson.remoting.Future; import hudson.remoting.RemoteOutputStream; @@ -60,7 +59,6 @@ import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; -import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.framework.io.ByteBuffer; import javax.servlet.ServletException; @@ -950,7 +948,7 @@ public class CVSSCM extends SCM implements Serializable { protected final boolean run(Launcher launcher, ArgumentListBuilder cmd, TaskListener listener, FilePath dir, OutputStream out) throws IOException, InterruptedException { Map env = createEnvVarMap(true); - int r = launcher.launch(cmd.toCommandArray(),env,out,dir).join(); + int r = launcher.launch().cmds(cmd).envs(env).stdout(out).pwd(dir).join(); if(r!=0) listener.fatalError(getDescriptor().getDisplayName()+" failed. exit code="+r); @@ -1153,9 +1151,8 @@ public class CVSSCM extends SCM implements Serializable { public void doVersion(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException { ByteBuffer baos = new ByteBuffer(); try { - Proc proc = Hudson.getInstance().createLauncher(TaskListener.NULL).launch( - new String[]{getCvsExeOrDefault(), "--version"}, new String[0], baos, null); - proc.join(); + Hudson.getInstance().createLauncher(TaskListener.NULL).launch() + .cmds(getCvsExeOrDefault(), "--version").stdout(baos).join(); rsp.setContentType("text/plain"); baos.writeTo(rsp.getOutputStream()); } catch (IOException e) { @@ -1285,10 +1282,10 @@ public class CVSSCM extends SCM implements Serializable { } rsp.setContentType("text/plain"); - Proc proc = Hudson.getInstance().createLauncher(TaskListener.NULL).launch( - new String[]{getCvsExeOrDefault(), "-d",cvsroot,"login"}, new String[0], - new ByteArrayInputStream((password+"\n").getBytes()), - rsp.getOutputStream()); + Proc proc = Hudson.getInstance().createLauncher(TaskListener.NULL).launch() + .cmds(getCvsExeOrDefault(), "-d",cvsroot,"login") + .stdin(new ByteArrayInputStream((password+"\n").getBytes())) + .stdout(rsp.getOutputStream()).start(); proc.join(); } } diff --git a/core/src/main/java/hudson/slaves/Channels.java b/core/src/main/java/hudson/slaves/Channels.java index 7025e8e170ff1ff86cbdc47361065570c312406b..67f0f33cb03443f368f3aff38f0861d1dac0f53b 100644 --- a/core/src/main/java/hudson/slaves/Channels.java +++ b/core/src/main/java/hudson/slaves/Channels.java @@ -167,13 +167,13 @@ public class Channels { args.add("-connectTo","localhost:"+serverSocket.getLocalPort()); listener.getLogger().println("Starting "+displayName); - Proc p = new LocalLauncher(listener).launch(args.toCommandArray(), new String[0], listener.getLogger(), workDir); + Proc p = new LocalLauncher(listener).launch().cmds(args).stdout(listener).pwd(workDir).start(); Socket s = serverSocket.accept(); serverSocket.close(); return forProcess("Channel to "+displayName, Computer.threadPoolForRemoting, - new BufferedInputStream(s.getInputStream()), new BufferedOutputStream(s.getOutputStream()), p); + new BufferedInputStream(s.getInputStream()), new BufferedOutputStream(s.getOutputStream()),null,p); } private static final Logger LOGGER = Logger.getLogger(Channels.class.getName()); diff --git a/core/src/main/java/hudson/tasks/Ant.java b/core/src/main/java/hudson/tasks/Ant.java index 465beaf8cac79f79001567176012dfb2d7b3d304..0a3a69cd41e1d9c4c85355caa82f9fa1877e0113 100644 --- a/core/src/main/java/hudson/tasks/Ant.java +++ b/core/src/main/java/hudson/tasks/Ant.java @@ -206,7 +206,7 @@ public class Ant extends Builder { long startTime = System.currentTimeMillis(); try { - int r = launcher.launch(args.toCommandArray(),env,listener.getLogger(),buildFilePath.getParent()).join(); + int r = launcher.launch().cmds(args).envs(env).stdout(listener).pwd(buildFilePath.getParent()).join(); return r==0; } catch (IOException e) { Util.displayIOException(e,listener); diff --git a/core/src/main/java/hudson/tasks/CommandInterpreter.java b/core/src/main/java/hudson/tasks/CommandInterpreter.java index e522690889bc1edd3905fb3d39762315c7b08736..cbb800bd190c805f96c2a6dc9b8d69ecc098c1be 100644 --- a/core/src/main/java/hudson/tasks/CommandInterpreter.java +++ b/core/src/main/java/hudson/tasks/CommandInterpreter.java @@ -81,7 +81,7 @@ public abstract class CommandInterpreter extends Builder { // convert variables to all upper cases. for(Map.Entry e : build.getBuildVariables().entrySet()) envVars.put(e.getKey(),e.getValue()); - r = launcher.launch(cmd,envVars,listener.getLogger(),ws).join(); + r = launcher.launch().cmds(cmd).envs(envVars).stdout(listener).pwd(ws).join(); } catch (IOException e) { Util.displayIOException(e,listener); e.printStackTrace(listener.fatalError(Messages.CommandInterpreter_CommandFailed())); diff --git a/core/src/main/java/hudson/tasks/Maven.java b/core/src/main/java/hudson/tasks/Maven.java index 9b3a2742673e311c2855f848a73e57bf6f7fb139..c3c21aa47df004d1c063e264d7b90290843f8c40 100644 --- a/core/src/main/java/hudson/tasks/Maven.java +++ b/core/src/main/java/hudson/tasks/Maven.java @@ -244,7 +244,7 @@ public class Maven extends Builder { env.put("MAVEN_OPTS",jvmOptions); try { - int r = launcher.launch(args.toCommandArray(),env,listener.getLogger(),proj.getModuleRoot()).join(); + int r = launcher.launch().cmds(args).envs(env).stdout(listener).pwd(proj.getModuleRoot()).join(); if (0 != r) { return false; } diff --git a/core/src/main/java/hudson/tools/CommandInstaller.java b/core/src/main/java/hudson/tools/CommandInstaller.java index e78a7c60169a974e516c97647005a5ad206498bb..da03be4316f8dc34124a1f45081ae46a89d5ac44 100644 --- a/core/src/main/java/hudson/tools/CommandInstaller.java +++ b/core/src/main/java/hudson/tools/CommandInstaller.java @@ -72,7 +72,7 @@ public class CommandInstaller extends ToolInstaller { FilePath script = dir.createTextTempFile("hudson", ".sh", command); try { String[] cmd = {"sh", "-e", script.getRemote()}; - int r = node.createLauncher(log).launch(cmd, Collections.emptyMap(), log.getLogger(), dir).join(); + int r = node.createLauncher(log).launch().cmds(cmd).stdout(log).pwd(dir).join(); if (r != 0) { throw new IOException("Command returned status " + r); } diff --git a/core/src/main/java/hudson/tools/JDKInstaller.java b/core/src/main/java/hudson/tools/JDKInstaller.java index d556ec8545901f0e66f9d590a593e4aa47ce4c94..12eebbdfc60dfd8649fa0038bdbdf1a9efeae7c9 100644 --- a/core/src/main/java/hudson/tools/JDKInstaller.java +++ b/core/src/main/java/hudson/tools/JDKInstaller.java @@ -122,7 +122,8 @@ public class JDKInstaller extends ToolInstaller { case LINUX: case SOLARIS: file.chmod(0755); - if(node.createLauncher(log).launch(new String[]{file.getRemote(),"-noregister"},new String[0],new ByteArrayInputStream("yes".getBytes()),out,expectedLocation).join()!=0) + if(node.createLauncher(log).launch().cmds(file.getRemote(),"-noregister") + .stdin(new ByteArrayInputStream("yes".getBytes())).stdout(out).pwd(expectedLocation).join()!=0) throw new AbortException("Failed to install JDK"); // JDK creates its own sub-directory, so pull them up @@ -166,7 +167,7 @@ public class JDKInstaller extends ToolInstaller { args.add("/s"); args.add("/v/qn REBOOT=Suppress INSTALLDIR="+normalizedPath+" /L "+logFile.getRemote()); - if(node.createLauncher(log).launch(args.toCommandArray(),new String[0],out,expectedLocation).join()!=0) { + if(node.createLauncher(log).launch().cmds(args).stdout(out).pwd(expectedLocation).join()!=0) { out.println("Failed to install JDK"); // log file is in UTF-16 InputStreamReader in = new InputStreamReader(logFile.read(), "UTF-16"); diff --git a/maven-plugin/src/main/java/hudson/maven/MavenProcessFactory.java b/maven-plugin/src/main/java/hudson/maven/MavenProcessFactory.java index ae9a44830400d60ba425c496d0d4f36e28b5d35a..a933d5f54de0c07c31401dca92a6ee00a7a11932 100644 --- a/maven-plugin/src/main/java/hudson/maven/MavenProcessFactory.java +++ b/maven-plugin/src/main/java/hudson/maven/MavenProcessFactory.java @@ -194,7 +194,7 @@ final class MavenProcessFactory implements ProcessCache.Factory { final ArgumentListBuilder cmdLine = buildMavenCmdLine(listener,acceptor.getPort()); String[] cmds = cmdLine.toCommandArray(); - final Proc proc = launcher.launch(cmds, envVars, out, workDir); + final Proc proc = launcher.launch().cmds(cmds).envs(envVars).stdout(out).pwd(workDir).start(); Connection con; try { @@ -209,7 +209,7 @@ final class MavenProcessFactory implements ProcessCache.Factory { } return Channels.forProcess("Channel to Maven "+ Arrays.toString(cmds), - Computer.threadPoolForRemoting, new BufferedInputStream(con.in), new BufferedOutputStream(con.out),proc); + Computer.threadPoolForRemoting, new BufferedInputStream(con.in), new BufferedOutputStream(con.out), listener.getLogger(), proc); // return launcher.launchChannel(buildMavenCmdLine(listener).toCommandArray(), // out, workDir, envVars); diff --git a/test/src/test/java/hudson/slaves/JNLPLauncherTest.java b/test/src/test/java/hudson/slaves/JNLPLauncherTest.java index d49747bf208e62e8998dbd1c6d8ab2be756ceda6..e83478ac935fc605edfa29c00be22887cc9dcc85 100644 --- a/test/src/test/java/hudson/slaves/JNLPLauncherTest.java +++ b/test/src/test/java/hudson/slaves/JNLPLauncherTest.java @@ -25,7 +25,6 @@ package hudson.slaves; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; import com.gargoylesoftware.htmlunit.html.HtmlPage; -import hudson.FilePath; import hudson.Proc; import hudson.Util; import hudson.model.Computer; @@ -84,8 +83,7 @@ public class JNLPLauncherTest extends HudsonTestCase { * Launches the JNLP slave agent and asserts its basic operations. */ private void launchJnlpAndVerify(Computer c, ArgumentListBuilder args) throws Exception { - Proc proc = createLocalLauncher().launch(args.toCommandArray(), - new String[0], System.out, new FilePath(new File("."))); + Proc proc = createLocalLauncher().launch().cmds(args).stdout(System.out).pwd(".").start(); try { // verify that the connection is established, up to 10 secs