All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.carrotgarden.maven.scalor.eclipse.Maven.scala Maven / Gradle / Ivy

Go to download

Build integrator for Java, Scala, Scala.macro, Scala.js, Scala.native, Eclipse and Maven

There is a newer version: 1.5.0.20190502185130
Show newest version
package com.carrotgarden.maven.scalor.eclipse

import java.io.File

import scala.collection.JavaConverters.asScalaBufferConverter
import scala.reflect.ClassTag

import org.apache.maven.RepositoryUtils
import org.apache.maven.artifact.Artifact
import org.apache.maven.model.Dependency
import org.apache.maven.plugin.Mojo
import org.apache.maven.plugin.MojoExecution
import org.apache.maven.plugin.descriptor.PluginDescriptor
import org.apache.maven.project.MavenProject
import org.codehaus.plexus.util.xml.Xpp3Dom
import org.eclipse.aether.RepositorySystem
import org.eclipse.aether.impl.ArtifactDescriptorReader
import org.eclipse.aether.impl.ArtifactResolver
import org.eclipse.aether.impl.DependencyCollector
import org.eclipse.aether.impl.Deployer
import org.eclipse.aether.impl.Installer
import org.eclipse.aether.impl.LocalRepositoryProvider
import org.eclipse.aether.impl.MetadataResolver
import org.eclipse.aether.impl.RemoteRepositoryManager
import org.eclipse.aether.impl.SyncContextFactory
import org.eclipse.aether.impl.VersionRangeResolver
import org.eclipse.aether.impl.VersionResolver
import org.eclipse.aether.internal.impl.DefaultRepositorySystem
import org.eclipse.aether.spi.log.LoggerFactory
import org.eclipse.aether.util.artifact.JavaScopes
import org.eclipse.core.resources.IFolder
import org.eclipse.core.resources.IProject
import org.eclipse.core.runtime.IPath
import org.eclipse.core.runtime.IProgressMonitor
import org.eclipse.core.runtime.Path
import org.eclipse.m2e.core.MavenPlugin
import org.eclipse.m2e.core.internal.MavenPluginActivator
import org.eclipse.m2e.core.internal.project.registry.MavenProjectFacade
import org.eclipse.m2e.core.internal.project.registry.ProjectRegistryManager
import org.eclipse.m2e.core.project.IMavenProjectFacade
import org.eclipse.m2e.core.project.MavenProjectUtils
import org.eclipse.m2e.core.project.configurator.ProjectConfigurationRequest

import com.carrotgarden.maven.scalor.A
import com.carrotgarden.maven.scalor.resolve
import com.carrotgarden.maven.scalor.util.Classer
import com.carrotgarden.maven.scalor.util.Error.Throw
import com.carrotgarden.maven.scalor.util.Logging
import com.carrotgarden.maven.scalor.util.Optioner.convert_Option_Value

/**
 * Provide M2E infrastructure functions.
 */
trait Maven {

  self : Base.Conf with Logging =>

  import Maven._

  /**
   * Configured value of Maven plugin configuration parameter.
   */
  def paramExecValue[ T ](
    project :   MavenProject,
    execution : MojoExecution,
    name :      String,
    monitor :   IProgressMonitor
  )( implicit tag : ClassTag[ T ] ) : T = baseParamValue(
    project, name, tag.runtimeClass, execution, monitor
  ).asInstanceOf[ T ]

  /**
   * Provide Maven plugin configuration parmeter for a goal.
   */
  def paramGoalValue[ T ](
    facade :  IMavenProjectFacade,
    goal :    String,
    name :    String,
    monitor : IProgressMonitor
  )( implicit tag : ClassTag[ T ] ) : T = {
    val project = facade.getMavenProject
    executionDefinition( facade, goal, monitor ).map {
      execution => paramExecValue( project, execution, name, monitor )( tag )
    }.getOrElse( Throw( s"Trying to extract parameter for missing goal: ${goal}" ) )
  }

  /**
   * Provide configuration value for execution goal.
   */
  def extractGoalValue[ T ](
    facade :  IMavenProjectFacade,
    goal :    String,
    name :    String,
    monitor : IProgressMonitor
  )( implicit tag : ClassTag[ T ] ) : T = {
    paramGoalValue( facade, goal, name, monitor )( tag )
  }

