From 8585d3d5fad6e3f5febdec5224b79fc42ba916c5 Mon Sep 17 00:00:00 2001 From: kohsuke Date: Fri, 10 Apr 2009 01:27:08 +0000 Subject: [PATCH] added a hook for decorating launchers git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@16994 71c3de6d-444a-0410-be80-ed276b4c234a --- core/src/main/java/hudson/Launcher.java | 55 +++++++++++++++++++ .../main/java/hudson/LauncherDecorator.java | 53 ++++++++++++++++++ core/src/main/java/hudson/model/Hudson.java | 3 +- core/src/main/java/hudson/model/Node.java | 3 + core/src/main/java/hudson/model/Slave.java | 2 +- .../main/java/hudson/tasks/BuildWrapper.java | 2 + 6 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 core/src/main/java/hudson/LauncherDecorator.java diff --git a/core/src/main/java/hudson/Launcher.java b/core/src/main/java/hudson/Launcher.java index 9a041e72b7..7a3d32e9d9 100644 --- a/core/src/main/java/hudson/Launcher.java +++ b/core/src/main/java/hudson/Launcher.java @@ -28,6 +28,7 @@ import hudson.Proc.RemoteProc; import hudson.model.Computer; import hudson.model.Hudson; import hudson.model.TaskListener; +import hudson.model.Node; import hudson.remoting.Callable; import hudson.remoting.Channel; import hudson.remoting.Pipe; @@ -325,6 +326,60 @@ public abstract class Launcher { printCommandLine(masked, workDir); } + /** + * Returns a decorated {@link Launcher} for the given node. + */ + public final Launcher decorateFor(Node node) { + Launcher l = this; + for (LauncherDecorator d : LauncherDecorator.all()) + l = d.decorate(l,node); + return l; + } + + /** + * Returns a decorated {@link Launcher} that puts the given set of arguments as a prefix to any commands + * that it invokes. + * + * @since 1.299 + */ + public final Launcher decorateByPrefix(final String... prefix) { + final Launcher outer = this; + return new Launcher(listener,channel) { + @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); + } + + @Override + public Channel launchChannel(String[] cmd, OutputStream out, FilePath workDir, Map envVars) throws IOException, InterruptedException { + return outer.launchChannel(prefix(cmd),out,workDir,envVars); + } + + @Override + public void kill(Map modelEnvVars) throws IOException, InterruptedException { + outer.kill(modelEnvVars); + } + + private String[] prefix(String[] args) { + String[] newArgs = new String[args.length+prefix.length]; + System.arraycopy(prefix,0,newArgs,0,prefix.length); + System.arraycopy(args,0,newArgs,prefix.length,args.length); + return newArgs; + } + + private boolean[] prefix(boolean[] args) { + boolean[] newArgs = new boolean[args.length+prefix.length]; + System.arraycopy(args,0,newArgs,prefix.length,args.length); + return newArgs; + } + }; + } + /** * {@link Launcher} that launches process locally. */ diff --git a/core/src/main/java/hudson/LauncherDecorator.java b/core/src/main/java/hudson/LauncherDecorator.java new file mode 100644 index 0000000000..b1d33b0685 --- /dev/null +++ b/core/src/main/java/hudson/LauncherDecorator.java @@ -0,0 +1,53 @@ +package hudson; + +import hudson.model.Hudson; +import hudson.model.Node; +import hudson.model.TaskListener; +import hudson.model.AbstractBuild; +import hudson.model.BuildListener; +import hudson.model.Executor; +import hudson.tasks.BuildWrapper; + +/** + * Decorates {@link Launcher} so that one can intercept executions of commands + * and alters the command being executed, such as doing this in fakeroot, sudo, pfexec, etc. + * + * @author Kohsuke Kawaguchi + * @since 1.299 + * @see BuildWrapper#decorateLauncher(AbstractBuild, Launcher, BuildListener) + */ +public abstract class LauncherDecorator implements ExtensionPoint { + /** + * Called from {@link Node#createLauncher(TaskListener)} to decorate the launchers. + * + *

+ * This method should perform node-specific decoration. For job-specific decoration, + * {@link BuildWrapper#decorateLauncher(AbstractBuild, Launcher, BuildListener)} might + * fit your needs better. + * + *

+ * If the implementation wants to do something differently if the launcher is + * for a build, call {@link Executor#currentExecutor()}. If it returns non-null + * you can figure out the current build in progress from there. Note that + * {@link Launcher}s are also created for doing things other than builds, + * so {@link Executor#currentExecutor()} may return null. Also, for job-specific + * decoration, see {@link BuildWrapper#decorateLauncher(AbstractBuild, Launcher, BuildListener)} as well. + * + * @param launcher + * The base launcher that you can decorate. Never null. + * @param node + * Node for which this launcher is created. Never null. + * @return + * Never null. Return the 'launcher' parameter to do no-op. + * @see Launcher#decorateFor(Node) + * @see Launcher#decorateByPrefix(String[]) + */ + public abstract Launcher decorate(Launcher launcher, Node node); + + /** + * Returns all the registered {@link LauncherDecorator}s. + */ + public static ExtensionList all() { + return Hudson.getInstance().getExtensionList(LauncherDecorator.class); + } +} diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index 14f1a59bdb..52b09c92d8 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -44,6 +44,7 @@ import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.DescriptorExtensionList; import hudson.ExtensionListView; +import hudson.LauncherDecorator; import hudson.logging.LogRecorderManager; import hudson.lifecycle.Lifecycle; import hudson.model.Descriptor.FormException; @@ -891,7 +892,7 @@ public final class Hudson extends Node implements ItemGroup, Stapl } public Launcher createLauncher(TaskListener listener) { - return new LocalLauncher(listener); + return new LocalLauncher(listener).decorateFor(this); } private final transient Object updateComputerLock = new Object(); diff --git a/core/src/main/java/hudson/model/Node.java b/core/src/main/java/hudson/model/Node.java index 06128e7088..f83887a575 100644 --- a/core/src/main/java/hudson/model/Node.java +++ b/core/src/main/java/hudson/model/Node.java @@ -93,6 +93,9 @@ public abstract class Node extends AbstractModelObject implements Describable + * The callee must call {@link Launcher#decorateFor(Node)} before returning to complete the decoration. */ public abstract Launcher createLauncher(TaskListener listener); diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index e2a790bc86..406c67f691 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -377,7 +377,7 @@ public abstract class Slave extends Node implements Serializable { public Launcher createLauncher(TaskListener listener) { SlaveComputer c = getComputer(); - return new RemoteLauncher(listener, c.getChannel(), c.isUnix()); + return new RemoteLauncher(listener, c.getChannel(), c.isUnix()).decorateFor(this); } /** diff --git a/core/src/main/java/hudson/tasks/BuildWrapper.java b/core/src/main/java/hudson/tasks/BuildWrapper.java index 193cf79c69..d53c190901 100644 --- a/core/src/main/java/hudson/tasks/BuildWrapper.java +++ b/core/src/main/java/hudson/tasks/BuildWrapper.java @@ -27,6 +27,7 @@ import hudson.ExtensionPoint; import hudson.Launcher; import hudson.DescriptorExtensionList; import hudson.FileSystemProvisionerDescriptor; +import hudson.LauncherDecorator; import hudson.model.AbstractBuild; import hudson.model.Build; import hudson.model.BuildListener; @@ -168,6 +169,7 @@ public abstract class BuildWrapper implements ExtensionPoint, Describable