com.google.code.sbt.compiler.plugin.AbstractSBTCompileMojo Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2013-2017 Grzegorz Slowikowski (gslowikowski at gmail dot com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.google.code.sbt.compiler.plugin;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.DirectoryScanner;
import com.google.code.sbt.compiler.api.Compiler;
import com.google.code.sbt.compiler.api.CompilerConfiguration;
import com.google.code.sbt.compiler.api.CompilerException;
import com.google.code.sbt.compiler.api.Compilers;
import com.google.code.sbt.compiler.api.SourcePositionMapper;
/**
* Abstract base class for SBT compilation mojos.
*
* @author Grzegorz Slowikowski
*/
public abstract class AbstractSBTCompileMojo
extends AbstractMojo
{
/**
* Scala artifacts "groupId".
*/
private static final String SCALA_GROUPID = "org.scala-lang";
/**
* Scala library "artifactId".
*/
private static final String SCALA_LIBRARY_ARTIFACTID = "scala-library";
/**
* Scala compiler "artifactId".
*/
private static final String SCALA_COMPILER_ARTIFACTID = "scala-compiler";
/**
* SBT artifacts "groupId".
*/
private static final String SBT_GROUP_ID = "com.typesafe.sbt";
/**
* SBT compile interface "artifactId".
*/
private static final String COMPILER_INTERFACE_ARTIFACT_ID = "compiler-interface";
/**
* SBT compile interface sources "classifier".
*/
private static final String COMPILER_INTERFACE_CLASSIFIER = "sources";
/**
* SBT interface "artifactId".
*/
private static final String XSBTI_ARTIFACT_ID = "sbt-interface";
/**
* Forced Scala version.
*
* If specified, this version of Scala compiler is used for compilation.
* If not specified, version of project's {@code org.scala-lang:scala-library} dependency is used.
* If there is no {@code org.scala-lang:scala-library} dependency in the project (in Java only projects),
* selected compiler's {@link Compiler#getDefaultScalaVersion()} is used.
*
* @since 1.0.0
*/
@Parameter( property = "scala.version" )
protected String scalaVersion;
/**
* Forced SBT version.
*
* Used to automatically select one of the "well known" SBT compilers if no compiler added explicitly as plugin's dependency.
* There are three cases possible:
*
* -
* If {@link #sbtVersion} is specified, compatible {@link Compiler} implementation
* is selected and configured to use {@link #sbtVersion} SBT version for compilation.
*
* -
* If {@link #sbtVersion} is not specified, and {@link #playVersion} is specified
* {@link #playVersion} parameter value is used to indirectly select compatible {@link Compiler} implementation
* and it's {@link Compiler#getDefaultSbtVersion()} SBT version used for compilation.
*
* -
* If both {@link #sbtVersion} and {@link #playVersion} are not specified
* the most recent {@link Compiler} implementation is selected
* and it's {@link Compiler#getDefaultSbtVersion()} SBT version used for compilation.
*
*
*
* @since 1.0.0
*/
@Parameter( property = "sbt.version" )
protected String sbtVersion;
/**
* Forced Play! Framework version.
*
*
* Used to select SBT version in Play! Framework projects based on framework version used.
* See {@link #sbtVersion} for more details.
*
* @since 1.0.0
*/
@Parameter( property = "play2.version" )
protected String playVersion;
/**
* Scala and Java source files encoding.
*
*
* If not specified, the encoding value will be the value of the {@code file.encoding} system property.
*
*
* {@code -encoding} option in {@link #scalacOptions} or {@link #javacOptions}
* overrides this parameter for Scala or Java compiler respectively.
*
* @since 1.0.0
*/
@Parameter( property = "project.build.sourceEncoding" )
protected String sourceEncoding;
/**
* Additional parameters for Java compiler.
*
*
* Space-separated list of parameters. Parameters containing spaces can be enclosed in apostrophes or quotes.
*
* @since 1.0.0
*/
@Parameter( property = "sbt.javacOptions", defaultValue = "-g" )
protected String javacOptions;
/**
* Additional parameters for Scala compiler.
*
*
* Space-separated list of parameters. Parameters containing spaces can be enclosed in apostrophes or quotes.
*
* @since 1.0.0
*/
@Parameter( property = "sbt.scalacOptions", defaultValue = "-deprecation -unchecked" )
protected String scalacOptions;
/**
* Additional parameters for Scala compiler.
*
* For internal use only.
*/
@Parameter( property = "sbt._scalacOptions", defaultValue = "", readonly = true )
protected String _scalacOptions;
/**
* Scala compiler plugins.
*
*
* Space-separated list of plugin definitions in {@code groupId:artifactId:version} format.
*
* @since 1.0.0
*/
@Parameter( property = "sbt.scalacPlugins", defaultValue = "" )
protected String scalacPlugins;
/**
* Scala compiler plugins.
*
* For internal use only.
*/
@Parameter( property = "sbt._scalacPlugins", defaultValue = "", readonly = true )
protected String _scalacPlugins;
/**
* Source position mappers.
*
*
* Space-separated list of source position mapper definitions in {@code groupId:artifactId:version} format.
*
* @since 1.0.0
*/
@Parameter( property = "sbt.sourcePositionMappers", defaultValue = "", readonly = true )
protected String sourcePositionMappers;
/**
* Source position mappers.
*
* For internal use only.
*/
@Parameter( property = "sbt._sourcePositionMappers", defaultValue = "", readonly = true )
protected String _sourcePositionMappers;
/**
* Maven project to interact with.
*/
@Parameter( defaultValue = "${project}", readonly = true, required = true )
protected MavenProject project;
/**
* All Maven projects in the reactor.
*/
@Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true )
protected List reactorProjects;
/**
* Artifact factory used to look up artifacts in the remote repository.
*/
@Component
protected ArtifactFactory factory;
/**
* Artifact resolver used to resolve artifacts.
*/
@Component
protected ArtifactResolver resolver;
/**
* Location of the local repository.
*/
@Parameter( property = "localRepository", readonly = true, required = true )
protected ArtifactRepository localRepo;
/**
* Remote repositories used by the resolver
*/
@Parameter( property = "project.remoteArtifactRepositories", readonly = true, required = true )
protected List remoteRepos;
/**
* For retrieval of artifact's metadata.
*/
@Component
protected ArtifactMetadataSource metadataSource;
/**
* Plugin's groupId used for well known providers resolution
*/
@Parameter( property = "plugin.groupId", readonly = true, required = true )
private String pluginGroupId;
/**
* Plugin's version used for well known providers resolution
*/
@Parameter( property = "plugin.version", readonly = true, required = true )
private String pluginVersion;
/**
* Map of compiler implementations. For now only zero or one allowed.
*/
@Component( role = Compiler.class )
private Map compilers;
/**
* Performs compilation.
*
* @throws MojoExecutionException if unexpected problem occurs
* @throws MojoFailureException if expected problem (such as compilation failure) occurs
*/
@Override
public void execute()
throws MojoExecutionException, MojoFailureException
{
if ( !"pom".equals( project.getPackaging() ) )
{
long ts = System.currentTimeMillis();
try
{
internalExecute();
}
finally
{
long te = System.currentTimeMillis();
getLog().debug( String.format( "Mojo execution time: %d ms", te - ts ) );
}
}
}
/**
* Performs compilation.
*
* @throws MojoExecutionException if unexpected problem occurs
* @throws MojoFailureException if expected problem (such as compilation failure) occurs
*/
protected void internalExecute()
throws MojoExecutionException, MojoFailureException
{
List compileSourceRoots = getCompileSourceRoots();
if ( compileSourceRoots.isEmpty() )// ?
{
getLog().info( "No sources to compile" );
return;
}
List sourceRootDirs = new ArrayList( compileSourceRoots.size() );
for ( String compileSourceRoot : compileSourceRoots )
{
sourceRootDirs.add( new File( compileSourceRoot ) );
}
List sourceFiles = getSourceFiles( sourceRootDirs );
if ( sourceFiles.isEmpty() )
{
getLog().info( "No sources to compile" );
return;
}
try
{
Compiler sbtCompiler = getSbtCompiler();
String resolvedScalaVersion = getScalaVersion( sbtCompiler );
Artifact scalaLibraryArtifact =
getResolvedArtifact( SCALA_GROUPID, SCALA_LIBRARY_ARTIFACTID, resolvedScalaVersion );
if ( scalaLibraryArtifact == null )
{
throw new MojoExecutionException( String.format( "Required %s:%s:%s:jar artifact not found",
SCALA_GROUPID, SCALA_LIBRARY_ARTIFACTID,
resolvedScalaVersion ) );
}
Artifact scalaCompilerArtifact =
getResolvedArtifact( SCALA_GROUPID, SCALA_COMPILER_ARTIFACTID, resolvedScalaVersion );
if ( scalaCompilerArtifact == null )
{
throw new MojoExecutionException( String.format( "Required %s:%s:%s:jar artifact not found",
SCALA_GROUPID, SCALA_COMPILER_ARTIFACTID,
resolvedScalaVersion ) );
}
List scalaExtraJars = getCompilerDependencies( scalaCompilerArtifact, scalaLibraryArtifact );
String resolvedSbtVersion = sbtCompiler.getDefaultSbtVersion();
Artifact xsbtiArtifact = getResolvedArtifact( SBT_GROUP_ID, XSBTI_ARTIFACT_ID, resolvedSbtVersion );
if ( xsbtiArtifact == null )
{
throw new MojoExecutionException( String.format( "Required %s:%s:%s:jar dependency not found",
SBT_GROUP_ID, XSBTI_ARTIFACT_ID, resolvedSbtVersion ) );
}
Artifact compilerInterfaceSrc =
getResolvedArtifact( SBT_GROUP_ID, COMPILER_INTERFACE_ARTIFACT_ID, resolvedSbtVersion,
COMPILER_INTERFACE_CLASSIFIER );
if ( compilerInterfaceSrc == null )
{
throw new MojoExecutionException( String.format( "Required %s:%s:%s:%s:jar dependency not found",
SBT_GROUP_ID, COMPILER_INTERFACE_ARTIFACT_ID,
resolvedSbtVersion, COMPILER_INTERFACE_CLASSIFIER ) );
}
List classpathElements = getClasspathElements();
classpathElements.remove( getOutputDirectory().getAbsolutePath() );
List classpathFiles = new ArrayList( classpathElements.size() );
for ( String path : classpathElements )
{
classpathFiles.add( new File( path ) );
}
String resolvedScalacOptions = scalacOptions.trim();
if ( _scalacOptions != null && _scalacOptions.length() > 0 )
{
resolvedScalacOptions = resolvedScalacOptions + ' ' + _scalacOptions;
}
if ( ( scalacPlugins != null && scalacPlugins.trim().length() > 0 )
|| ( _scalacPlugins != null && _scalacPlugins.trim().length() > 0 ) )
{
List resolvedScalaCompilerPluginArtifacts = new ArrayList();
resolveArtifacts( resolvedScalaCompilerPluginArtifacts, scalacPlugins );
resolveArtifacts( resolvedScalaCompilerPluginArtifacts, _scalacPlugins );
for ( Artifact artifact: resolvedScalaCompilerPluginArtifacts )
{
String arg = "-Xplugin:" + artifact.getFile().getAbsolutePath();
if ( arg.indexOf( ' ' ) >= 0 )
{
arg = '\"' + arg + '\"';
}
resolvedScalacOptions = resolvedScalacOptions + ' ' + arg;
}
}
SourcePositionMapper sourcePositionMapper = null;
if ( sbtCompiler.supportsSourcePositionMappers() )
{
if ( ( sourcePositionMappers != null && sourcePositionMappers.trim().length() > 0 )
|| ( _sourcePositionMappers != null && _sourcePositionMappers.trim().length() > 0 ) )
{
List resolvedSourcePositionMapperArtifacts = new ArrayList();
resolveArtifacts( resolvedSourcePositionMapperArtifacts, sourcePositionMappers );
resolveArtifacts( resolvedSourcePositionMapperArtifacts, _sourcePositionMappers );
if ( !resolvedSourcePositionMapperArtifacts.isEmpty() )
{
Set resolvedSourcePositionMapperArtifactSet =
getAllDependencies( new HashSet( resolvedSourcePositionMapperArtifacts ), null /* filter */ );
List resolvedSourcePositionMappers =
resolveSourcePositionMappers( resolvedSourcePositionMapperArtifactSet );
if ( resolvedSourcePositionMappers != null )
{
sourcePositionMapper = new SourcePositionMapperCollection( resolvedSourcePositionMappers );
sourcePositionMapper.setCharsetName( sourceEncoding );
}
}
}
}
CompilerConfiguration configuration = new CompilerConfiguration();
configuration.setSourceFiles( sourceFiles );
configuration.setScalaLibraryFile( scalaLibraryArtifact.getFile() );
configuration.setScalaCompilerFile( scalaCompilerArtifact.getFile() );
configuration.setScalaExtraJarFiles( scalaExtraJars );
configuration.setXsbtiFile( xsbtiArtifact.getFile() );
configuration.setCompilerInterfaceSrcFile( compilerInterfaceSrc.getFile() );
configuration.setClasspathFiles( classpathFiles );
configuration.setLogger( new MavenCompilerLogger( getLog() ) );
configuration.setOutputDirectory( getOutputDirectory() );
configuration.setSourceEncoding( sourceEncoding );
configuration.setJavacOptions( javacOptions );
configuration.setScalacOptions( resolvedScalacOptions );
configuration.setAnalysisCacheFile( getAnalysisCacheFile() );
configuration.setAnalysisCacheMap( getAnalysisCacheMap() );
configuration.setSourcePositionMapper( sourcePositionMapper );
sbtCompiler.performCompile( configuration );
}
catch ( CompilerException e )
{
throw new MojoFailureException( "Scala compilation failed", e );
}
catch ( ArtifactNotFoundException e )
{
throw new MojoExecutionException( "Scala compilation failed", e );
}
catch ( ArtifactResolutionException e )
{
throw new MojoExecutionException( "Scala compilation failed", e );
}
catch ( MalformedURLException e )
{
throw new MojoExecutionException( "Scala compilation failed", e );
}
}
/**
* Returns compilation classpath elements.
*
* @return classpath elements
*/
protected abstract List getClasspathElements();
/**
* Returns compilation source roots.
*
* @return source roots
*/
protected abstract List getCompileSourceRoots();
/**
* Returns source inclusion filters for the compiler.
*
* @return source inclusion filters
*/
protected abstract Set getSourceIncludes();
/**
* Returns source exclusion filters for the compiler.
*
* @return source exclusion filters
*/
protected abstract Set getSourceExcludes();
/**
* Returns output directory.
*
* @return output directory
*/
protected abstract File getOutputDirectory();
/**
* Returns SBT incremental compilation analysis cache file location for this project.
*
* @return analysis cache file
*/
protected abstract File getAnalysisCacheFile();
/**
* Returns SBT incremental compilation analysis cache file locations map for all reactor projects.
*
* @return analysis cache files map
*/
protected abstract Map getAnalysisCacheMap();
private Artifact getDependencyArtifact( Collection> classPathArtifacts, String groupId, String artifactId,
String type )
{
Artifact result = null;
for ( Iterator> iter = classPathArtifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
if ( groupId.equals( artifact.getGroupId() ) && artifactId.equals( artifact.getArtifactId() )
&& type.equals( artifact.getType() ) )
{
result = artifact;
break;
}
}
return result;
}
private List getSourceFiles( List sourceRootDirs )
{
List sourceFiles = new ArrayList();
Set sourceIncludes = getSourceIncludes();
if ( sourceIncludes.isEmpty() )
{
sourceIncludes.add( "**/*.java" );
sourceIncludes.add( "**/*.scala" );
}
Set sourceExcludes = getSourceExcludes();
DirectoryScanner scanner = new DirectoryScanner();
scanner.setIncludes( sourceIncludes.toArray( new String[sourceIncludes.size()] ) );
if ( !sourceExcludes.isEmpty() )
{
scanner.setExcludes( sourceExcludes.toArray( new String[sourceExcludes.size()] ) );
}
scanner.addDefaultExcludes();
for ( File dir : sourceRootDirs )
{
if ( dir.isDirectory() )
{
scanner.setBasedir( dir );
scanner.scan();
String[] includedFileNames = scanner.getIncludedFiles();
for ( String includedFileName : includedFileNames )
{
File tmpAbsFile = new File( dir, includedFileName ).getAbsoluteFile(); // ?
sourceFiles.add( tmpAbsFile );
}
}
}
// scalac is sensible to scala file order, file system can't guarantee file order => unreproductible build error
// across platform
// to guarantee reproductible command line we order file by path (os dependend).
// Collections.sort( sourceFiles );
return sourceFiles;
}
private String getScalaVersion( Compiler sbtCompiler )
{
String result = scalaVersion;
if ( result == null || result.length() == 0 )
{
Artifact scalaLibraryArtifact =
getDependencyArtifact( project.getArtifacts(), SCALA_GROUPID, SCALA_LIBRARY_ARTIFACTID, "jar" );
if ( scalaLibraryArtifact != null )
{
result = scalaLibraryArtifact.getVersion();
}
else
{
result = sbtCompiler.getDefaultScalaVersion();
}
}
return result;
}
/**
* Returns SBT incremental main compilation analysis cache file location for a project.
*
* @param p Maven project
* @return analysis cache file location
*/
protected File defaultAnalysisCacheFile( MavenProject p )
{
File classesDirectory = new File( p.getBuild().getOutputDirectory() );
return new File( Compilers.getCacheDirectory( classesDirectory ), "compile" );
}
/**
* Returns SBT incremental test compilation analysis cache file location for a project.
*
* @param p Maven project
* @return analysis cache file location
*/
protected File defaultTestAnalysisCacheFile( MavenProject p )
{
File testClassesDirectory = new File( p.getBuild().getTestOutputDirectory() );
return new File( Compilers.getCacheDirectory( testClassesDirectory ), "test-compile" );
}
// Private utility methods
private Artifact getResolvedArtifact( String groupId, String artifactId, String version )
throws ArtifactNotFoundException, ArtifactResolutionException
{
Artifact artifact = factory.createArtifact( groupId, artifactId, version, Artifact.SCOPE_RUNTIME, "jar" );
resolver.resolve( artifact, remoteRepos, localRepo );
return artifact;
}
private Artifact getResolvedArtifact( String groupId, String artifactId, String version, String classifier )
throws ArtifactNotFoundException, ArtifactResolutionException
{
Artifact artifact = factory.createArtifactWithClassifier( groupId, artifactId, version, "jar", classifier );
resolver.resolve( artifact, remoteRepos, localRepo );
return artifact;
}
private List getCompilerDependencies( Artifact scalaCompilerArtifact, Artifact scalaLibraryArtifact )
throws ArtifactNotFoundException, ArtifactResolutionException
{
ArtifactFilter scalaLibraryFilter =
new ExcludesArtifactFilter( Collections.singletonList( scalaLibraryArtifact.getGroupId() + ":"
+ scalaLibraryArtifact.getArtifactId() ) );
List d = new ArrayList();
for ( Artifact artifact : getAllDependencies( scalaCompilerArtifact, scalaLibraryFilter ) )
{
if ( !scalaCompilerArtifact.getGroupId().equals( artifact.getGroupId() )
|| !scalaCompilerArtifact.getArtifactId().equals( artifact.getArtifactId() ) )
{
d.add( artifact.getFile() ); // don't add scalaCompilerArtifact file
}
}
return d;
}
private Set getAllDependencies( Artifact artifact, ArtifactFilter filter )
throws ArtifactNotFoundException, ArtifactResolutionException
{
return getAllDependencies( Collections.singleton( artifact ), filter );
}
private Set getAllDependencies( Set artifacts, ArtifactFilter filter )
throws ArtifactNotFoundException, ArtifactResolutionException
{
Artifact originatingArtifact = factory.createBuildArtifact( "dummy", "dummy", "1.0", "jar" );
ArtifactResolutionResult resolutionResult =
resolver.resolveTransitively( artifacts, originatingArtifact, localRepo,
remoteRepos, metadataSource, filter );
return resolutionResult.getArtifacts();
}
// Cached classloaders
private static final ConcurrentHashMap cachedClassLoaders = new ConcurrentHashMap( 2 );
private static ClassLoader getCachedClassLoader( String compilerId )
{
return cachedClassLoaders.get( compilerId );
}
private static void setCachedClassLoader( String compilerId, ClassLoader classLoader )
{
cachedClassLoaders.put( compilerId, classLoader );
}
private Compiler getSbtCompiler()
throws MojoExecutionException
{
Compiler sbtCompiler = null;
if ( !compilers.isEmpty() )
{
sbtCompiler = getDeclaredSbtCompiler();
}
else
{
sbtCompiler = getWellKnownSbtCompiler();
}
return sbtCompiler;
}
private Compiler getDeclaredSbtCompiler()
throws MojoExecutionException
{
if ( compilers.size() > 1 )
{
throw new MojoExecutionException( "Too many compiles defined. A maximum of one allowed." );
}
Map.Entry compilerEntry = compilers.entrySet().iterator().next();
String compilerId = compilerEntry.getKey();
Compiler sbtCompiler = compilerEntry.getValue();
getLog().debug( String.format( "Using declared compiler \"%s\".", compilerId ) );
return sbtCompiler;
}
private Compiler getWellKnownSbtCompiler()
throws MojoExecutionException
{
try
{
String compilerId = Compilers.getDefaultCompilerId( sbtVersion, playVersion );
ClassLoader compilerClassLoader = getCachedClassLoader( compilerId );
if ( compilerClassLoader == null )
{
getLog().debug( String.format( "Cached classloader for compiler \"%s\" not available.", compilerId ) );
}
else
{
if ( compilerClassLoader.getParent() == Thread.currentThread().getContextClassLoader() )
{
getLog().debug( String.format( "Using cached classloader for compiler \"%s\".", compilerId ) );
}
else
{
getLog().debug( String.format( "Invalidated cached classloader for compiler \"%s\". Parent classloader changed from %d to %d.",
compilerId,
Integer.valueOf( compilerClassLoader.getParent().hashCode() ),
Integer.valueOf( Thread.currentThread().getContextClassLoader().hashCode() ) ) );
compilerClassLoader = null;
}
}
if ( compilerClassLoader == null )
{
Artifact compilerArtifact =
getResolvedArtifact( pluginGroupId, "sbt-compiler-" + compilerId, pluginVersion );
Set compilerDependencies = getAllDependencies( compilerArtifact, null );
List classPathFiles = new ArrayList( compilerDependencies.size() + 1 );
// classPathFiles.add( compilerArtifact.getFile() );
for ( Artifact dependencyArtifact : compilerDependencies )
{
classPathFiles.add( dependencyArtifact.getFile() );
}
String javaHome = System.getProperty( "java.home" );
classPathFiles.add( new File( javaHome, "../lib/tools.jar" ) );
List classPathUrls = new ArrayList( classPathFiles.size() );
for ( File classPathFile : classPathFiles )
{
classPathUrls.add( new URL( classPathFile.toURI().toASCIIString() ) );
}
compilerClassLoader =
new URLClassLoader( classPathUrls.toArray( new URL[classPathUrls.size()] ),
Thread.currentThread().getContextClassLoader() );
getLog().debug( String.format( "Setting cached classloader for compiler \"%s\" with parent classloader %d",
compilerId, Integer.valueOf( compilerClassLoader.getParent().hashCode() ) ) );
setCachedClassLoader( compilerId, compilerClassLoader );
}
ServiceLoader compilerServiceLoader = ServiceLoader.load( Compiler.class, compilerClassLoader );
// get first (there should be exactly one)
Compiler sbtCompiler = compilerServiceLoader.iterator().next();
getLog().debug( String.format( "Using autodetected compiler \"%s\".", compilerId ) );
return sbtCompiler;
}
catch ( ArtifactNotFoundException e )
{
throw new MojoExecutionException( "Compiler autodetection failed", e );
}
catch ( ArtifactResolutionException e )
{
throw new MojoExecutionException( "Compiler autodetection failed", e );
}
catch ( MalformedURLException e )
{
throw new MojoExecutionException( "Compiler autodetection failed", e );
}
}
// "artifactGAVs" in format "groupId1:artifactId1:version1 groupId2:artifactId2:version2"
private void resolveArtifacts( List artifacts, String artifactGAVs )
throws ArtifactNotFoundException, ArtifactResolutionException
{
if ( artifactGAVs != null && artifactGAVs.trim().length() > 0 )
{
String[] scalacPluginsGAVs = artifactGAVs.trim().split( " " );
for ( String scalacPluginGAV : scalacPluginsGAVs )
{
String[] gav = scalacPluginGAV.split( ":" );
String groupId = gav[ 0 ];
String artifactId = gav[ 1 ];
String version = gav[ 2 ];
Artifact scalacPluginArtifact = getResolvedArtifact( groupId, artifactId, version );
if ( scalacPluginArtifact != null )
{
artifacts.add( scalacPluginArtifact );
}
}
}
}
private List resolveSourcePositionMappers( Set resolvedSourcePositionMapperArtifacts )
throws MalformedURLException
{
List result = null;
List classPathUrls = new ArrayList( resolvedSourcePositionMapperArtifacts.size() );
for ( Artifact artifact : resolvedSourcePositionMapperArtifacts )
{
classPathUrls.add( new URL( artifact.getFile().toURI().toASCIIString() ) );
}
ClassLoader tmpMappersClassLoader =
new URLClassLoader( classPathUrls.toArray( new URL[classPathUrls.size()] ),
Thread.currentThread().getContextClassLoader() );
ServiceLoader spmServiceLoader =
ServiceLoader.load( SourcePositionMapper.class, tmpMappersClassLoader );
Iterator spmIterator = spmServiceLoader.iterator();
if ( spmIterator.hasNext() )
{
result = new ArrayList();
while ( spmIterator.hasNext() )
{
result.add( spmIterator.next() );
}
}
return result;
}
}