Skip to content

Commit 5d0d63f

Browse files
committed
Split GroovyScript for agent and controller
Make GroovyScript simpler by separating the parts meant only for the controller into a new class that extends GroovyScript. This also makes the intention of each class and the differences between them clearer from the names themselves.
1 parent 22a9c44 commit 5d0d63f

File tree

4 files changed

+75
-56
lines changed

4 files changed

+75
-56
lines changed

src/main/java/org/jenkinsci/plugins/scriptler/builder/ScriptlerBuilder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.jenkinsci.plugins.scriptler.config.Parameter;
4646
import org.jenkinsci.plugins.scriptler.config.Script;
4747
import org.jenkinsci.plugins.scriptler.config.ScriptlerConfiguration;
48+
import org.jenkinsci.plugins.scriptler.util.ControllerGroovyScript;
4849
import org.jenkinsci.plugins.scriptler.util.GroovyScript;
4950
import org.jenkinsci.plugins.scriptler.util.ScriptHelper;
5051
import org.jenkinsci.plugins.scriptler.util.UIHelper;
@@ -256,8 +257,8 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
256257
final Object output;
257258
if (script.onlyController) {
258259
// When run on controller, make build, launcher, listener available to script
259-
output = FilePath.localChannel.call(
260-
new GroovyScript(script.getScriptText(), expandedParams, true, listener, launcher, build));
260+
output = FilePath.localChannel.call(new ControllerGroovyScript(
261+
script.getScriptText(), expandedParams, true, listener, launcher, build));
261262
} else {
262263
VirtualChannel channel = launcher.getChannel();
263264
if (channel == null) {

src/main/java/org/jenkinsci/plugins/scriptler/tokenmacro/ScriptlerTokenMacro.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
import hudson.remoting.ChannelClosedException;
99
import hudson.remoting.VirtualChannel;
1010
import java.io.IOException;
11-
import java.util.Collections;
11+
import java.util.List;
12+
import jenkins.model.Jenkins;
1213
import org.jenkinsci.plugins.scriptler.Messages;
1314
import org.jenkinsci.plugins.scriptler.config.Script;
15+
import org.jenkinsci.plugins.scriptler.util.ControllerGroovyScript;
1416
import org.jenkinsci.plugins.scriptler.util.GroovyScript;
1517
import org.jenkinsci.plugins.scriptler.util.ScriptHelper;
1618
import org.jenkinsci.plugins.tokenmacro.DataBoundTokenMacro;
@@ -39,21 +41,23 @@ public String evaluate(AbstractBuild<?, ?> context, TaskListener listener, Strin
3941
throw new MacroEvaluationException(Messages.tokenmacro_AdminScriptOnly(scriptId));
4042
}
4143

44+
String scriptText = script.getScriptText();
4245
VirtualChannel channel;
43-
if (script.onlyController) {
46+
GroovyScript groovyScript;
47+
if (script.onlyController || Jenkins.get().equals(context.getBuiltOn())) {
4448
channel = FilePath.localChannel;
49+
groovyScript = new ControllerGroovyScript(scriptText, List.of(), true, listener, null, context);
4550
} else {
4651
FilePath remoteFilePath = context.getWorkspace();
4752
if (remoteFilePath == null) {
4853
// the remote node has apparently disconnected, so we can't run our script
4954
throw new ChannelClosedException((Channel) null, null);
5055
}
5156
channel = remoteFilePath.getChannel();
57+
groovyScript = new GroovyScript(scriptText, List.of(), true, listener);
5258
}
5359

54-
Object output = channel.call(
55-
new GroovyScript(script.getScriptText(), Collections.emptyList(), true, listener, null, context));
56-
60+
Object output = channel.call(groovyScript);
5761
return output != null ? output.toString() : "";
5862
}
5963

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package org.jenkinsci.plugins.scriptler.util;
2+
3+
import edu.umd.cs.findbugs.annotations.NonNull;
4+
import groovy.lang.GroovyShell;
5+
import hudson.Launcher;
6+
import hudson.model.AbstractBuild;
7+
import hudson.model.TaskListener;
8+
import java.io.Serial;
9+
import java.util.Collection;
10+
import jenkins.model.Jenkins;
11+
import org.jenkinsci.plugins.scriptler.config.Parameter;
12+
13+
public class ControllerGroovyScript extends GroovyScript {
14+
@Serial
15+
private static final long serialVersionUID = 1L;
16+
17+
private final transient AbstractBuild<?, ?> build;
18+
private final transient Launcher launcher;
19+
20+
/**
21+
* This constructor can only be used when the script is executed on the controller, because launcher and build can not be transferred to an agent and therefore the execution will fail
22+
* @param script the script to be executed
23+
* @param parameters the parameters to be passed to the script
24+
* @param failWithException should the job fail with an exception
25+
* @param listener access to logging via listener
26+
* @param launcher the launcher
27+
* @param build the current build
28+
*/
29+
public ControllerGroovyScript(
30+
String script,
31+
@NonNull Collection<Parameter> parameters,
32+
boolean failWithException,
33+
TaskListener listener,
34+
Launcher launcher,
35+
AbstractBuild<?, ?> build) {
36+
super(script, parameters, failWithException, listener);
37+
this.build = build;
38+
this.launcher = launcher;
39+
}
40+
41+
@Override
42+
public ClassLoader getClassLoader() {
43+
return Jenkins.get().getPluginManager().uberClassLoader;
44+
}
45+
46+
@Override
47+
protected void setShellVariables(@NonNull GroovyShell shell) {
48+
super.setShellVariables(shell);
49+
if (build != null) {
50+
shell.setVariable("build", build);
51+
}
52+
if (launcher != null) {
53+
shell.setVariable("launcher", launcher);
54+
}
55+
}
56+
}

src/main/java/org/jenkinsci/plugins/scriptler/util/GroovyScript.java

Lines changed: 7 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,15 @@
33
import edu.umd.cs.findbugs.annotations.NonNull;
44
import groovy.lang.GroovyShell;
55
import groovy.lang.Script;
6-
import hudson.Launcher;
7-
import hudson.model.AbstractBuild;
86
import hudson.model.TaskListener;
97
import java.io.PrintStream;
108
import java.io.Serial;
119
import java.util.*;
1210
import java.util.concurrent.ConcurrentLinkedQueue;
13-
import jenkins.model.Jenkins;
1411
import jenkins.security.MasterToSlaveCallable;
15-
import jenkins.security.Roles;
1612
import org.apache.commons.collections.map.LRUMap;
1713
import org.jenkinsci.plugins.scriptler.Messages;
1814
import org.jenkinsci.plugins.scriptler.config.Parameter;
19-
import org.jenkinsci.remoting.Role;
20-
import org.jenkinsci.remoting.RoleChecker;
2115

2216
/**
2317
* Inspired by hudson.util.RemotingDiagnostics.Script, but adding parameters.
@@ -33,9 +27,6 @@ public class GroovyScript extends MasterToSlaveCallable<Object, RuntimeException
3327

3428
private final boolean failWithException;
3529
private final TaskListener listener;
36-
private final transient AbstractBuild<?, ?> build;
37-
private final transient Launcher launcher;
38-
private transient ClassLoader cl;
3930

4031
@SuppressWarnings("unchecked")
4132
private static final Map<String, ConcurrentLinkedQueue<Script>> cache = Collections.synchronizedMap(new LRUMap(10));
@@ -50,56 +41,30 @@ public class GroovyScript extends MasterToSlaveCallable<Object, RuntimeException
5041
}
5142

5243
/**
53-
* This constructor can only be used when the script is executed on the controller, because launcher and build can not be transferred to an agent and the execution will fail
44+
* Constructor
5445
* @param script the script to be executed
5546
* @param parameters the parameters to be passed to the script
5647
* @param failWithException should the job fail with an exception
5748
* @param listener access to logging via listener
58-
* @param launcher the launcher
59-
* @param build the current build
6049
*/
6150
public GroovyScript(
6251
String script,
6352
@NonNull Collection<Parameter> parameters,
6453
boolean failWithException,
65-
TaskListener listener,
66-
Launcher launcher,
67-
AbstractBuild<?, ?> build) {
54+
TaskListener listener) {
6855
this.script = script;
6956
this.parameters = new ArrayList<>(parameters);
7057
this.failWithException = failWithException;
7158
this.listener = listener;
72-
this.cl = getClassLoader();
73-
this.build = build;
74-
this.launcher = launcher;
75-
}
76-
77-
/**
78-
* Constructor
79-
* @param script the script to be executed
80-
* @param parameters the parameters to be passed to the script
81-
* @param failWithException should the job fail with an exception
82-
* @param listener access to logging via listener
83-
*/
84-
public GroovyScript(
85-
String script,
86-
@NonNull Collection<Parameter> parameters,
87-
boolean failWithException,
88-
TaskListener listener) {
89-
this(script, parameters, failWithException, listener, null, null);
9059
}
9160

9261
public ClassLoader getClassLoader() {
93-
return Jenkins.get().getPluginManager().uberClassLoader;
62+
return Thread.currentThread().getContextClassLoader();
9463
}
9564

9665
public Object call() {
97-
// if we run locally, cl!=null. Otherwise the delegating classloader will be available as context classloader.
98-
if (cl == null) {
99-
cl = Thread.currentThread().getContextClassLoader();
100-
}
10166
PrintStream logger = listener.getLogger();
102-
GroovyShell shell = new GroovyShell(cl);
67+
GroovyShell shell = new GroovyShell(getClassLoader());
10368

10469
for (Parameter param : parameters) {
10570
final String paramName = param.getName();
@@ -112,9 +77,7 @@ public Object call() {
11277

11378
// set default variables
11479
shell.setVariable("out", logger);
115-
shell.setVariable("listener", listener);
116-
if (build != null) shell.setVariable("build", build);
117-
if (launcher != null) shell.setVariable("launcher", launcher);
80+
setShellVariables(shell);
11881

11982
ConcurrentLinkedQueue<Script> scriptPool = cache.get(script);
12083
if (scriptPool == null) {
@@ -152,13 +115,8 @@ public Object call() {
152115
}
153116
}
154117

155-
@Override
156-
public void checkRoles(RoleChecker roleChecker) throws SecurityException {
157-
if (launcher != null && build != null) {
158-
roleChecker.check(this, Roles.MASTER);
159-
} else {
160-
roleChecker.check(this, Role.UNKNOWN);
161-
}
118+
protected void setShellVariables(@NonNull GroovyShell shell) {
119+
shell.setVariable("listener", listener);
162120
}
163121

164122
private static final class ScriptlerExecutionException extends RuntimeException {

0 commit comments

Comments
 (0)