1 package org.codehaus.mojo.gwt.shell;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import org.apache.maven.artifact.Artifact;
27 import org.apache.maven.plugin.MojoExecutionException;
28 import org.apache.maven.plugin.MojoFailureException;
29 import org.apache.maven.plugins.annotations.LifecyclePhase;
30 import org.apache.maven.plugins.annotations.Mojo;
31 import org.apache.maven.plugins.annotations.Parameter;
32 import org.apache.maven.plugins.annotations.ResolutionScope;
33 import org.codehaus.mojo.gwt.GwtModule;
34 import org.codehaus.mojo.gwt.utils.GwtModuleReaderException;
35 import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
36 import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
37 import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping;
38 import org.codehaus.plexus.util.StringUtils;
39
40 import java.io.File;
41 import java.util.Collection;
42 import java.util.HashSet;
43
44
45
46
47
48
49
50
51
52
53
54
55 @Mojo(name = "compile", defaultPhase = LifecyclePhase.PREPARE_PACKAGE, requiresDependencyResolution = ResolutionScope.COMPILE, threadSafe = true)
56 public class CompileMojo
57 extends AbstractGwtShellMojo
58 {
59
60 @Parameter(property = "gwt.compiler.skip", defaultValue = "false")
61 private boolean skip;
62
63
64
65
66
67
68 @Parameter(property = "gwt.compiler.force", defaultValue = "false")
69 private boolean force;
70
71
72
73
74
75
76
77
78
79 @Parameter(property = "gwt.compiler.localWorkers")
80 private int localWorkers;
81
82
83
84
85 @Parameter(alias = "enableAssertions", defaultValue = "false")
86 private boolean checkAssertions;
87
88
89
90
91
92
93
94 @Parameter(defaultValue = "false", property = "gwt.disableClassMetadata")
95 private boolean disableClassMetadata;
96
97
98
99
100
101
102
103 @Parameter(defaultValue = "false", property = "gwt.disableCastChecking")
104 private boolean disableCastChecking;
105
106
107
108
109
110
111
112 @Parameter(defaultValue = "false", property = "gwt.disableRunAsync")
113 private boolean disableRunAsync;
114
115
116
117
118
119
120
121 @Parameter(defaultValue = "false", property = "gwt.validateOnly")
122 private boolean validateOnly;
123
124
125
126
127
128
129
130 @Parameter(defaultValue = "false", property = "gwt.draftCompile")
131 private boolean draftCompile;
132
133
134
135
136 @Parameter(defaultValue = "${project.build.directory}/extra")
137 private File extra;
138
139
140
141
142 @Parameter
143 private File workDir;
144
145
146
147
148
149
150
151
152 @Parameter(defaultValue = "false", property = "gwt.extraParam")
153 private boolean extraParam;
154
155
156
157
158
159
160
161
162
163 @Parameter(defaultValue = "false", property = "gwt.compiler.compileReport")
164 private boolean compileReport;
165
166
167
168
169
170
171
172
173
174
175
176
177 @Parameter(defaultValue = "-1", property = "gwt.compiler.optimizationLevel")
178 private int optimizationLevel;
179
180
181
182
183
184
185
186
187
188 @Parameter(alias = "soycDetailed", defaultValue = "false", property = "gwt.compiler.soycDetailed")
189 private boolean detailedSoyc;
190
191
192
193
194
195
196
197
198
199
200 @Parameter(alias = "strict", defaultValue = "false", property = "gwt.compiler.strict")
201 private boolean failOnError;
202
203
204
205
206
207
208
209
210
211
212 @Parameter(alias = "enableClosureCompiler", defaultValue = "false", property = "gwt.compiler.enableClosureCompiler")
213 private boolean closureCompiler;
214
215
216
217
218
219
220 @Parameter(defaultValue = "false", property = "gwt.compiler.closureFormattedOutput")
221 private boolean closureFormattedOutput;
222
223
224
225
226
227
228
229
230
231 @Parameter(defaultValue = "false", property = "gwt.compiler.compilerMetrics")
232 private boolean compilerMetrics;
233
234
235
236
237
238
239
240
241
242 @Parameter(defaultValue = "-1", property = "gwt.compiler.fragmentCount")
243 private int fragmentCount;
244
245
246
247
248
249
250 @Parameter(defaultValue = "true", property = "gwt.compiler.clusterFunctions")
251 private boolean clusterFunctions;
252
253
254
255
256
257
258
259 @Parameter(defaultValue = "true", property = "gwt.compiler.inlineLiteralParameters")
260 private boolean inlineLiteralParameters;
261
262
263
264
265
266
267 @Parameter(defaultValue = "true", property = "gwt.compiler.optimizeDataflow")
268 private boolean optimizeDataflow;
269
270
271
272
273
274
275 @Parameter(defaultValue = "false", property = "gwt.compiler.generateJsInteropExports")
276 private boolean generateJsInteropExports;
277
278
279
280
281
282
283 @Parameter(defaultValue = "true", property = "gwt.compiler.ordinalizeEnums")
284 private boolean ordinalizeEnums;
285
286
287
288
289
290
291
292
293 @Parameter(defaultValue = "true", property = "gwt.compiler.removeDuplicateFunctions")
294 private boolean removeDuplicateFunctions;
295
296
297
298
299
300
301 @Parameter(defaultValue = "false", property = "gwt.saveSource")
302 private boolean saveSource;
303
304
305
306
307
308
309
310
311 @Parameter
312 private File saveSourceOutput;
313
314
315
316
317
318
319 @Parameter(defaultValue = "auto", property = "maven.compiler.source")
320 private String sourceLevel;
321
322
323
324
325
326
327
328
329
330
331 @Parameter
332 private String namespace;
333
334 @Parameter(defaultValue = "false")
335 private boolean overlappingSourceWarnings;
336
337
338
339
340
341
342 @Parameter(defaultValue = "false")
343 private boolean enableJsonSoyc;
344
345
346
347
348
349
350 @Parameter(alias = "compilePerFile", defaultValue = "false", property = "gwt.compiler.incremental")
351 private boolean incremental;
352
353
354
355
356
357
358
359
360 @Parameter(defaultValue = "NONE", property = "gwt.compiler.methodNameDisplayMode")
361 private String methodNameDisplayMode;
362
363
364
365
366
367
368
369
370 @Parameter(defaultValue = "true", property = "gwt.compiler.printJavaCommandOnError" )
371 private boolean printJavaCommandOnError;
372
373 public void doExecute( )
374 throws MojoExecutionException, MojoFailureException
375 {
376 if ( skip || "pom".equals( getProject().getPackaging() ) )
377 {
378 getLog().info( "GWT compilation is skipped" );
379 return;
380 }
381
382 if ( !this.getOutputDirectory().exists() )
383 {
384 this.getOutputDirectory().mkdirs();
385 }
386
387 compile( getModules() );
388 }
389
390 @Override
391 protected String getExtraJvmArgs()
392 {
393 String jvmArgs = super.getExtraJvmArgs();
394
395
396 if ( System.getProperty( "java.vendor" ).startsWith( "IBM" ) && StringUtils.isEmpty(getJvm()) && !StringUtils.isEmpty( jvmArgs ))
397 {
398 return jvmArgs + " -Dgwt.jjs.javaArgs=" + StringUtils.quoteAndEscape( jvmArgs, '"', new char[] { '"', ' ', '\t', '\r', '\n' } );
399 }
400 return jvmArgs;
401 }
402
403 private void compile( String[] modules )
404 throws MojoExecutionException
405 {
406 boolean upToDate = true;
407
408 JavaCommand cmd = createJavaCommand()
409 .setMainClass( "com.google.gwt.dev.Compiler" );
410 if ( gwtSdkFirstInClasspath )
411 {
412 cmd.addToClasspath( getGwtUserJar() )
413 .addToClasspath( getGwtDevJar() );
414 }
415 cmd.addToClasspath( getClasspath( Artifact.SCOPE_COMPILE ) );
416 if ( !gwtSdkFirstInClasspath )
417 {
418 cmd.addToClasspath( getGwtUserJar() )
419 .addToClasspath( getGwtDevJar() );
420 }
421
422 cmd.arg( "-logLevel", getLogLevel() )
423 .arg( "-war", getOutputDirectory().getAbsolutePath() )
424 .arg( "-localWorkers", String.valueOf( getLocalWorkers() ) )
425
426 .arg( checkAssertions, "-checkAssertions" )
427 .arg( draftCompile, "-draftCompile" )
428 .arg( validateOnly, "-validateOnly" )
429 .arg( disableClassMetadata, "-XnoclassMetadata" )
430 .arg( disableCastChecking, "-XnocheckCasts" )
431 .arg( disableRunAsync, "-XnocodeSplitting" )
432 .arg( failOnError, "-failOnError" )
433 .arg( detailedSoyc, "-XdetailedSoyc" )
434 .arg( closureCompiler, "-XclosureCompiler" )
435 .arg( closureFormattedOutput, "-XclosureFormattedOutput" )
436 .arg( compileReport, "-compileReport" )
437 .arg( compilerMetrics, "-XcompilerMetrics" )
438 .arg( "-XfragmentCount", String.valueOf( fragmentCount ) )
439 .arg( !clusterFunctions, "-XnoclusterFunctions" )
440 .arg( !inlineLiteralParameters, "-XnoinlineLiteralParameters" )
441 .arg( !optimizeDataflow, "-XnooptimizeDataflow" )
442 .arg( !ordinalizeEnums, "-XnoordinalizeEnums" )
443 .arg( !removeDuplicateFunctions, "-XnoremoveDuplicateFunctions" )
444 .arg( saveSource, "-saveSource" )
445 .arg( "-sourceLevel", sourceLevel )
446 .arg( enableJsonSoyc, "-XenableJsonSoyc" )
447 .arg( incremental, "-incremental" )
448 .arg( generateJsInteropExports, "-generateJsInteropExports" )
449 ;
450
451 if ( style != null && style.length() > 0 )
452 {
453 cmd.arg( "-style", style );
454 }
455
456 if ( methodNameDisplayMode != null && methodNameDisplayMode.length() > 0 && !methodNameDisplayMode.equals( "NONE" ))
457 {
458 cmd.arg( "-XmethodNameDisplayMode", methodNameDisplayMode );
459 }
460
461 if ( namespace != null && namespace.length() > 0 )
462 {
463 cmd.arg( "-Xnamespace", namespace );
464 }
465
466 if ( saveSourceOutput != null )
467 {
468 cmd.arg( "-saveSourceOutput", saveSourceOutput.getAbsolutePath() );
469 }
470
471 if ( optimizationLevel >= 0 )
472 {
473 cmd.arg( "-optimize" ).arg( Integer.toString( optimizationLevel ) );
474 }
475
476 if ( extraParam || compileReport || ( saveSource && saveSourceOutput == null ) )
477 {
478 getLog().debug( "create extra directory " );
479 if ( !extra.exists() )
480 {
481 extra.mkdirs();
482 }
483 cmd.arg( "-extra" ).arg( extra.getAbsolutePath() );
484 }
485 else
486 {
487 getLog().debug( "NOT create extra directory " );
488 }
489
490 addCompileSourceArtifacts( cmd );
491 addArgumentDeploy(cmd);
492 addArgumentGen( cmd );
493 addPersistentUnitCache(cmd);
494
495 if ( workDir != null )
496 {
497 cmd.arg( "-workDir" ).arg( String.valueOf( workDir ) );
498 }
499
500 for ( String target : modules )
501 {
502 if ( !compilationRequired( target, getOutputDirectory() ) )
503 {
504 continue;
505 }
506 cmd.arg( target );
507 upToDate = false;
508 }
509
510 cmd.setPrintCommandOnError(printJavaCommandOnError);
511
512 if ( !upToDate )
513 {
514 try
515 {
516 cmd.execute();
517 }
518 catch ( JavaCommandException e )
519 {
520 throw new MojoExecutionException( e.getMessage(), e );
521 }
522 }
523 }
524
525 private int getLocalWorkers()
526 {
527 if ( localWorkers > 0 )
528 {
529 return localWorkers;
530 }
531 return Runtime.getRuntime().availableProcessors();
532 }
533
534
535
536
537
538
539
540
541
542
543
544
545 private boolean compilationRequired( String module, File output )
546 throws MojoExecutionException
547 {
548 getLog().debug( "**Checking if compilation is required for " + module );
549 try
550 {
551
552 GwtModule gwtModule = readModule( module );
553 if ( gwtModule.getEntryPoints().size() == 0 )
554 {
555 getLog().info( gwtModule.getName() + " has no EntryPoint - compilation skipped" );
556
557
558 return false;
559 }
560 getLog().debug( "Module has an entrypoint" );
561
562 if ( force )
563 {
564 return true;
565 }
566 getLog().debug( "Compilation not forced");
567
568 String modulePath = gwtModule.getPath();
569
570 String outputTarget = modulePath + "/" + modulePath + ".nocache.js";
571 File outputTargetFile = new File( output, outputTarget );
572
573 if ( !outputTargetFile.exists() )
574 {
575 return true;
576 }
577 getLog().debug( "Output file exists");
578
579 File moduleFile = gwtModule.getSourceFile();
580 if(moduleFile == null) {
581 return true;
582 }
583 getLog().debug( "There is a module source file (not an input stream");
584
585
586 if(moduleFile.lastModified() > outputTargetFile.lastModified())
587 {
588 getLog().debug( "Module file has been modified since the output file was created; recompiling" );
589 return true;
590 }
591 getLog().debug( "The module XML hasn't been updated");
592
593
594 SingleTargetSourceMapping singleTargetMapping = new SingleTargetSourceMapping( ".java", outputTarget );
595 StaleSourceScanner scanner = new StaleSourceScanner();
596 scanner.addSourceMapping( singleTargetMapping );
597
598 SingleTargetSourceMapping uiBinderMapping = new SingleTargetSourceMapping( ".ui.xml", outputTarget );
599 scanner.addSourceMapping( uiBinderMapping );
600
601 Collection<File> compileSourceRoots = new HashSet<File>();
602 for (String sourceRoot : getProject().getCompileSourceRoots()) {
603 for (String sourcePackage : gwtModule.getSources()) {
604 String packagePath = gwtModule.getPackage().replace( '.', File.separatorChar );
605 File sourceDirectory = new File (sourceRoot + File.separatorChar + packagePath + File.separator + sourcePackage);
606 if(sourceDirectory.exists()) {
607 getLog().debug(" Looking in a source directory "+sourceDirectory.getAbsolutePath() + " for possible changes");
608 compileSourceRoots.add(sourceDirectory);
609 }
610 }
611 }
612
613 for ( File sourceRoot : compileSourceRoots )
614 {
615 if ( !sourceRoot.isDirectory() )
616 {
617 continue;
618 }
619 try
620 {
621 if ( !scanner.getIncludedSources( sourceRoot, output ).isEmpty() )
622 {
623 getLog().debug( "found stale source in " + sourceRoot + " compared with " + output );
624 return true;
625 }
626 }
627 catch ( InclusionScanException e )
628 {
629 throw new MojoExecutionException( "Error scanning source root: \'" + sourceRoot + "\' "
630 + "for stale files to recompile.", e );
631 }
632 }
633 getLog().info( module + " is up to date. GWT compilation skipped" );
634 return false;
635 }
636 catch ( GwtModuleReaderException e )
637 {
638 throw new MojoExecutionException( e.getMessage(), e );
639 }
640 }
641 }