1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.codehaus.gmavenplus.mojo;
18
19 import org.apache.maven.plugins.annotations.Parameter;
20 import org.apache.maven.shared.model.fileset.FileSet;
21 import org.apache.maven.shared.model.fileset.util.FileSetManager;
22 import org.codehaus.gmavenplus.javaparser.LanguageLevel;
23 import org.codehaus.gmavenplus.model.IncludeClasspath;
24 import org.codehaus.gmavenplus.model.Link;
25 import org.codehaus.gmavenplus.model.Scopes;
26 import org.codehaus.gmavenplus.model.internal.Version;
27 import org.codehaus.gmavenplus.util.FileUtils;
28
29 import org.codehaus.gmavenplus.model.GroovyDocConfiguration;
30 import org.codehaus.gmavenplus.util.GroovyCompiler;
31
32 import java.io.BufferedReader;
33 import java.io.BufferedWriter;
34 import java.io.File;
35 import java.io.IOException;
36 import java.io.InputStreamReader;
37 import java.io.OutputStreamWriter;
38 import java.lang.reflect.InvocationTargetException;
39 import java.net.MalformedURLException;
40 import java.nio.file.Files;
41 import java.util.ArrayList;
42 import java.util.List;
43 import java.util.Properties;
44
45
46
47
48
49
50
51 public abstract class AbstractGroovyDocMojo extends AbstractGroovySourcesMojo {
52
53
54
55
56 protected static final Version GROOVY_1_6_0_RC1 = new Version(1, 6, 0, "RC-1");
57
58
59
60
61 protected static final Version GROOVY_1_5_8 = new Version(1, 5, 8);
62
63
64
65
66 @Parameter(defaultValue = "Groovy Documentation")
67 protected String windowTitle;
68
69
70
71
72 @Parameter(defaultValue = "Groovy Documentation")
73 protected String docTitle;
74
75
76
77
78 @Parameter(defaultValue = "Groovy Documentation")
79 protected String footer;
80
81
82
83
84 @Parameter
85 protected LanguageLevel languageLevel;
86
87
88
89
90 @Parameter(defaultValue = "Groovy Documentation")
91 protected String header;
92
93
94
95
96 @Parameter(defaultValue = "true")
97 protected boolean displayAuthor;
98
99
100
101
102 @Parameter
103 protected File overviewFile;
104
105
106
107
108 @Parameter
109 protected File stylesheetFile;
110
111
112
113
114 @Parameter(defaultValue = "${project.build.sourceEncoding}")
115 protected String stylesheetEncoding;
116
117
118
119
120
121
122
123
124
125
126 @Parameter(defaultValue = "private")
127 protected String scope;
128
129
130
131
132
133
134 @Parameter
135 protected List<Link> links;
136
137
138
139
140
141
142 @Parameter(property = "skipGroovydoc", defaultValue = "false")
143 protected boolean skipGroovyDoc;
144
145
146
147
148
149
150
151
152
153
154
155
156 @Parameter(defaultValue = "PROJECT_ONLY")
157 protected IncludeClasspath includeClasspath;
158
159
160
161
162
163
164 @Parameter
165 protected String[] defaultDocTemplates = null;
166
167
168
169
170
171
172 @Parameter
173 protected String[] defaultPackageTemplates = null;
174
175
176
177
178
179
180 @Parameter
181 protected String[] defaultClassTemplates = null;
182
183
184
185
186
187
188
189 @Parameter
190 protected String groovyDocToolClass = null;
191
192
193
194
195
196
197
198 @Parameter
199 protected String outputToolClass = null;
200
201
202
203
204
205
206
207 @Parameter
208 protected String fileOutputToolClass = null;
209
210
211
212
213
214
215
216 @Parameter
217 protected String resourceManagerClass = null;
218
219
220
221
222
223
224
225 @Parameter
226 protected String classpathResourceManagerClass = null;
227
228
229
230
231
232
233
234
235 @Parameter
236 protected String linkArgumentClass = null;
237
238
239
240
241
242
243 @Parameter(defaultValue = "false")
244 protected boolean attachGroovyDocAnnotation;
245
246
247
248
249 @javax.inject.Inject
250 protected org.apache.maven.toolchain.ToolchainManager toolchainManager;
251
252
253
254
255 @Parameter(defaultValue = "${session}", readonly = true, required = true)
256 protected org.apache.maven.execution.MavenSession session;
257
258
259
260
261
262
263 @Parameter(property = "fork", defaultValue = "false")
264 protected boolean fork;
265
266
267
268
269
270
271
272
273
274
275
276
277
278 protected synchronized void doGroovyDocGeneration(final FileSet[] sourceDirectories, final List<?> classpath, final File outputDirectory) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException, MalformedURLException {
279 if (skipGroovyDoc) {
280 getLog().info("Skipping generation of GroovyDoc because ${skipGroovydoc} was set to true.");
281 return;
282 }
283
284 if (sourceDirectories == null || sourceDirectories.length == 0) {
285 getLog().info("No source directories specified for GroovyDoc generation. Skipping.");
286 return;
287 }
288
289 GroovyDocConfiguration configuration = new GroovyDocConfiguration(sourceDirectories, classpath, outputDirectory);
290 configuration.setIncludeClasspath(includeClasspath);
291 configuration.setDocProperties(setupProperties());
292 configuration.setLinks(links);
293
294 configuration.setAttachGroovyDocAnnotation(attachGroovyDocAnnotation);
295 configuration.setDefaultDocTemplates(defaultDocTemplates);
296 configuration.setDefaultPackageTemplates(defaultPackageTemplates);
297 configuration.setDefaultClassTemplates(defaultClassTemplates);
298 configuration.setGroovyDocToolClass(groovyDocToolClass);
299 configuration.setOutputToolClass(outputToolClass);
300 configuration.setFileOutputToolClass(fileOutputToolClass);
301 configuration.setResourceManagerClass(resourceManagerClass);
302 configuration.setClasspathResourceManagerClass(classpathResourceManagerClass);
303 configuration.setLinkArgumentClass(linkArgumentClass);
304 configuration.setWindowTitle(windowTitle);
305 configuration.setDocTitle(docTitle);
306 configuration.setFooter(footer);
307 configuration.setHeader(header);
308 configuration.setDisplayAuthor(displayAuthor);
309 configuration.setDisplayAuthor(displayAuthor);
310 configuration.setOverviewFile(overviewFile);
311 configuration.setLanguageLevel(languageLevel != null ? languageLevel.toString() : null);
312
313 configuration.setScope(scope);
314
315 org.apache.maven.toolchain.Toolchain toolchain = toolchainManager.getToolchainFromBuildContext("jdk", session);
316 if (toolchain != null) {
317 getLog().info("Toolchain in gmavenplus-plugin: " + toolchain);
318 performForkedGroovyDocGeneration(configuration, toolchain.findTool("java"));
319 } else if (fork) {
320 String javaExecutable = getJavaExecutable();
321 getLog().info("Forking GroovyDoc generation using " + javaExecutable);
322 performForkedGroovyDocGeneration(configuration, javaExecutable);
323 } else {
324 performInProcessGroovyDocGeneration(configuration);
325 }
326
327
328 if (stylesheetFile != null) {
329 copyStylesheet(outputDirectory);
330 }
331 }
332
333 protected void performInProcessGroovyDocGeneration(GroovyDocConfiguration configuration) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, InstantiationException, MalformedURLException {
334 setupClassWrangler(configuration.getClasspath(), includeClasspath);
335 classWrangler.logGroovyVersion(mojoExecution.getMojoDescriptor().getGoal());
336 logPluginClasspath();
337
338 if (!groovyVersionSupportsAction()) {
339 getLog().error("Your Groovy version (" + classWrangler.getGroovyVersionString() + ") doesn't support GroovyDoc. The minimum version of Groovy required is " + minGroovyVersion + ". Skipping GroovyDoc generation.");
340 return;
341 }
342 if (groovyIs(GROOVY_1_6_0_RC1) || groovyIs(GROOVY_1_5_8)) {
343
344 getLog().warn("Groovy " + GROOVY_1_5_8 + " and " + GROOVY_1_6_0_RC1 + " are blacklisted from the supported GroovyDoc versions because of their dependency on Ant. Skipping GroovyDoc generation.");
345 return;
346 }
347
348 GroovyCompiler compiler = new GroovyCompiler(classWrangler, getLog());
349 compiler.generateGroovyDoc(configuration);
350 }
351
352 protected void performForkedGroovyDocGeneration(GroovyDocConfiguration configuration, String javaExecutable) throws InvocationTargetException {
353 try {
354
355 File configFile = File.createTempFile("groovy-doc-config", ".ser");
356 configFile.deleteOnExit();
357 try (java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(java.nio.file.Files.newOutputStream(configFile.toPath()))) {
358 oos.writeObject(configuration);
359 }
360
361
362 String forkClasspath = buildForkClasspath();
363
364 List<String> command = new ArrayList<>();
365 command.add(javaExecutable);
366 command.add("-cp");
367 command.add(forkClasspath);
368 command.add("org.codehaus.gmavenplus.util.ForkedGroovyCompiler");
369 command.add(configFile.getAbsolutePath());
370
371 ProcessBuilder pb = new ProcessBuilder(command);
372 pb.inheritIO();
373 Process process = pb.start();
374 int exitCode = process.waitFor();
375
376 if (exitCode != 0) {
377 throw new InvocationTargetException(new RuntimeException("Forked GroovyDoc generation failed with exit code " + exitCode));
378 }
379 } catch (IOException | InterruptedException e) {
380 throw new InvocationTargetException(e);
381 }
382 }
383
384 protected String buildForkClasspath() {
385 StringBuilder cp = new StringBuilder();
386
387 cp.append(pluginDescriptor.getPluginArtifact().getFile().getAbsolutePath());
388
389
390 for (org.apache.maven.artifact.Artifact artifact : pluginDescriptor.getArtifacts()) {
391 cp.append(File.pathSeparator);
392 cp.append(artifact.getFile().getAbsolutePath());
393 }
394
395
396 try {
397 Class<?> logClass = org.apache.maven.plugin.logging.Log.class;
398 java.security.CodeSource codeSource = logClass.getProtectionDomain().getCodeSource();
399 if (codeSource != null) {
400 String logJar = new File(codeSource.getLocation().toURI()).getAbsolutePath();
401 cp.append(File.pathSeparator).append(logJar);
402 }
403 } catch (Exception e) {
404 getLog().warn("Could not find maven-plugin-api jar to add to fork classpath", e);
405 }
406
407 return cp.toString();
408 }
409
410
411
412
413
414
415 protected Properties setupProperties() {
416 Properties properties = new Properties();
417 properties.setProperty("windowTitle", windowTitle);
418 properties.setProperty("docTitle", docTitle);
419 properties.setProperty("footer", footer);
420 properties.setProperty("header", header);
421 properties.setProperty("author", Boolean.toString(displayAuthor));
422 properties.setProperty("overviewFile", overviewFile != null ? overviewFile.getAbsolutePath() : "");
423 try {
424 Scopes scopeVal = Scopes.valueOf(scope.toUpperCase());
425 if (scopeVal.equals(Scopes.PUBLIC)) {
426 properties.setProperty("publicScope", "true");
427 } else if (scopeVal.equals(Scopes.PROTECTED)) {
428 properties.setProperty("protectedScope", "true");
429 } else if (scopeVal.equals(Scopes.PACKAGE)) {
430 properties.setProperty("packageScope", "true");
431 } else if (scopeVal.equals(Scopes.PRIVATE)) {
432 properties.setProperty("privateScope", "true");
433 }
434 } catch (IllegalArgumentException e) {
435 getLog().warn("Scope (" + scope + ") was not recognized. Skipping argument.");
436 }
437
438 return properties;
439 }
440
441
442
443
444
445
446
447 protected void copyStylesheet(final File outputDirectory) {
448 getLog().info("Using stylesheet from " + stylesheetFile.getAbsolutePath() + ".");
449 try {
450 BufferedReader bufferedReader = null;
451 BufferedWriter bufferedWriter = null;
452 try {
453 if (stylesheetEncoding != null) {
454 bufferedReader = new BufferedReader(new InputStreamReader(Files.newInputStream(stylesheetFile.toPath()), stylesheetEncoding));
455 } else {
456 bufferedReader = new BufferedReader(new InputStreamReader(Files.newInputStream(stylesheetFile.toPath())));
457 }
458 StringBuilder css = new StringBuilder();
459 String line;
460 while ((line = bufferedReader.readLine()) != null) {
461 css.append(line).append("\n");
462 }
463 File outfile = new File(outputDirectory, "stylesheet.css");
464 if (stylesheetEncoding != null) {
465 bufferedWriter = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(outfile.toPath()), stylesheetEncoding));
466 } else {
467 bufferedWriter = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(outfile.toPath())));
468 }
469 bufferedWriter.write(css.toString());
470 } finally {
471 FileUtils.closeQuietly(bufferedReader);
472 FileUtils.closeQuietly(bufferedWriter);
473 }
474 } catch (IOException e) {
475 getLog().warn("Unable to copy specified stylesheet (" + stylesheetFile.getAbsolutePath() + ").");
476 }
477 }
478
479 }