Skip to content

Commit 23472ee

Browse files
committed
added support for multiple sbt launchers
1 parent 5b24258 commit 23472ee

File tree

4 files changed

+178
-59
lines changed

4 files changed

+178
-59
lines changed

pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
22
<modelVersion>4.0.0</modelVersion>
33
<parent>
4-
<groupId>org.jvnet.hudson.plugins</groupId>
4+
<groupId>org.jenkins-ci.plugins</groupId>
55
<artifactId>plugin</artifactId>
6-
<version>1.392</version>
6+
<version>1.396</version>
77
<relativePath>../pom.xml</relativePath>
88
</parent>
99

@@ -29,8 +29,8 @@
2929
<url>file:.</url>
3030
</snapshotRepository>
3131
<repository>
32-
<id>java.net-m2-repository</id>
33-
<url>http://maven.hudson-labs.org:8081/content/repositories/releases/</url>
32+
<id>maven.jenkins-ci.org</id>
33+
<url>http://maven.jenkins-ci.org:8081/content/repositories/releases/</url>
3434
</repository>
3535
</distributionManagement>
3636

src/main/java/org/jvnet/hudson/plugins/SbtPluginBuilder.java

Lines changed: 143 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@
1616

1717
import java.io.File;
1818
import java.io.IOException;
19+
import java.io.Serializable;
1920
import java.util.ArrayList;
2021
import java.util.List;
22+
import java.util.logging.Logger;
2123
import java.util.regex.Matcher;
2224
import java.util.regex.Pattern;
2325

2426
import javax.servlet.ServletException;
2527

28+
import jline.ArgumentCompletor;
29+
2630
import net.sf.json.JSONObject;
2731

2832
import org.apache.commons.lang.StringUtils;
@@ -31,7 +35,7 @@
3135
import org.kohsuke.stapler.StaplerRequest;
3236

