blob: c17e520cf2ddaba138f6a17569b5550927e88cd4 [file] [log] [blame]
/* ==========================================================================
* Copyright 2003-2004 Mevenide Team
*
* 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 org.netbeans.nbm;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
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.ArtifactResolver;
import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
import org.apache.maven.shared.dependency.graph.DependencyNode;
import org.netbeans.nbm.model.Dependency;
import org.netbeans.nbm.model.NetBeansModule;
import org.netbeans.nbm.model.io.xpp3.NetBeansModuleXpp3Reader;
import org.netbeans.nbm.utils.AbstractNetbeansMojo;
import org.netbeans.nbm.utils.ExamineManifest;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
import org.codehaus.plexus.util.IOUtil;
public abstract class AbstractNbmMojo
extends AbstractNetbeansMojo
{
static boolean matchesLibrary( Artifact artifact, List<String> libraries, ExamineManifest depExaminator,
Log log, boolean useOsgiDependencies )
{
String artId = artifact.getArtifactId();
String grId = artifact.getGroupId();
String id = grId + ":" + artId;
boolean explicit = libraries.remove( id );
if ( explicit )
{
log.debug(
id + " included as module library, explicitly declared in module descriptor." );
return explicit;
}
if ( Artifact.SCOPE_PROVIDED.equals( artifact.getScope() ) || Artifact.SCOPE_SYSTEM.equals(
artifact.getScope() ) )
{
log.debug(
id + " omitted as module library, has scope 'provided/system'" );
return false;
}
if ( "nbm".equals( artifact.getType() ) )
{
return false;
}
if ( depExaminator.isNetBeansModule() || ( useOsgiDependencies && depExaminator.isOsgiBundle() ) )
{
//TODO I can see how someone might want to include an osgi bundle as library, not dependency.
// I guess it won't matter much in 6.9+, in older versions it could be a problem.
return false;
}
log.debug(
id + " included as module library, squeezed through all the filters." );
return true;
}
static Dependency resolveNetBeansDependency( Artifact artifact, List<Dependency> deps,
ExamineManifest manifest, Log log )
{
String artId = artifact.getArtifactId();
String grId = artifact.getGroupId();
String id = grId + ":" + artId;
for ( Dependency dep : deps )
{
if ( id.equals( dep.getId() ) )
{
if ( manifest.isNetBeansModule() )
{
return dep;
}
else
{
if ( dep.getExplicitValue() != null )
{
return dep;
}
log.warn(
id + " declared as module dependency in descriptor, but not a NetBeans module" );
return null;
}
}
}
if ( "nbm".equals( artifact.getType() ) )
{
Dependency dep = new Dependency();
dep.setId( id );
dep.setType( "spec" );
log.debug( "Adding nbm module dependency - " + id );
return dep;
}
if ( manifest.isNetBeansModule() )
{
Dependency dep = new Dependency();
dep.setId( id );
dep.setType( "spec" );
log.debug( "Adding direct NetBeans module dependency - " + id );
return dep;
}
return null;
}
protected final NetBeansModule readModuleDescriptor( File descriptor )
throws MojoExecutionException
{
if ( descriptor == null )
{
throw new MojoExecutionException(
"The module descriptor has to be configured." );
}
if ( !descriptor.exists() )
{
throw new MojoExecutionException(
"The module descriptor is missing: '" + descriptor + "'." );
}
Reader r = null;
try
{
r = new FileReader( descriptor );
NetBeansModuleXpp3Reader reader = new NetBeansModuleXpp3Reader();
NetBeansModule module = reader.read( r );
return module;
}
catch ( IOException exc )
{
throw new MojoExecutionException(
"Error while reading module descriptor '" + descriptor + "'.",
exc );
}
catch ( XmlPullParserException xml )
{
throw new MojoExecutionException(
"Error while reading module descriptor '" + descriptor + "'.",
xml );
}
finally
{
IOUtil.close( r );
}
}
protected final NetBeansModule createDefaultDescriptor( MavenProject project, boolean log )
{
if ( log )
{
getLog().info(
"No Module Descriptor defined, trying to fallback to generated values:" );
}
NetBeansModule module = new NetBeansModule();
return module;
}
static List<Artifact> getLibraryArtifacts( DependencyNode treeRoot, NetBeansModule module,
List<Artifact> runtimeArtifacts,
Map<Artifact, ExamineManifest> examinerCache, Log log,
boolean useOsgiDependencies )
throws MojoExecutionException
{
List<Artifact> include = new ArrayList<Artifact>();
if ( module != null )
{
List<String> librList = new ArrayList<String>();
if ( module.getLibraries() != null )
{
librList.addAll( module.getLibraries() );
}
CollectLibrariesNodeVisitor visitor = new CollectLibrariesNodeVisitor( librList,
runtimeArtifacts, examinerCache, log, treeRoot, useOsgiDependencies );
treeRoot.accept( visitor );
include.addAll( visitor.getArtifacts() );
}
return include;
}
static List<ModuleWrapper> getModuleDependencyArtifacts( DependencyNode treeRoot, NetBeansModule module,
Dependency[] customDependencies, MavenProject project,
Map<Artifact, ExamineManifest> examinerCache,
List<Artifact> libraryArtifacts, Log log,
boolean useOsgiDependencies )
throws MojoExecutionException
{
List<Dependency> deps = new ArrayList<Dependency>();
if (customDependencies != null) {
deps.addAll( Arrays.asList( customDependencies ));
}
if (module != null && !module.getDependencies().isEmpty()) {
log.warn( "dependencies in module descriptor are deprecated, use the plugin's parameter moduleDependencies");
//we need to make sure a dependency is not twice there, module deps override the config (as is the case with other
//configurations)
for (Dependency d : module.getDependencies()) {
Dependency found = null;
for (Dependency d2 : deps) {
if (d2.getId().equals(d.getId())) {
found = d2;
break;
}
}
if (found != null) {
deps.remove( found );
}
deps.add(d);
}
}
List<ModuleWrapper> include = new ArrayList<ModuleWrapper>();
@SuppressWarnings( "unchecked" )
List<Artifact> artifacts = project.getCompileArtifacts();
for ( Artifact artifact : artifacts )
{
if ( libraryArtifacts.contains( artifact ) )
{
continue;
}
ExamineManifest depExaminator = examinerCache.get( artifact );
if ( depExaminator == null )
{
depExaminator = new ExamineManifest( log );
depExaminator.setArtifactFile( artifact.getFile() );
depExaminator.checkFile();
examinerCache.put( artifact, depExaminator );
}
Dependency dep = resolveNetBeansDependency( artifact, deps, depExaminator, log );
if ( dep != null )
{
ModuleWrapper wr = new ModuleWrapper();
wr.dependency = dep;
wr.artifact = artifact;
wr.transitive = false;
//only direct deps matter to us..
if ( depExaminator.isNetBeansModule() && artifact.getDependencyTrail().size() > 2 )
{
log.debug(
artifact.getId() + " omitted as NetBeans module dependency, not a direct one. Declare it in the pom for inclusion." );
wr.transitive = true;
}
include.add( wr );
}
else
{
if ( useOsgiDependencies && depExaminator.isOsgiBundle() )
{
ModuleWrapper wr = new ModuleWrapper();
wr.osgi = true;
String id = artifact.getGroupId() + ":" + artifact.getArtifactId();
for ( Dependency depe : deps )
{
if ( id.equals( depe.getId() ) )
{
wr.dependency = depe;
}
}
boolean print = false;
if ( wr.dependency == null )
{
Dependency depe = new Dependency();
depe.setId( id );
depe.setType( "spec" );
wr.dependency = depe;
print = true;
}
wr.artifact = artifact;
wr.transitive = false;
//only direct deps matter to us..
if ( artifact.getDependencyTrail().size() > 2 )
{
log.debug(
artifact.getId() + " omitted as NetBeans module OSGi dependency, not a direct one. Declare it in the pom for inclusion." );
wr.transitive = true;
}
else
{
if ( print )
{
log.info( "Adding OSGi bundle dependency - " + id );
}
}
include.add( wr );
}
}
}
return include;
}
static class ModuleWrapper
{
Dependency dependency;
Artifact artifact;
boolean transitive = true;
boolean osgi = false;
}
//copied from dependency:tree mojo
protected DependencyNode createDependencyTree( MavenProject project, DependencyGraphBuilder dependencyGraphBuilder,
String scope )
throws MojoExecutionException
{
ArtifactFilter artifactFilter = createResolvingArtifactFilter( scope );
try
{
return dependencyGraphBuilder.buildDependencyGraph( project, artifactFilter );
}
catch ( DependencyGraphBuilderException exception )
{
throw new MojoExecutionException( "Cannot build project dependency tree", exception );
}
}
//copied from dependency:tree mojo
/**
* Gets the artifact filter to use when resolving the dependency tree.
*
* @return the artifact filter
*/
private ArtifactFilter createResolvingArtifactFilter( String scope )
{
ArtifactFilter filter;
// filter scope
if ( scope != null )
{
getLog().debug( "+ Resolving dependency tree for scope '" + scope + "'" );
filter = new ScopeArtifactFilter( scope );
}
else
{
filter = null;
}
return filter;
}
protected final ArtifactResult turnJarToNbmFile( Artifact art, ArtifactFactory artifactFactory,
ArtifactResolver artifactResolver, MavenProject project,
ArtifactRepository localRepository )
throws MojoExecutionException
{
if ( "jar".equals( art.getType() ) || "nbm".equals( art.getType() ) )
{
//TODO, it would be nice to have a check to see if the
// "to-be-created" module nbm artifact is actually already in the
// list of dependencies (as "nbm-file") or not..
// that would be a timesaver
ExamineManifest mnf = new ExamineManifest( getLog() );
File jar = art.getFile();
if ( !jar.isFile() )
{
//MNBMODULE-210 with recent CoS changes in netbeans (7.4) jar will be file as we link open projects in the build
// via WorkspaceReader. That's fine here, as all we need is to know if project is osgi or nbm module.
// the nbm file has to be in local repository though.
String path = localRepository.pathOf( art );
File jar2 = new File(localRepository.getBasedir(), path.replace( "/", File.separator));
File manifest = new File(jar, "META-INF/MANIFEST.MF" );
if (! jar2.isFile() || !manifest.isFile() ) {
getLog().warn( "MNBMODULE-131: need to at least run install phase on " + jar2 );
return new ArtifactResult( null, null );
}
mnf.setManifestFile( manifest );
} else {
mnf.setJarFile( jar );
}
mnf.checkFile();
if ( mnf.isNetBeansModule() )
{
Artifact nbmArt = artifactFactory.createDependencyArtifact(
art.getGroupId(),
art.getArtifactId(),
art.getVersionRange(),
"nbm-file",
art.getClassifier(),
art.getScope() );
try
{
artifactResolver.resolve( nbmArt, project.getRemoteArtifactRepositories(), localRepository );
}
catch ( ArtifactResolutionException ex )
{
//shall be check before actually resolving from repos?
checkReactor( art, nbmArt );
if ( !nbmArt.isResolved() )
{
throw new MojoExecutionException( "Failed to retrieve the nbm file from repository", ex );
}
}
catch ( ArtifactNotFoundException ex )
{
//shall be check before actually resolving from repos?
checkReactor( art, nbmArt );
if ( !nbmArt.isResolved() )
{
throw new MojoExecutionException( "Failed to retrieve the nbm file from repository", ex );
}
}
return new ArtifactResult( nbmArt, mnf );
}
if ( mnf.isOsgiBundle() )
{
return new ArtifactResult( null, mnf );
}
}
return new ArtifactResult( null, null );
}
protected static final class ArtifactResult
{
private final Artifact converted;
private final ExamineManifest manifest;
ArtifactResult( Artifact conv, ExamineManifest manifest )
{
converted = conv;
this.manifest = manifest;
}
boolean hasConvertedArtifact()
{
return converted != null;
}
Artifact getConvertedArtifact()
{
return converted;
}
public boolean isOSGiBundle()
{
return manifest != null && manifest.isOsgiBundle();
}
public ExamineManifest getExaminedManifest()
{
return manifest;
}
}
private void checkReactor( Artifact art, Artifact nbmArt )
{
if ( art.getFile().getName().endsWith( ".jar" ) )
{
String name = art.getFile().getName();
name = name.substring( 0, name.length() - ".jar".length() ) + ".nbm";
File fl = new File( art.getFile().getParentFile(), name );
if ( fl.exists() )
{
nbmArt.setFile( fl );
nbmArt.setResolved( true );
}
}
}
}