1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org_scala_tools_maven;
17
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.List;
21 import java.util.Set;
22
23 import org.apache.maven.artifact.Artifact;
24 import org.apache.maven.artifact.ArtifactUtils;
25 import org.apache.maven.artifact.factory.ArtifactFactory;
26 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
27 import org.apache.maven.artifact.repository.ArtifactRepository;
28 import org.apache.maven.artifact.resolver.ArtifactCollector;
29 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
30 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
31 import org.apache.maven.artifact.resolver.ArtifactResolver;
32 import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
33 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
34 import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
35 import org.apache.maven.model.Dependency;
36 import org.apache.maven.plugin.AbstractMojo;
37 import org.apache.maven.plugin.MojoExecutionException;
38 import org.apache.maven.plugin.MojoFailureException;
39 import org.apache.maven.project.MavenProject;
40 import org.apache.maven.project.MavenProjectBuilder;
41 import org.apache.maven.project.ProjectBuildingException;
42 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
43 import org.apache.maven.shared.dependency.tree.DependencyNode;
44 import org.apache.maven.shared.dependency.tree.DependencyTreeBuilder;
45 import org.apache.maven.shared.dependency.tree.filter.AncestorOrSelfDependencyNodeFilter;
46 import org.apache.maven.shared.dependency.tree.filter.AndDependencyNodeFilter;
47 import org.apache.maven.shared.dependency.tree.filter.DependencyNodeFilter;
48 import org.apache.maven.shared.dependency.tree.traversal.CollectingDependencyNodeVisitor;
49 import org.apache.maven.shared.dependency.tree.traversal.DependencyNodeVisitor;
50 import org.apache.maven.shared.dependency.tree.traversal.FilteringDependencyNodeVisitor;
51 import org.codehaus.plexus.util.StringUtils;
52 import org_scala_tools_maven_dependency.CheckScalaVersionVisitor;
53 import org_scala_tools_maven_dependency.ScalaDistroArtifactFilter;
54 import org_scala_tools_maven_executions.JavaMainCaller;
55 import org_scala_tools_maven_executions.JavaMainCallerByFork;
56 import org_scala_tools_maven_executions.JavaMainCallerInProcess;
57 import org_scala_tools_maven_executions.MainHelper;
58
59 public abstract class ScalaMojoSupport extends AbstractMojo {
60
61 public static final String SCALA_GROUPID= "org.scala-lang";
62 public static final String SCALA_LIBRARY_ARTIFACTID= "scala-library";
63
64
65
66
67
68 protected MavenProject project;
69
70
71
72
73
74
75
76
77 protected ArtifactFactory factory;
78
79
80
81
82
83
84
85
86 protected ArtifactResolver resolver;
87
88
89
90
91
92
93
94 protected ArtifactRepository localRepo;
95
96
97
98
99
100
101
102
103 protected List<?> remoteRepos;
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119 protected BasicArtifact[] dependencies;
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135 protected BasicArtifact[] compilerPlugins;
136
137
138
139
140
141
142 protected String[] jvmArgs;
143
144
145
146
147
148
149 protected String[] args;
150
151
152
153
154
155
156
157
158 protected String scalaClassName;
159
160
161
162
163
164
165
166 private String scalaVersion;
167
168
169
170
171
172
173
174
175
176 public boolean displayCmd;
177
178
179
180
181
182
183 protected boolean fork = true;
184
185
186
187
188
189
190 protected boolean forceUseArgFile = false;
191
192
193
194
195
196
197 protected boolean checkMultipleScalaVersions;
198
199
200
201
202
203
204 protected boolean failOnMultipleScalaVersions = false;
205
206
207
208
209
210
211
212 protected MavenProjectBuilder mavenProjectBuilder;
213
214
215
216
217
218
219
220
221 private ArtifactRepository localRepository;
222
223
224
225
226
227
228
229
230 private ArtifactFactory artifactFactory;
231
232
233
234
235
236
237
238
239 private ArtifactMetadataSource artifactMetadataSource;
240
241
242
243
244
245
246
247
248 private ArtifactCollector artifactCollector;
249
250
251
252
253
254
255
256
257 private DependencyTreeBuilder dependencyTreeBuilder;
258
259 private VersionNumber _scalaVersionN;
260
261
262
263
264
265
266
267
268
269
270
271 @SuppressWarnings("unchecked")
272 protected Set<Artifact> resolveDependencyArtifacts(MavenProject theProject) throws Exception {
273 AndArtifactFilter filter = new AndArtifactFilter();
274 filter.add(new ScopeArtifactFilter(Artifact.SCOPE_TEST));
275 filter.add(new ArtifactFilter(){
276 public boolean include(Artifact artifact) {
277 return !artifact.isOptional();
278 }
279 });
280
281 Set<Artifact> artifacts = theProject.createArtifacts(factory, Artifact.SCOPE_RUNTIME, filter);
282 for (Artifact artifact : artifacts) {
283 resolver.resolve(artifact, remoteRepos, localRepo);
284 }
285 return artifacts;
286 }
287
288
289
290
291
292
293
294
295
296
297
298
299
300 protected Set<Artifact> resolveArtifactDependencies(Artifact artifact) throws Exception {
301 Artifact pomArtifact = factory.createArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), "", "pom");
302 MavenProject pomProject = mavenProjectBuilder.buildFromRepository(pomArtifact, remoteRepos, localRepo);
303 return resolveDependencyArtifacts(pomProject);
304 }
305
306 public void addToClasspath(String groupId, String artifactId, String version, Set<String> classpath) throws Exception {
307 addToClasspath(groupId, artifactId, version, classpath, true);
308 }
309
310
311 public void addToClasspath(String groupId, String artifactId, String version, Set<String> classpath, boolean addDependencies) throws Exception {
312 addToClasspath(factory.createArtifact(groupId, artifactId, version, Artifact.SCOPE_RUNTIME, "jar"), classpath, addDependencies);
313 }
314
315 protected void addToClasspath(Artifact artifact, Set<String> classpath, boolean addDependencies) throws Exception {
316 resolver.resolve(artifact, remoteRepos, localRepo);
317 classpath.add(artifact.getFile().getCanonicalPath());
318 if (addDependencies) {
319 for (Artifact dep : resolveArtifactDependencies(artifact)) {
320
321 addToClasspath(dep, classpath, addDependencies);
322 }
323 }
324 }
325
326 public void execute() throws MojoExecutionException, MojoFailureException {
327 try {
328 String oldWay = System.getProperty("maven.scala.version");
329 if (oldWay != null) {
330 getLog().warn("using 'maven.scala.version' is deprecated, use 'scala.version' instead");
331 if (scalaVersion != null) {
332 scalaVersion = oldWay;
333 }
334 }
335
336 oldWay = System.getProperty("maven.scala.displayCmd");
337 if (oldWay != null) {
338 getLog().warn("using 'maven.scala.displayCmd' is deprecated, use 'displayCmd' instead");
339 displayCmd = displayCmd || Boolean.parseBoolean(oldWay);
340 }
341 checkScalaVersion();
342 doExecute();
343 } catch (MojoExecutionException exc) {
344 throw exc;
345 } catch (MojoFailureException exc) {
346 throw exc;
347 } catch (RuntimeException exc) {
348 throw exc;
349 } catch (Exception exc) {
350 throw new MojoExecutionException("wrap: " + exc, exc);
351 }
352 }
353
354 @SuppressWarnings("unchecked")
355 protected List<Dependency> getDependencies() {
356 return project.getCompileDependencies();
357 }
358
359 protected VersionNumber findScalaVersion() throws Exception {
360 if (_scalaVersionN == null) {
361 String detectedScalaVersion = scalaVersion;
362 if (StringUtils.isEmpty(detectedScalaVersion)) {
363 detectedScalaVersion = findScalaVersionFromDependencies();
364 }
365 if (StringUtils.isEmpty(detectedScalaVersion)) {
366 if (!"pom".equals( project.getPackaging().toLowerCase() )) {
367 getLog().warn("you don't define "+SCALA_GROUPID + ":" + SCALA_LIBRARY_ARTIFACTID + " as a dependency of the project");
368 }
369 detectedScalaVersion = "0.0.0";
370 } else {
371
372
373
374
375 boolean isSnapshot = ArtifactUtils.isSnapshot(detectedScalaVersion);
376 if (isSnapshot && !detectedScalaVersion.endsWith("-SNAPSHOT")) {
377 detectedScalaVersion = detectedScalaVersion.substring(0, detectedScalaVersion.lastIndexOf('-', detectedScalaVersion.lastIndexOf('-')-1)) + "-SNAPSHOT";
378 }
379 }
380 if (StringUtils.isEmpty(detectedScalaVersion)) {
381 throw new MojoFailureException("no scalaVersion detected or set");
382 }
383 if (StringUtils.isNotEmpty(scalaVersion)) {
384 if (!scalaVersion.equals(detectedScalaVersion)) {
385 getLog().warn("scala library version define in dependencies doesn't match the scalaVersion of the plugin");
386 }
387
388 }
389 _scalaVersionN = new VersionNumber(detectedScalaVersion);
390 }
391 return _scalaVersionN;
392 }
393
394
395 private String findScalaVersionFromDependencies() throws Exception {
396 String detectedScalaVersion = null;
397 for (Dependency dep : getDependencies()) {
398 if (SCALA_GROUPID.equals(dep.getGroupId()) && SCALA_LIBRARY_ARTIFACTID.equals(dep.getArtifactId())) {
399 detectedScalaVersion = dep.getVersion();
400 }
401 }
402 if (StringUtils.isEmpty(detectedScalaVersion)) {
403 List<Dependency> deps = new ArrayList<Dependency>();
404 deps.addAll(project.getModel().getDependencies());
405 if (project.getModel().getDependencyManagement() != null) {
406 deps.addAll(project.getModel().getDependencyManagement().getDependencies());
407 }
408 for (Dependency dep : deps) {
409 if (SCALA_GROUPID.equals(dep.getGroupId()) && SCALA_LIBRARY_ARTIFACTID.equals(dep.getArtifactId())) {
410 detectedScalaVersion = dep.getVersion();
411 }
412 }
413 }
414 return detectedScalaVersion;
415 }
416
417 protected void checkScalaVersion() throws Exception {
418 if (checkMultipleScalaVersions) {
419 checkCorrectVersionsOfScalaLibrary(findScalaVersion().toString());
420 }
421 }
422
423
424
425 private void checkCorrectVersionsOfScalaLibrary(String requiredScalaVersion) throws Exception {
426 getLog().info("Checking for multiple versions of scala");
427
428
429 checkArtifactForScalaVersion(requiredScalaVersion, dependencyTreeBuilder.buildDependencyTree( project, localRepository, artifactFactory,
430 artifactMetadataSource, null, artifactCollector ));
431 }
432
433
434
435 private void checkArtifactForScalaVersion(String requiredScalaVersion, DependencyNode rootNode) throws Exception {
436 final CheckScalaVersionVisitor visitor = new CheckScalaVersionVisitor(requiredScalaVersion, getLog());
437
438 CollectingDependencyNodeVisitor collectingVisitor = new CollectingDependencyNodeVisitor();
439 DependencyNodeVisitor firstPassVisitor = new FilteringDependencyNodeVisitor( collectingVisitor, createScalaDistroDependencyFilter() );
440 rootNode.accept( firstPassVisitor );
441
442 DependencyNodeFilter secondPassFilter = new AncestorOrSelfDependencyNodeFilter( collectingVisitor.getNodes() );
443 DependencyNodeVisitor filteredVisitor = new FilteringDependencyNodeVisitor( visitor, secondPassFilter );
444
445 rootNode.accept( filteredVisitor );
446
447 if(visitor.isFailed()) {
448 visitor.logScalaDependents();
449 if(failOnMultipleScalaVersions) {
450 getLog().error("Multiple versions of scala libraries detected!");
451 throw new MojoFailureException("Multiple versions of scala libraries detected!");
452 }
453 getLog().warn("Multiple versions of scala libraries detected!");
454 }
455 }
456
457
458
459
460
461 private DependencyNodeFilter createScalaDistroDependencyFilter() {
462 List<ArtifactFilter> filters = new ArrayList<ArtifactFilter>();
463 filters.add(new ScalaDistroArtifactFilter());
464 return new AndDependencyNodeFilter(filters);
465 }
466
467
468
469 protected abstract void doExecute() throws Exception;
470
471
472 protected JavaMainCaller getScalaCommand() throws Exception {
473 JavaMainCaller cmd = getEmptyScalaCommand(scalaClassName);
474 cmd.addArgs(args);
475 addCompilerPluginOptions(cmd);
476 cmd.addJvmArgs(jvmArgs);
477 return cmd;
478 }
479
480 protected JavaMainCaller getEmptyScalaCommand(String mainClass) throws Exception {
481
482 JavaMainCaller cmd;
483 if(fork) {
484
485
486
487 getLog().debug("use java command with args in file forced : " + forceUseArgFile);
488 cmd = new JavaMainCallerByFork(this, mainClass, getToolClasspath(), null, null, forceUseArgFile);
489 } else {
490 cmd = new JavaMainCallerInProcess(this, mainClass, getToolClasspath(), null, null);
491 }
492 cmd.addJvmArgs("-Xbootclasspath/a:"+ getBootClasspath());
493 return cmd;
494 }
495
496 private String getToolClasspath() throws Exception {
497 Set<String> classpath = new HashSet<String>();
498 addToClasspath(SCALA_GROUPID, "scala-compiler", findScalaVersion().toString(), classpath);
499
500
501 if (dependencies != null) {
502 for(BasicArtifact artifact: dependencies) {
503 addToClasspath(artifact.groupId, artifact.artifactId, artifact.version, classpath);
504 }
505 }
506 return MainHelper.toMultiPath(classpath.toArray(new String[classpath.size()]));
507 }
508
509 private String getBootClasspath() throws Exception {
510 Set<String> classpath = new HashSet<String>();
511 addToClasspath(SCALA_GROUPID, SCALA_LIBRARY_ARTIFACTID, findScalaVersion().toString(), classpath);
512 return MainHelper.toMultiPath(classpath.toArray(new String[classpath.size()]));
513 }
514
515
516
517
518
519 protected boolean isJavaSupportedByCompiler() throws Exception {
520 return findScalaVersion().compareTo(new VersionNumber("2.7.2")) >= 0;
521 }
522
523
524
525
526
527
528
529 protected void addCompilerPluginOptions(JavaMainCaller scalac) throws Exception {
530 for (String plugin : getCompilerPlugins()) {
531 scalac.addArgs("-Xplugin:" + plugin);
532 }
533 }
534
535
536
537
538
539
540 private Set<String> getCompilerPlugins() throws Exception {
541 Set<String> plugins = new HashSet<String>();
542 if (compilerPlugins != null) {
543 Set<String> ignoreClasspath = new HashSet<String>();
544 String sv = findScalaVersion().toString();
545 addToClasspath(SCALA_GROUPID, "scala-compiler", sv, ignoreClasspath);
546 addToClasspath(SCALA_GROUPID, SCALA_LIBRARY_ARTIFACTID, sv, ignoreClasspath);
547 for (BasicArtifact artifact : compilerPlugins) {
548 getLog().info("compiler plugin: " + artifact.toString());
549
550 Set<String> pluginClassPath = new HashSet<String>();
551
552 addToClasspath(artifact.groupId, artifact.artifactId, artifact.version, pluginClassPath, false);
553 pluginClassPath.removeAll(ignoreClasspath);
554 plugins.addAll(pluginClassPath);
555 }
556 }
557 return plugins;
558 }
559
560
561 }