com.carrotgarden.maven.scalor.base.Params.scala Maven / Gradle / Ivy
package com.carrotgarden.maven.scalor.base
import java.io.File
import java.util.ArrayList
import java.util.Arrays
import java.util.Collections
import org.apache.maven.artifact.Artifact
import org.apache.maven.execution.MavenSession
import org.apache.maven.model.Dependency
import org.apache.maven.plugin.BuildPluginManager
import org.apache.maven.plugin.MojoExecution
import org.apache.maven.plugin.descriptor.PluginDescriptor
import org.apache.maven.plugins.annotations.Component
import org.apache.maven.plugins.annotations.Parameter
import org.apache.maven.project.MavenProject
import org.apache.maven.toolchain.ToolchainManager
import com.carrotgarden.maven.scalor.util.Error.Throw
import com.carrotgarden.maven.scalor.util.Maven
import com.carrotgarden.maven.tools.Description
/**
* Shared mojo execution configuration parameters.
*
* Provides components injected by Maven runtime.
*/
trait Params extends AnyRef
with ParamsPlugin
with ParamsProject {
}
trait ParamsPlugin {
@Description( """
Maven build session.
""" )
@Parameter( defaultValue = "${session}", required = true, readonly = true )
var session : MavenSession = _
@Description( """
This plugin descriptor.
""" )
@Parameter( defaultValue = "${plugin}", required = true, readonly = true )
var pluginMeta : PluginDescriptor = _
@Description( """
This mojo execution.
""" )
@Parameter( defaultValue = "${mojoExecution}", required = true, readonly = true )
var mojoExecution : MojoExecution = _
@Description( """
Maven tool chain provider.
""" )
@Component()
var toolchainManager : ToolchainManager = _
@Description( """
Maven build plugin manager.
""" )
@Component()
var buildManager : BuildPluginManager = _
}
trait ParamsProject {
@Description( """
Current maven project.
""" )
@Parameter( defaultValue = "${project}", required = true, readonly = true )
var project : MavenProject = _
val propertySeparator = "\u0000"
/**
* Custom optional project property.
*/
def extractProperty( key : String ) : Option[ String ] = {
Option( project.getProperties.getProperty( key ) )
}
/**
* Custom optional project property containing a list.
*/
def extractPropertyList( key : String ) : Option[ java.util.List[ String ] ] = {
extractProperty( key ).map( entry => Arrays.asList( entry.split( propertySeparator ) : _* ) )
}
/**
* Custom optional project property.
*/
def persistProperty( key : String, value : String ) : Unit = {
project.getProperties.setProperty( key, value )
}
/**
* Custom optional project property containing a list.
*/
def persistPropertyList( key : String, sourceValue : String ) : Unit = {
val sourceList = extractPropertyList( key ).getOrElse( Collections.emptyList() )
val targetList = sourceValue.split( propertySeparator ) ++ sourceList.toArray
val targetValue = targetList.mkString( propertySeparator )
persistProperty( key, targetValue )
}
/**
* Resolved project dependencies with matching scopes.
*/
def projectDepenencyList( bucket : Scope.Bucket = Scope.Select.Test ) = {
val list = new ArrayList[ Artifact ]()
val iter = project.getArtifacts.iterator
while ( iter.hasNext ) {
val artifact = iter.next
if ( artifact != null && artifact.getArtifactHandler != null ) {
// Filter by @Mojo "requiresDependencyResolution = ResolutionScope.Value".
val hasResolve = artifact.getArtifactHandler.isAddedToClasspath
// Filter by provided scope configuration.
val hasBucket = Scope.hasMatch( artifact, bucket )
// Ensure is downloaded.
val hasFile = artifact.getFile != null
if ( hasResolve && hasBucket && hasFile ) {
list.add( artifact )
}
}
}
list
}
/**
* Resolved project dependencies with matching scopes.
*/
// FIXME switch to aether
def projectClassPath( bucket : Scope.Bucket = Scope.Select.Test ) : Array[ File ] = {
val list = new ArrayList[ File ]()
val iter = project.getArtifacts.iterator
while ( iter.hasNext ) {
val artifact = iter.next
if ( artifact != null && artifact.getArtifactHandler != null ) {
// Filter by @Mojo "requiresDependencyResolution = ResolutionScope.Value"
val hasResolve = artifact.getArtifactHandler.isAddedToClasspath
// Filter by provided scope configuration
val hasBucket = Scope.hasMatch( artifact, bucket )
if ( hasResolve && hasBucket ) {
val file = artifact.getFile
if ( file != null ) {
list.add( file.getCanonicalFile )
}
}
}
}
list.toArray( Array[ File ]() )
}
}
/**
* Common parameters.
*/
trait ParamsAny {
@Description( """
Separator for plugin configuration list values provided in pom.xml
.
Separator regular expression is used as follows:
string.split( commonSequenceSeparator ).map( _.trim ).filterNot( _.isEmpty )
Note: <![CDATA[ ... ]]>
brackets can help preserve text entries in pom.xml
.
Note: to insert unicode symbol in Eclipse/GTK, type CTRL+SHIFT+U, then XXXX - a 4-hex-digit unicode value.
For example, for star ★, use hex code 2605.
""" )
@Parameter(
property = "scalor.commonSequenceSeparator",
defaultValue = """[★\n]+"""
)
var commonSequenceSeparator : String = _
@Description( """
Regular expression for plugin configuration map values provided in pom.xml
.
Extractor for pattern: key=value
.
Must define exactly two regex capture groups.
Mapping regular expression is used as follows:
case commonMappingPattern.r( key, value ) => ( key, value )
Note: <![CDATA[ ... ]]>
brackets can help preserve text entries in pom.xml
.
""" )
@Parameter(
property = "scalor.commonMappingPattern",
defaultValue = """\s*([^=\s]+)\s*=\s*([^\s]+)\s*"""
)
var commonMappingPattern : String = _
/**
* Produce clean options list.
*/
def parseCommonList( options : String ) : Array[ String ] = {
val separator = commonSequenceSeparator
options.split( separator ).map( _.trim ).filterNot( _.isEmpty )
}
/**
* Produce clean options mapping.
*/
def parseCommonMapping( options : String ) : Map[ String, String ] = {
val regexKeyValue = commonMappingPattern.r
val termList = parseCommonList( options )
val entryList = termList.collect {
case regexKeyValue( key, value ) => ( key, value )
}
entryList.toMap
}
}
/**
* Scala compiler installation definition.
*/
trait ParamsCompiler extends AnyRef
with ParamsDefine
with ParamsRegex {
import com.carrotgarden.maven.scalor.meta.Macro.nameOf
import com.carrotgarden.maven.scalor.zinc.Version
import scala.tools.nsc.settings.ScalaVersion
import scala.tools.nsc.settings.SpecificScalaVersion
/**
* Locate plugin bridge dependency.
*/
def defineFindBridge() : Dependency = {
Self.pluginDependency( regexCompilerBridge ).getOrElse(
Throw( s"Missing bridge, see: ${nameOf( defineAuto )}, ${nameOf( regexCompilerBridge )}." )
)
}
/**
* Locate plugin compiler dependency.
*/
def defineFindCompiler() : Dependency = {
Self.pluginDependency( regexScalaCompiler ).getOrElse(
Throw( s"Missing compiler, see: ${nameOf( defineAuto )}, ${nameOf( regexScalaCompiler )}." )
)
}
/**
* Locate project library dependency.
*/
def defineFindLibrary( project : MavenProject ) : Artifact = {
Maven.locateArtifact( project, regexScalaLibrary ).getOrElse(
Throw( s"Missing library, see: ${nameOf( defineAuto )}, ${nameOf( regexScalaLibrary )}." )
)
}
/**
* Extract project library version.
*/
def defineLibraryVersion( project : MavenProject ) : SpecificScalaVersion = {
val library = defineFindLibrary( project )
ScalaVersion( library.getVersion ).asInstanceOf[ SpecificScalaVersion ]
}
/**
* Construct bridge dependency.
*/
def defineMakeBridge( project : MavenProject ) : Dependency = {
val scalaVersion = defineLibraryVersion( project )
val scalaVersionEpoch = Version.scalaVersionEpoch( scalaVersion )
val scalaVersionRelease = Version.scalaVersionRelease( scalaVersion )
val bridgeSource = defineFindBridge()
val bridgeSourceId = bridgeSource.getArtifactId
val bridgeArtifactPast = Version.artifactVersion( bridgeSourceId ).getOrElse(
Throw( s"Can not parse bridge: regex=${Version.atifactVersionRegex} artifact=${bridgeSourceId}." )
)
val bridgeArtifactNext = bridgeArtifactPast.copy( versionTail = scalaVersionEpoch )
val bridgeTarget = new Dependency()
bridgeTarget.setGroupId( bridgeSource.getGroupId )
bridgeTarget.setArtifactId( bridgeArtifactNext.unparse )
bridgeTarget.setVersion( bridgeSource.getVersion )
bridgeTarget
}
/**
* Construct compiler dependency.
*/
def defineMakeCompiler( project : MavenProject ) : Dependency = {
val scalaVersion = defineLibraryVersion( project )
val scalaVersionEpoch = Version.scalaVersionEpoch( scalaVersion )
val scalaVersionRelease = Version.scalaVersionRelease( scalaVersion )
val compilerSource = defineFindCompiler()
val compilerTarget = new Dependency()
compilerTarget.setGroupId( compilerSource.getGroupId )
compilerTarget.setArtifactId( compilerSource.getArtifactId )
compilerTarget.setVersion( scalaVersionRelease )
compilerTarget
}
/**
* Provide bridge via auto-discovery.
*/
def defineAutoBridge( project : MavenProject ) : Array[ Dependency ] = {
if ( defineBridge == null ) {
defineBridge = Array.empty
}
if ( defineBridge.nonEmpty ) {
defineBridge
} else if ( defineBridge.isEmpty && defineAuto ) {
Array( defineMakeBridge( project ) )
} else {
Throw( s"Missing bridge, see: ${nameOf( defineAuto )}, ${nameOf( defineBridge )}." )
}
}
/**
* Provide compiler via auto-discovery.
*/
def defineAutoCompiler( project : MavenProject ) : Array[ Dependency ] = {
if ( defineCompiler == null ) {
defineCompiler = Array.empty
}
if ( defineCompiler.nonEmpty ) {
defineCompiler
} else if ( defineCompiler.isEmpty && defineAuto ) {
Array( defineMakeCompiler( project ) )
} else {
Throw( s"Missing compiler, see: ${nameOf( defineAuto )}, ${nameOf( defineCompiler )}." )
}
}
/**
* Provide compiler plugin definitions.
*/
def defineAutoPluginList( project : MavenProject ) : Array[ Dependency ] = {
if ( definePluginList == null ) {
definePluginList = Array.empty
}
definePluginList
}
}
/**
* Provide compiler dependency definitions.
*/
trait ParamsDefine {
@Description( """
Enable auto-discovery of
defineBridge and
defineCompiler dependencies.
When false
, bridge and compiler definitions must be explicitly provided in pom.xml
.
When true
, plugin will use the following bridge and compiler dependency discovery heuristic:
- check for bridge and compiler defined in
pom.xml
, if yes - use that, if not - try auto define:
- find
scala-library
on project build class path with help of regexScalaLibrary
- determine Scala epoch
X.Y
and release X.Y.Z
versions of Scala Library
- construct
compiler-bridge
dependency from:
- discovered project Scala epoch version
- bridge artifact included with the plugin
- with help of regexCompilerBridge
- construct
scala-compiler
dependency from:
- discovered project Scala release version
- compiler artifact included with the plugin
- with help of regexScalaCompiler
Use zincLogBridgeClassPath
to review actual resolved bridge artifact in Maven.
Use zincLogCompilerClassPath
to review actual resolved compiler artifact in Maven.
Use eclipseLogPersistInstall
to review actual resolved compiler artifact in Eclipse (bridge is managed by Scala IDE).
""" )
@Parameter(
property = "scalor.defineAuto",
defaultValue = "true"
)
var defineAuto : Boolean = _
@Description( """
Provide Scala compiler bridge dependency.
Can declare here additional dependencies for the bridge.
Bridge artifact must match expected regular expression in
regexCompilerBridge.
Example entry in pom.xml
:
<defineBridge>
<dependency>
<groupId>org.scala-sbt</groupId>
<artifactId>compiler-bridge_${version.scala.epoch}</artifactId>
<version>${version.scala.zinc}</version>
</dependency>
</defineBridge>
This dependency list is empty by default.
""" )
@Parameter(
defaultValue = ""
)
var defineBridge : Array[ Dependency ] = Array.empty
@Description( """
Provide Scala compiler dependency.
Can declare here additional dependencies for the compiler.
Compiler artifact must match expected regular expression in
regexScalaCompiler.
Example entry in pom.xml
:
<defineCompiler>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>${version.scala.release}</version>
</dependency>
</defineCompiler>
This dependency list is empty by default.
""" )
@Parameter(
defaultValue = ""
)
var defineCompiler : Array[ Dependency ] = Array.empty
@Description( """
Provide Scala plugins dependency.
Can declare mulitiple scala compiler plugins.
Plugin artifact jar must contain expected descriptor resource in
resourcePluginDescriptor.
Example entry in pom.xml
:
<definePluginList>
<dependency>
<groupId>org.scala-js</groupId>
<artifactId>scalajs-compiler_${version.scala.release}</artifactId>
<version>${version.sjs.release}</version>
</dependency>
</definePluginList>
This dependency list is empty by default.
""" )
@Parameter(
defaultValue = ""
)
var definePluginList : Array[ Dependency ] = Array.empty
}
trait ParamsRegex {
@Description( """
Maven identity of Scala bridge artifact.
Regular expression in the form: ${groupId}:${artifactId}
.
Used for auto discovery of compiler-bridge from
defineBridge.
""" )
@Parameter(
property = "scalor.regexCompilerBridge",
defaultValue = "org.scala-sbt:compiler-bridge_.+"
)
var regexCompilerBridge : String = _
@Description( """
Maven identity of Scala compiler artifact.
Regular expression in the form: ${groupId}:${artifactId}
.
Used for auto discovery of scala-compiler from
defineCompiler.
""" )
@Parameter(
property = "scalor.regexScalaCompiler",
defaultValue = "org.scala-lang:scala-compiler"
)
var regexScalaCompiler : String = _
@Description( """
Maven identity of Scala library artifact.
Regular expression in the form: ${groupId}:${artifactId}
.
Used for auto discovery of scala-library from
defineCompiler.
""" )
@Parameter(
property = "scalor.regexScalaLibrary",
defaultValue = "org.scala-lang:scala-library"
)
var regexScalaLibrary : String = _
// @Description( """
// Maven identity of Scala reflect artifact.
// Regular expression in the form: ${groupId}:${artifactId}
.
// Used for auto discovery of scala-reflect from
// defineCompiler.
// """ )
// @Parameter(
// property = "scalor.regexScalaReflect",
// defaultValue = "org.scala-lang:scala-reflect"
// )
// var regexScalaReflect : String = _
@Description( """
Scala compiler plugin descriptor file name, stored inside compiler plugin jar.
Used for auto discovery of Scala compiler plugins form
definePluginList.
Plain file name, not a regex.
""" )
@Parameter(
property = "scalor.resourcePluginDescriptor",
defaultValue = "scalac-plugin.xml"
)
var resourcePluginDescriptor : String = _
}
object Params {
/**
* Artifact set definition.
*/
trait Define[ T ] {
val defineBridge : Seq[ T ]
val defineCompiler : Seq[ T ]
val definePluginList : Seq[ T ]
}
/**
* Maven resolution request.
*/
case class DefineRequest(
defineBridge : Seq[ Dependency ],
defineCompiler : Seq[ Dependency ],
definePluginList : Seq[ Dependency ]
) extends Define[ Dependency ]
/**
* Maven resolution response.
*/
case class DefineResponse(
defineBridge : Seq[ Artifact ],
defineCompiler : Seq[ Artifact ],
definePluginList : Seq[ Artifact ]
) extends Define[ Artifact ]
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy