22
22
23
23
import com .google .common .collect .ImmutableList ;
24
24
import com .google .common .collect .ImmutableMap ;
25
+ import com .google .gson .Gson ;
26
+ import com .google .gson .GsonBuilder ;
27
+ import com .google .gson .JsonArray ;
28
+ import com .google .gson .JsonObject ;
29
+
25
30
import org .apache .commons .lang3 .tuple .ImmutableTriple ;
26
31
import org .apache .commons .lang3 .tuple .Triple ;
27
32
import org .gradle .api .Project ;
46
51
import javax .xml .transform .dom .DOMSource ;
47
52
import javax .xml .transform .stream .StreamResult ;
48
53
import java .io .File ;
54
+ import java .io .FileWriter ;
55
+ import java .io .IOException ;
56
+ import java .io .Writer ;
49
57
import java .util .Collections ;
50
58
import java .util .LinkedHashMap ;
51
59
import java .util .List ;
@@ -60,11 +68,13 @@ public final class IDEUtils {
60
68
public static void createIDEGenRunsTasks (@ Nonnull final MinecraftExtension minecraft , @ Nonnull final TaskProvider <Task > prepareRuns , @ Nonnull final TaskProvider <Task > makeSourceDirs ) {
61
69
final Project project = minecraft .getProject ();
62
70
63
- final Map <String , Triple <List <Object >, File , RunConfigurationGenerator >> ideConfigurationGenerators = ImmutableMap .<String , Triple <List <Object >, File , RunConfigurationGenerator >>builder ()
71
+ final Map <String , Triple <List <Object >, File , RunConfigurationBuilder >> ideConfigurationGenerators = ImmutableMap .<String , Triple <List <Object >, File , RunConfigurationBuilder >>builder ()
64
72
.put ("genIntellijRuns" , ImmutableTriple .of (Collections .singletonList (prepareRuns .get ()),
65
- new File (project .getRootProject ().getRootDir (), ".idea/runConfigurations" ), IDEUtils ::createIntellijRunConfigurationXML ))
73
+ new File (project .getRootProject ().getRootDir (), ".idea/runConfigurations" ), new XMLConfigurationBuilder ( IDEUtils ::createIntellijRunConfigurationXML ) ))
66
74
.put ("genEclipseRuns" , ImmutableTriple .of (ImmutableList .of (prepareRuns .get (), makeSourceDirs .get ()),
67
- project .getProjectDir (), IDEUtils ::createEclipseRunConfigurationXML ))
75
+ project .getProjectDir (), new XMLConfigurationBuilder (IDEUtils ::createEclipseRunConfigurationXML )))
76
+ .put ("genVSCodeRuns" , ImmutableTriple .of (ImmutableList .of (prepareRuns .get (), makeSourceDirs .get ()),
77
+ new File (project .getProjectDir (), ".vscode" ), new JsonConfigurationBuilder (IDEUtils ::createVSCodeRunConfiguration )))
68
78
.build ();
69
79
70
80
ideConfigurationGenerators .forEach ((taskName , configurationGenerator ) -> {
@@ -73,40 +83,12 @@ public static void createIDEGenRunsTasks(@Nonnull final MinecraftExtension minec
73
83
task .dependsOn (configurationGenerator .getLeft ());
74
84
75
85
task .doLast (t -> {
76
- try {
77
- final File runConfigurationsDir = configurationGenerator .getMiddle ();
78
-
79
- if (!runConfigurationsDir .exists ()) {
80
- runConfigurationsDir .mkdirs ();
81
- }
86
+ final File runConfigurationsDir = configurationGenerator .getMiddle ();
82
87
83
- final DocumentBuilderFactory docFactory = DocumentBuilderFactory .newInstance ();
84
- final DocumentBuilder docBuilder = docFactory .newDocumentBuilder ();
85
- final TransformerFactory transformerFactory = TransformerFactory .newInstance ();
86
- final Transformer transformer = transformerFactory .newTransformer ();
87
-
88
- transformer .setOutputProperty (OutputKeys .INDENT , "yes" );
89
- transformer .setOutputProperty ("{http://xml.apache.org/xslt}indent-amount" , "2" );
90
-
91
- minecraft .getRuns ().forEach (runConfig -> {
92
- final Stream <String > propStream = runConfig .getProperties ().entrySet ().stream ().map (kv -> String .format ("-D%s=%s" , kv .getKey (), kv .getValue ()));
93
- final String props = Stream .concat (propStream , runConfig .getJvmArgs ().stream ()).collect (Collectors .joining (" " ));
94
- final Map <String , Document > documents = configurationGenerator .getRight ().createRunConfigurationXML (project , runConfig , props , docBuilder );
95
-
96
- documents .forEach ((fileName , document ) -> {
97
- final DOMSource source = new DOMSource (document );
98
- final StreamResult result = new StreamResult (new File (runConfigurationsDir , fileName ));
99
-
100
- try {
101
- transformer .transform (source , result );
102
- } catch (TransformerException e ) {
103
- e .printStackTrace ();
104
- }
105
- });
106
- });
107
- } catch (ParserConfigurationException | TransformerConfigurationException e ) {
108
- e .printStackTrace ();
88
+ if (!runConfigurationsDir .exists ()) {
89
+ runConfigurationsDir .mkdirs ();
109
90
}
91
+ configurationGenerator .getRight ().createConfig (minecraft , runConfigurationsDir , project );
110
92
});
111
93
});
112
94
});
@@ -231,49 +213,7 @@ private static Map<String, Document> createEclipseRunConfigurationXML(@Nonnull f
231
213
{
232
214
envs .setAttribute ("key" , "org.eclipse.debug.core.environmentVariables" );
233
215
234
- runConfig .getEnvironment ().compute ("MOD_CLASSES" , (key , value ) -> {
235
- // Only replace environment variable if it is already set
236
- if (value == null || value .isEmpty ()) {
237
- return value ;
238
- }
239
-
240
- final EclipseModel eclipse = project .getExtensions ().findByType (EclipseModel .class );
241
-
242
- if (eclipse != null ) {
243
- final Map <String , String > outputs = eclipse .getClasspath ().resolveDependencies ().stream ()
244
- .filter (SourceFolder .class ::isInstance )
245
- .map (SourceFolder .class ::cast )
246
- .map (SourceFolder ::getOutput )
247
- .distinct ()
248
- .collect (Collectors .toMap (output -> output .split ("/" )[output .split ("/" ).length - 1 ], output -> project .file (output ).getAbsolutePath ()));
249
-
250
- if (runConfig .getMods ().isEmpty ()) {
251
- return runConfig .getAllSources ().stream ()
252
- .map (SourceSet ::getName )
253
- .filter (outputs ::containsKey )
254
- .map (outputs ::get )
255
- .map (s -> String .join (File .pathSeparator , s , s )) // <resources>:<classes>
256
- .collect (Collectors .joining (File .pathSeparator ));
257
- } else {
258
- final SourceSet main = project .getConvention ().getPlugin (JavaPluginConvention .class ).getSourceSets ().getByName (SourceSet .MAIN_SOURCE_SET_NAME );
259
-
260
- return runConfig .getMods ().stream ()
261
- .map (modConfig -> {
262
- return (modConfig .getSources ().isEmpty () ? Stream .of (main ) : modConfig .getSources ().stream ())
263
- .map (SourceSet ::getName )
264
- .filter (outputs ::containsKey )
265
- .map (outputs ::get )
266
- .map (output -> modConfig .getName () + "%%" + output )
267
- .map (s -> String .join (File .pathSeparator , s , s )); // <resources>:<classes>
268
- })
269
- .flatMap (Function .identity ())
270
- .collect (Collectors .joining (File .pathSeparator ));
271
- }
272
- }
273
-
274
- return value ;
275
- });
276
-
216
+ runConfig .getEnvironment ().compute ("MOD_CLASSES" , (key , value ) -> mapModClasses (key , value , project , runConfig ));
277
217
runConfig .getEnvironment ().forEach ((name , value ) -> {
278
218
final Element envEntry = javaDocument .createElement ("mapEntry" );
279
219
{
@@ -292,12 +232,168 @@ private static Map<String, Document> createEclipseRunConfigurationXML(@Nonnull f
292
232
return documents ;
293
233
}
294
234
235
+ @ Nonnull
236
+ private static JsonObject createVSCodeRunConfiguration (@ Nonnull final Project project , @ Nonnull final RunConfig runConfig , @ Nonnull final String props ) {
237
+ JsonObject config = new JsonObject ();
238
+ config .addProperty ("type" , "java" );
239
+ config .addProperty ("name" , runConfig .getTaskName ());
240
+ config .addProperty ("request" , "launch" );
241
+ config .addProperty ("mainClass" , runConfig .getMain ());
242
+ config .addProperty ("projectName" , project .getName ());
243
+ config .addProperty ("cwd" , replaceRootDirBy (project , runConfig .getWorkingDirectory ().toString (), "${workspaceFolder}" ));
244
+ config .addProperty ("vmArgs" , props );
245
+ config .addProperty ("args" , String .join (" " , runConfig .getArgs ()));
246
+ JsonObject env = new JsonObject ();
247
+ runConfig .getEnvironment ().compute ("MOD_CLASSES" , (key , value ) -> replaceRootDirBy (project , mapModClasses (key , value , project , runConfig ), "${workspaceFolder}" ));
248
+ runConfig .getEnvironment ().compute ("nativesDirectory" , (key , value ) -> replaceRootDirBy (project , value , "${workspaceFolder}" ));
249
+ runConfig .getEnvironment ().forEach ((name , value ) -> {
250
+ env .addProperty (name , value );
251
+ });
252
+ config .add ("env" , env );
253
+ return config ;
254
+ }
255
+
256
+ private static String replaceRootDirBy (@ Nonnull final Project project , String value , @ Nonnull final String replacement ) {
257
+ if (value == null || value .isEmpty ()) {
258
+ return value ;
259
+ }
260
+ return value .replace (project .getRootDir ().toString (), replacement );
261
+ }
262
+
263
+ private static String mapModClasses (String key , String value , @ Nonnull final Project project , @ Nonnull final RunConfig runConfig ) {
264
+ // Only replace environment variable if it is already set
265
+ if (value == null || value .isEmpty ()) {
266
+ return value ;
267
+ }
268
+
269
+ final EclipseModel eclipse = project .getExtensions ().findByType (EclipseModel .class );
270
+
271
+ if (eclipse != null ) {
272
+ final Map <String , String > outputs = eclipse .getClasspath ().resolveDependencies ().stream ()
273
+ .filter (SourceFolder .class ::isInstance )
274
+ .map (SourceFolder .class ::cast )
275
+ .map (SourceFolder ::getOutput )
276
+ .distinct ()
277
+ .collect (Collectors .toMap (output -> output .split ("/" )[output .split ("/" ).length - 1 ], output -> project .file (output ).getAbsolutePath ()));
278
+
279
+ if (runConfig .getMods ().isEmpty ()) {
280
+ return runConfig .getAllSources ().stream ()
281
+ .map (SourceSet ::getName )
282
+ .filter (outputs ::containsKey )
283
+ .map (outputs ::get )
284
+ .map (s -> String .join (File .pathSeparator , s , s )) // <resources>:<classes>
285
+ .collect (Collectors .joining (File .pathSeparator ));
286
+ } else {
287
+ final SourceSet main = project .getConvention ().getPlugin (JavaPluginConvention .class ).getSourceSets ().getByName (SourceSet .MAIN_SOURCE_SET_NAME );
288
+
289
+ return runConfig .getMods ().stream ()
290
+ .map (modConfig -> {
291
+ return (modConfig .getSources ().isEmpty () ? Stream .of (main ) : modConfig .getSources ().stream ())
292
+ .map (SourceSet ::getName )
293
+ .filter (outputs ::containsKey )
294
+ .map (outputs ::get )
295
+ .map (output -> modConfig .getName () + "%%" + output )
296
+ .map (s -> String .join (File .pathSeparator , s , s )); // <resources>:<classes>
297
+ })
298
+ .flatMap (Function .identity ())
299
+ .collect (Collectors .joining (File .pathSeparator ));
300
+ }
301
+ }
302
+
303
+ return value ;
304
+ }
305
+
295
306
@ FunctionalInterface
296
- private interface RunConfigurationGenerator {
307
+ private interface XMLRunConfigurationGenerator {
297
308
298
309
@ Nonnull
299
310
Map <String , Document > createRunConfigurationXML (@ Nonnull final Project project , @ Nonnull final RunConfig runConfig , @ Nonnull final String props , @ Nonnull final DocumentBuilder documentBuilder );
300
311
301
312
}
302
313
314
+ @ FunctionalInterface
315
+ private interface JsonRunConfigurationGenerator {
316
+
317
+ @ Nonnull
318
+ JsonObject createRunConfigurationJson (@ Nonnull final Project project , @ Nonnull final RunConfig runConfig , @ Nonnull final String props );
319
+
320
+ }
321
+
322
+ private interface RunConfigurationBuilder {
323
+
324
+ void createConfig (@ Nonnull final MinecraftExtension minecraft , @ Nonnull final File runConfigurationsDir , @ Nonnull final Project project );
325
+
326
+ }
327
+
328
+ private static class XMLConfigurationBuilder implements RunConfigurationBuilder {
329
+
330
+ private XMLRunConfigurationGenerator configGenerator ;
331
+
332
+ public XMLConfigurationBuilder (XMLRunConfigurationGenerator generator ) {
333
+ configGenerator = generator ;
334
+ }
335
+
336
+ @ Override
337
+ public void createConfig (@ Nonnull final MinecraftExtension minecraft , @ Nonnull final File runConfigurationsDir , @ Nonnull final Project project ) {
338
+ try {
339
+ final DocumentBuilderFactory docFactory = DocumentBuilderFactory .newInstance ();
340
+ final DocumentBuilder docBuilder = docFactory .newDocumentBuilder ();
341
+ final TransformerFactory transformerFactory = TransformerFactory .newInstance ();
342
+ final Transformer transformer = transformerFactory .newTransformer ();
343
+
344
+ transformer .setOutputProperty (OutputKeys .INDENT , "yes" );
345
+ transformer .setOutputProperty ("{http://xml.apache.org/xslt}indent-amount" , "2" );
346
+
347
+ minecraft .getRuns ().forEach (runConfig -> {
348
+ final Stream <String > propStream = runConfig .getProperties ().entrySet ().stream ().map (kv -> String .format ("-D%s=%s" , kv .getKey (), kv .getValue ()));
349
+ final String props = Stream .concat (propStream , runConfig .getJvmArgs ().stream ()).collect (Collectors .joining (" " ));
350
+ final Map <String , Document > documents = configGenerator .createRunConfigurationXML (project , runConfig , props , docBuilder );
351
+
352
+ documents .forEach ((fileName , document ) -> {
353
+ final DOMSource source = new DOMSource (document );
354
+ final StreamResult result = new StreamResult (new File (runConfigurationsDir , fileName ));
355
+
356
+ try {
357
+ transformer .transform (source , result );
358
+ } catch (TransformerException e ) {
359
+ e .printStackTrace ();
360
+ }
361
+ });
362
+ });
363
+ } catch (ParserConfigurationException | TransformerConfigurationException e ) {
364
+ e .printStackTrace ();
365
+ }
366
+ }
367
+ }
368
+
369
+ private static class JsonConfigurationBuilder implements RunConfigurationBuilder {
370
+
371
+ private JsonRunConfigurationGenerator configGenerator ;
372
+
373
+ public JsonConfigurationBuilder (JsonRunConfigurationGenerator generator ) {
374
+ configGenerator = generator ;
375
+ }
376
+
377
+ @ Override
378
+ public void createConfig (@ Nonnull final MinecraftExtension minecraft , @ Nonnull final File runConfigurationsDir , @ Nonnull final Project project ) {
379
+ final JsonObject rootObject = new JsonObject ();
380
+ rootObject .addProperty ("version" , "0.2.0" );
381
+ JsonArray runConfigs = new JsonArray ();
382
+ minecraft .getRuns ().forEach (runConfig -> {
383
+ final Stream <String > propStream = runConfig .getProperties ().entrySet ().stream ().map (kv -> String .format ("-D%s=%s" , kv .getKey (), kv .getValue ()));
384
+ final String props = Stream .concat (propStream , runConfig .getJvmArgs ().stream ()).collect (Collectors .joining (" " ));
385
+ runConfigs .add (configGenerator .createRunConfigurationJson (project , runConfig , props ));
386
+ });
387
+ rootObject .add ("configurations" , runConfigs );
388
+ Writer writer ;
389
+ try {
390
+ writer = new FileWriter (new File (runConfigurationsDir , "launch.json" ));
391
+ Gson gson = new GsonBuilder ().setPrettyPrinting ().create ();
392
+ writer .write (gson .toJson (rootObject ));
393
+ writer .close ();
394
+ } catch (IOException e ) {
395
+ e .printStackTrace ();
396
+ }
397
+ }
398
+ }
303
399
}
0 commit comments