  /**
   * Extract plugin configuration parameters for executon goal.
   */
  def extractGoalValue(
    facade :  IMavenProjectFacade,
    monitor : IProgressMonitor,
    goal :    String
  )(
    name : String, klaz : Class[ _ ]
  ) : Object = {
    val javaType = Classer.primitiveWrap( klaz )
    extractGoalValue( facade, goal, name, monitor )( ClassTag( javaType ) )
  }

}

object Maven {

  /**
   * Relative path of project file. File must be inside the project.
   */
  def relativePath( project : IProject, file : File ) = {
    MavenProjectUtils.getProjectRelativePath( project, file.getCanonicalPath );
  }

  /**
   * Absolute path of project file. File must be inside the project.
   */
  def absolutePath( project : IProject, file : File ) : IPath = {
    project.getFullPath.append( relativePath( project, file ) )
  }

  def projectFolder( project : IProject, absolutePath : String ) : IFolder = {
    val location = project.getLocation
    if ( location.equals( Path.fromOSString( absolutePath ) ) ) {
      project.getFolder( location )
    } else {
      project.getFolder( projectRelative( project, absolutePath ) )
    }
  }

  def projectRelative( project : IProject, absolutePath : String ) : IPath = {
    val basedir = project.getLocation.toFile // absolute
    val resolve =
      if ( absolutePath.equals( basedir.getCanonicalPath ) ) {
        "."
      } else if ( absolutePath.startsWith( basedir.getCanonicalPath ) ) {
        absolutePath.substring( basedir.getCanonicalPath().length() + 1 )
      } else { // outside the project
        absolutePath
      }
    new Path( resolve.replace( '\\', '/' ) )
  }

  /**
   * Locate default Maven execution for a given Maven goal.
   */
  def executionDefinition(
    facade :  IMavenProjectFacade,
    goal :    String,
    monitor : IProgressMonitor
  ) : Option[ MojoExecution ] = {
    facade.asInstanceOf[ MavenProjectFacade ]
      .getExecutionPlan( ProjectRegistryManager.LIFECYCLE_DEFAULT, monitor )
      .asScala.find { execution =>
        execution.getGoal == goal
      }.map { execution =>
        // work around https://bugs.eclipse.org/bugs/show_bug.cgi?id=529319
        val mojoConfig : Xpp3Dom = execution.getConfiguration
        val pluginConfig : Xpp3Dom = execution.getPlugin.getConfiguration.asInstanceOf[ Xpp3Dom ]
        val configuration = ( mojoConfig, pluginConfig ) match {
          case ( null, null )               => null
          case ( null, pluginConfig )       => pluginConfig
          case ( mojoConfig, null )         => mojoConfig
          case ( mojoConfig, pluginConfig ) => Xpp3Dom.mergeXpp3Dom( mojoConfig, pluginConfig )
        }
        execution.setConfiguration( configuration )
        execution
      }
  }

  /**
   * Provide descriptor of this plugin.
   */
  def pluginDescriptor(
    facade :  IMavenProjectFacade,
    monitor : IProgressMonitor
  ) : PluginDescriptor = {
    val execution = executionDefinition( facade, A.mojo.`eclipse-config`, monitor )
    execution.getMojoDescriptor.getPluginDescriptor
  }

  /**
   * Access context of this (plugin,project).
   */
  def pluginContext(
    facade :  IMavenProjectFacade,
    monitor : IProgressMonitor
  ) : java.util.Map[ String, Object ] = {
    val maven = MavenPlugin.getMaven
    val context = maven.getExecutionContext
    val plugin = pluginDescriptor( facade, monitor )
    val project = facade.getMavenProject
    context.getSession.getPluginContext( plugin, project )
  }

  import com.carrotgarden.maven.scalor.base.Params._
  import org.osgi.framework.Version

