16
16
17
17
import java .io .File ;
18
18
import java .io .IOException ;
19
+ import java .io .Serializable ;
19
20
import java .util .ArrayList ;
20
21
import java .util .List ;
22
+ import java .util .logging .Logger ;
21
23
import java .util .regex .Matcher ;
22
24
import java .util .regex .Pattern ;
23
25
24
26
import javax .servlet .ServletException ;
25
27
28
+ import jline .ArgumentCompletor ;
29
+
26
30
import net .sf .json .JSONObject ;
27
31
28
32
import org .apache .commons .lang .StringUtils ;
31
35
import org .kohsuke .stapler .StaplerRequest ;
32
36
33
37
/**
34
- * Sample {@link Builder}.
38
+ * sbt plugin {@link Builder}.
35
39
*
36
40
* <p>
37
41
* When the user configures the project and enables this builder,
45
49
* {@link #perform(AbstractBuild, Launcher, BuildListener)} method will be
46
50
* invoked.
47
51
*
48
- * @author Kohsuke Kawaguchi
52
+ * @author Uzi Landsmann
49
53
*/
50
54
public class SbtPluginBuilder extends Builder {
51
55
52
- private final String actions ;
56
+ public static final Logger LOGGER = Logger .getLogger (SbtPluginBuilder .class
57
+ .getName ());
58
+
59
+ private final String name ;
53
60
private final String jvmFlags ;
54
61
private final String sbtFlags ;
62
+ private final String actions ;
55
63
56
64
// Fields in config.jelly must match the parameter names in the
57
65
// "DataBoundConstructor"
58
66
@ 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 ;
60
70
this .jvmFlags = jvmFlags ;
61
71
this .sbtFlags = sbtFlags ;
62
72
this .actions = actions ;
63
73
}
64
74
75
+ public String getName () {
76
+ return name ;
77
+ }
78
+
65
79
public String getJvmFlags () {
66
80
return jvmFlags ;
67
81
}
@@ -74,6 +88,10 @@ public String getActions() {
74
88
return actions ;
75
89
}
76
90
91
+ /**
92
+ * Perform the sbt build. Interpret the command arguments and create a
93
+ * command line, then run it.
94
+ */
77
95
@ Override
78
96
public boolean perform (AbstractBuild build , Launcher launcher ,
79
97
BuildListener listener ) {
@@ -95,31 +113,40 @@ public boolean perform(AbstractBuild build, Launcher launcher,
95
113
return success ;
96
114
} catch (IllegalArgumentException e ) {
97
115
// Util.displayIOException(e, listener);
98
- e .printStackTrace (listener .fatalError ("command execution failed" ));
116
+ e .printStackTrace (listener .fatalError ("command execution failed: "
117
+ + e .getMessage ()));
99
118
build .setResult (Result .FAILURE );
100
119
return false ;
101
120
} catch (IOException e ) {
102
121
Util .displayIOException (e , listener );
103
- e .printStackTrace (listener .fatalError ("command execution failed" ));
122
+ e .printStackTrace (listener .fatalError ("command execution failed: "
123
+ + e .getMessage ()));
104
124
build .setResult (Result .FAILURE );
105
125
return false ;
106
126
} catch (InterruptedException e ) {
107
127
// Util.displayIOException(e, listener);
108
- e .printStackTrace (listener .fatalError ("command execution failed" ));
128
+ e .printStackTrace (listener .fatalError ("command execution failed: "
129
+ + e .getMessage ()));
109
130
build .setResult (Result .FAILURE );
110
131
return false ;
111
132
}
112
133
113
134
}
114
135
136
+ /**
137
+ * Create an {@link ArgumentListBuilder} to run the build, given command
138
+ * arguments.
139
+ */
115
140
private ArgumentListBuilder buildCmdLine (AbstractBuild build ,
116
141
Launcher launcher , BuildListener listener )
117
142
throws IllegalArgumentException {
118
143
ArgumentListBuilder args = new ArgumentListBuilder ();
119
144
120
- String sbtJarPath = getDescriptor ().getSbtJarPath ();
145
+ DescriptorImpl descriptor = (DescriptorImpl ) getDescriptor ();
146
+
147
+ String launcherPath = descriptor .getJar (name ).getPath ();
121
148
122
- if (StringUtils .isBlank (sbtJarPath )) {
149
+ if (StringUtils .isBlank (launcherPath )) {
123
150
throw new IllegalArgumentException ("SBT jar path is empty" );
124
151
}
125
152
@@ -133,19 +160,12 @@ private ArgumentListBuilder buildCmdLine(AbstractBuild build,
133
160
+ "/java" : "java" ;
134
161
args .add (new File (java ).getAbsolutePath ());
135
162
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 );
145
165
146
166
args .add ("-jar" );
147
167
148
- args .add (sbtJarPath );
168
+ args .add (launcherPath );
149
169
150
170
for (String action : split (actions )) {
151
171
args .add (action );
@@ -154,13 +174,35 @@ private ArgumentListBuilder buildCmdLine(AbstractBuild build,
154
174
return args ;
155
175
}
156
176
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
+
157
196
/*
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
160
201
*/
161
202
private List <String > split (String s ) {
162
203
List <String > result = new ArrayList <String >();
163
- Matcher matcher = Pattern .compile ("[^\\ s\" ']+|\" ([^\" ]*)\" |'([^']*)'" ).matcher (s );
204
+ Matcher matcher = Pattern .compile ("[^\\ s\" ']+|\" ([^\" ]*)\" |'([^']*)'" )
205
+ .matcher (s );
164
206
while (matcher .find ()) {
165
207
if (matcher .group (1 ) != null )
166
208
result .add (matcher .group (1 ));
@@ -172,9 +214,6 @@ else if (matcher.group(2) != null)
172
214
return result ;
173
215
}
174
216
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.
178
217
@ Override
179
218
public DescriptorImpl getDescriptor () {
180
219
return (DescriptorImpl ) super .getDescriptor ();
@@ -194,53 +233,107 @@ public DescriptorImpl getDescriptor() {
194
233
public static final class DescriptorImpl extends
195
234
BuildStepDescriptor <Builder > {
196
235
197
- private String sbtJarPath ;
236
+ private volatile Jar [] jars = new Jar [ 0 ] ;
198
237
199
238
public DescriptorImpl () {
239
+ super (SbtPluginBuilder .class );
200
240
load ();
201
241
}
202
242
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
219
244
public boolean isApplicable (Class <? extends AbstractProject > aClass ) {
220
- // indicates that this builder can be used with all kinds of project
221
- // types
222
245
return true ;
223
246
}
224
247
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
+
225
262
/**
226
263
* This human readable name is used in the configuration screen.
227
264
*/
228
265
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 ;
230
276
}
231
277
232
278
@ Override
233
279
public boolean configure (StaplerRequest req , JSONObject formData )
234
280
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
+ }
236
303
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 ;
239
325
}
240
326
241
- public String getSbtJarPath ( ) {
242
- return sbtJarPath ;
327
+ public void setName ( String name ) {
328
+ this . name = name ;
243
329
}
244
330
331
+ public String getPath () {
332
+ return path ;
333
+ }
334
+
335
+ public void setPath (String path ) {
336
+ this .path = path ;
337
+ }
245
338
}
246
339
}
0 commit comments