3337
/**
34-
* Sample {@link Builder}.
38+
* sbt plugin {@link Builder}.
3539
*
3640
* <p>
3741
* When the user configures the project and enables this builder,
@@ -45,23 +49,33 @@
4549
* {@link #perform(AbstractBuild, Launcher, BuildListener)} method will be
4650
* invoked.
4751
*
48-
* @author Kohsuke Kawaguchi
52+
* @author Uzi Landsmann
4953
*/
5054
public class SbtPluginBuilder extends Builder {
5155

52-
private final String actions;
56+
public static final Logger LOGGER = Logger.getLogger(SbtPluginBuilder.class
57+
.getName());
58+
59+
private final String name;
5360
private final String jvmFlags;
5461
private final String sbtFlags;
62+
private final String actions;
5563

5664
// Fields in config.jelly must match the parameter names in the
5765
// "DataBoundConstructor"
5866
@DataBoundConstructor
59-
public SbtPluginBuilder(String jvmFlags, String sbtFlags, String actions) {
67+
public SbtPluginBuilder(String name, String jvmFlags, String sbtFlags,
68+
String actions) {
69+
this.name = name;
6070
this.jvmFlags = jvmFlags;
6171
this.sbtFlags = sbtFlags;
6272
this.actions = actions;
6373
}
6474

75+
public String getName() {
76+
return name;
77+
}
78+
6579
public String getJvmFlags() {
6680
return jvmFlags;
6781
}
@@ -74,6 +88,10 @@ public String getActions() {
7488
return actions;
7589
}
7690

91+
/**
92+
* Perform the sbt build. Interpret the command arguments and create a
93+
* command line, then run it.
94+
*/
7795
@Override
7896
public boolean perform(AbstractBuild build, Launcher launcher,
7997
BuildListener listener) {
@@ -95,31 +113,40 @@ public boolean perform(AbstractBuild build, Launcher launcher,
95113
return success;
96114
} catch (IllegalArgumentException e) {
97115
// Util.displayIOException(e, listener);
98-
e.printStackTrace(listener.fatalError("command execution failed"));
116+
e.printStackTrace(listener.fatalError("command execution failed: "
117+
+ e.getMessage()));
99118
build.setResult(Result.FAILURE);
100119
return false;
101120
} catch (IOException e) {
102121
Util.displayIOException(e, listener);
103-
e.printStackTrace(listener.fatalError("command execution failed"));
122+
e.printStackTrace(listener.fatalError("command execution failed: "
123+
+ e.getMessage()));
104124
build.setResult(Result.FAILURE);
105125
return false;
106126
} catch (InterruptedException e) {
107127
// Util.displayIOException(e, listener);
108-
e.printStackTrace(listener.fatalError("command execution failed"));
128+
e.printStackTrace(listener.fatalError("command execution failed: "
129+
+ e.getMessage()));
109130
build.setResult(Result.FAILURE);
110131
return false;
111132
}
112133

113134
}
114135

136+
/**
137+
* Create an {@link ArgumentListBuilder} to run the build, given command
138+
* arguments.
139+
*/
115140
private ArgumentListBuilder buildCmdLine(AbstractBuild build,
116141
Launcher launcher, BuildListener listener)
117142
throws IllegalArgumentException {
118143
ArgumentListBuilder args = new ArgumentListBuilder();
119144

120-
String sbtJarPath = getDescriptor().getSbtJarPath();
145+
DescriptorImpl descriptor = (DescriptorImpl) getDescriptor();
146+
147+
String launcherPath = descriptor.getJar(name).getPath();
121148

122-
if (StringUtils.isBlank(sbtJarPath)) {
149+
if (StringUtils.isBlank(launcherPath)) {
123150
throw new IllegalArgumentException("SBT jar path is empty");
124151
}
125152

@@ -133,19 +160,12 @@ private ArgumentListBuilder buildCmdLine(AbstractBuild build,
133160
+ "/java" : "java";
134161
args.add(new File(java).getAbsolutePath());
135162

136-
String[] split = jvmFlags.split(" ");
137-
for (String flag : split) {
138-
args.add(flag);
139-
}
140-
141-
split = sbtFlags.split(" ");
142-
for (String flag : split) {
143-
args.add(flag);
144-
}
163+
splitAndAddArgs(jvmFlags, args);
164+
splitAndAddArgs(sbtFlags, args);
145165

146166
args.add("-jar");
147167

148-
args.add(sbtJarPath);
168+
args.add(launcherPath);
149169

150170
for (String action : split(actions)) {
151171
args.add(action);
@@ -154,13 +174,35 @@ private ArgumentListBuilder buildCmdLine(AbstractBuild build,
154174
return args;
155175
}
156176

177+
/**
178+
* Split arguments and add them to the args list
179+
*
180+
* @param argsToSplit
181+
* the arguments to split
182+
* @param args
183+
* java/sbt command arguments
184+
*/
185+
private void splitAndAddArgs(String argsToSplit, ArgumentListBuilder args) {
186+
if (StringUtils.isBlank(argsToSplit)) {
187+
return;
188+
}
189+
190+
String[] split = argsToSplit.split(" ");
191+
for (String flag : split) {
192+
args.add(flag);
193+
}
194+
}
195+
157196
/*
158-
* Splits by whitespace except if surrounded by quotes.
159-
* See http://stackoverflow.com/questions/366202/regex-for-splitting-a-string-using-space-when-not-surrounded-by-single-or-double/366532#366532
197+
* Splits by whitespace except if surrounded by quotes. See
198+
* http://stackoverflow
199+
* .com/questions/366202/regex-for-splitting-a-string-using
200+
* -space-when-not-surrounded-by-single-or-double/366532#366532
160201
*/
161202
private List<String> split(String s) {
162203
List<String> result = new ArrayList<String>();
163-
Matcher matcher = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'").matcher(s);
204+
Matcher matcher = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'")
205+
.matcher(s);
164206
while (matcher.find()) {
165207
if (matcher.group(1) != null)
166208
result.add(matcher.group(1));
@@ -172,9 +214,6 @@ else if (matcher.group(2) != null)
172214
return result;
173215
}
174216

175-
// overrided for better type safety.
176-
// if your plugin doesn't really define any property on Descriptor,
177-
// you don't have to do this.
178217
@Override
179218
public DescriptorImpl getDescriptor() {
180219
return (DescriptorImpl) super.getDescriptor();
@@ -194,53 +233,107 @@ public DescriptorImpl getDescriptor() {
194233
public static final class DescriptorImpl extends
195234
BuildStepDescriptor<Builder> {
196235

197-
private String sbtJarPath;
236+
private volatile Jar[] jars = new Jar[0];
198237

199238
public DescriptorImpl() {
239+
super(SbtPluginBuilder.class);
200240
load();
201241
}
202242

203-
/**
204-
* Performs on-the-fly validation of the form field 'name'.
205-
*
206-
* @param value
207-
* This parameter receives the value that the user has typed.
208-
* @return Indicates the outcome of the validation. This is sent to the
209-
* browser.
210-
*/
211-
public FormValidation doCheckSbtJarPath(@QueryParameter String value)
212-
throws IOException, ServletException {
213-
if (value.isEmpty()) {
214-
return FormValidation.error("Please enter a path");
215-
}
216-
return FormValidation.ok();
217-
}
218-
243+
@Override
219244
public boolean isApplicable(Class<? extends AbstractProject> aClass) {
220-
// indicates that this builder can be used with all kinds of project
221-
// types
222245
return true;
223246
}
224247

248+
@Override
249+
public Builder newInstance(StaplerRequest req, JSONObject formData) {
250+
251+
LOGGER.info(String.format("Creating new instance with formData %s",
252+
formData));
253+
254+
String name = formData.getString("name");
255+
String jvmFlags = formData.getString("jvmFlags");
256+
String sbtFlags = formData.getString("sbtFlags");
257+
String actions = formData.getString("actions");
258+
259+
return new SbtPluginBuilder(name, jvmFlags, sbtFlags, actions);
260+
}
261+
225262
/**
226263
* This human readable name is used in the configuration screen.
227264
*/
228265
public String getDisplayName() {
229-
return "Build using SBT";
266+
return "Build using sbt";
267+
}
268+
269+
public Jar getJar(String name) {
270+
for (Jar jar : jars) {
271+
if (jar.getName().equals(name)) {
272+
return jar;
273+
}
274+
}
275+
return null;
230276
}
231277

232278
@Override
233279
public boolean configure(StaplerRequest req, JSONObject formData)
234280
throws FormException {
235-
sbtJarPath = formData.getString("sbtJarPath");
281+
282+
try {
283+
jars = req.bindJSONToList(Jar.class,
284+
req.getSubmittedForm().get("jar")).toArray(new Jar[0]);
285+
save();
286+
return true;
287+
} catch (ServletException e) {
288+
289+
LOGGER.severe(String.format("Couldn't save jars beacause %s",
290+
e.getMessage()));
291+
LOGGER.severe(String.format("Stacktrace %s", e.getStackTrace()
292+
.toString()));
293+
294+
return false;
295+
}
296+
}
297+
298+
public Jar[] getJars() {
299+
return jars;
300+
}
301+
302+
}
236303

237-
save();
238-
return super.configure(req, formData);
304+
/**
305+
* Representation of an sbt launcher. Several such launchers can be defined
306+
* in Jenkins properties to choose among when running a project.
307+
*/
308+
public static final class Jar implements Serializable {
309+
private static final long serialVersionUID = 1L;
310+
311+
/** The human-friendly name of this launcher */
312+
private String name;
313+
314+
/** The path to the launcher */
315+
private String path;
316+
317+
@DataBoundConstructor
318+
public Jar(String name, String path) {
319+
this.name = name;
320+
this.path = path;
321+
}
322+
323+
public String getName() {
324+
return name;
239325
}
240326

241-
public String getSbtJarPath() {
242-
return sbtJarPath;
327+
public void setName(String name) {
328+
this.name = name;
243329
}
244330

331+
public String getPath() {
332+
return path;
333+
}
334+
335+
public void setPath(String path) {
336+
this.path = path;
337+
}
245338
}
246339
}

src/main/resources/org/jvnet/hudson/plugins/SbtPluginBuilder/config.jelly

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,20 @@
44
55
See global.jelly for a general discussion about jelly script.
66
-->
7+
8+
<f:entry title="sbt launcher">
9+
<select class="setting-input" name="jar.name" description="Select configured sbt launcher">
10+
<j:forEach var="jar" items="${descriptor.jars}">
11+
<f:option selected="${jar.name.equals(instance.name)}">${jar.name}</f:option>
12+
</j:forEach>
13+
</select>
14+
</f:entry>
715

816
<f:entry title="JVM Flags" field="jvmFlags">
917
<f:textbox/>
1018
</f:entry>
1119

12-
<f:entry title="SBT Flags" field="sbtFlags" >
20+
<f:entry title="sbt Flags" field="sbtFlags" >
1321
<f:textbox default="-Dsbt.log.noformat=true"/>
1422
</f:entry>
1523

0 commit comments

Comments
 (0)