  /**
   * Needed for M2E 1.8 / Maven 3.3.9
   * Not needed for M2E 1.9 / Maven 3.5.2
   *
   * Work around M2E invalid component injector:
   * https://issues.apache.org/jira/browse/MNG-6233
   * https://github.com/apache/maven/commit/66fc74d6296ea0a33f8a9712dc5ed5eb3affd529
   */
  def hackRepoSystem(
    request : ProjectConfigurationRequest
  ) : RepositorySystem = {
    val project = request.getMavenProject
    val activator = MavenPluginActivator.getDefault
    val mavenFace = MavenPlugin.getMaven
    val mavenImpl = activator.getMaven

    val minimalVersion = new Version( "1.9.0" )
    val currentVersion = activator.getBundle.getVersion
    val requireHack = currentVersion.compareTo( minimalVersion ) < 0

    if ( requireHack ) {
      val loader = mavenImpl.getProjectRealm( project )
      Classer.withContextLoader[ RepositorySystem ]( loader ) {
        val system = new DefaultRepositorySystem
        import mavenImpl._
        import system._
        setLoggerFactory( lookupComponent( classOf[ LoggerFactory ] ) )
        setVersionResolver( lookupComponent( classOf[ VersionResolver ] ) )
        setVersionRangeResolver( lookupComponent( classOf[ VersionRangeResolver ] ) )
        setArtifactResolver( lookupComponent( classOf[ ArtifactResolver ] ) )
        setMetadataResolver( lookupComponent( classOf[ MetadataResolver ] ) )
        setArtifactDescriptorReader( lookupComponent( classOf[ ArtifactDescriptorReader ] ) )
        setDependencyCollector( lookupComponent( classOf[ DependencyCollector ] ) )
        setInstaller( lookupComponent( classOf[ Installer ] ) )
        setDeployer( lookupComponent( classOf[ Deployer ] ) )
        setLocalRepositoryProvider( lookupComponent( classOf[ LocalRepositoryProvider ] ) )
        setSyncContextFactory( lookupComponent( classOf[ SyncContextFactory ] ) )
        setRemoteRepositoryManager( lookupComponent( classOf[ RemoteRepositoryManager ] ) )
        system
      }
    } else {
      mavenImpl.lookupComponent( classOf[ RepositorySystem ] )
    }
  }

  def resolveDefine(
    request : ProjectConfigurationRequest,
    define :  DefineRequest,
    scope :   String,
    monitor : IProgressMonitor
  ) : DefineResponse = {
    val mavenFace = MavenPlugin.getMaven
    val context = mavenFace.getExecutionContext

    val repoSystem = hackRepoSystem( request )
    val repoSession = context.getRepositorySession
    val remoteRepoList = RepositoryUtils.toRepos( mavenFace.getArtifactRepositories )
    val stereotypes = repoSession.getArtifactTypeRegistry

    val aether = resolve.AetherUnit(
      repoSystem,
      repoSession,
      remoteRepoList
    )

    import define._
    val bridgeList = aether.resolveRoundTrip( defineBridge, stereotypes, scope )
    val compilerList = aether.resolveRoundTrip( defineCompiler, stereotypes, scope )
    val pluginDefineList = aether.resolveRoundTrip( definePluginList, stereotypes, scope )

    DefineResponse(
      bridgeList,
      compilerList,
      pluginDefineList
    )

  }

  type MojoFunction[ T <: Mojo, U ] = T => U

  /**
   * Invoke function with resolved/configured mojo .
   */
  def withProjectMojo[ T <: Mojo, U ](
    project :   MavenProject,
    execution : MojoExecution
  )(
    function : MojoFunction[ T, U ]
  )(
    implicit
    tag : ClassTag[ T ]
  ) : U = {
    val activator = MavenPluginActivator.getDefault
    val mavenFace = MavenPlugin.getMaven
    val mavenImpl = activator.getMaven
    val session = mavenFace.getExecutionContext.getSession
    // val projectLoader = mavenImpl.getProjectRealm( project )
    val pluginLoader = execution.getMojoDescriptor.getPluginDescriptor.getClassRealm
    Classer.withContextLoader( pluginLoader ) {
      val klaz = pluginLoader.loadClass( tag.runtimeClass.getName )
      val mojo = mavenFace.getConfiguredMojo( session, execution, klaz ).asInstanceOf[ T ]
      try {
        function( mojo )
      } finally {
        mavenFace.releaseMojo( mojo, execution )
      }
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy