blob: 1cbdb175a95789f6afc4de82b43ab2c38d1b63ba [file] [log] [blame]
/* ==========================================================================
* Copyright 2003-2006 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.repository;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.deployer.ArtifactDeployer;
import org.apache.maven.artifact.deployer.ArtifactDeploymentException;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.artifact.installer.ArtifactInstallationException;
import org.apache.maven.artifact.installer.ArtifactInstaller;
import org.apache.maven.artifact.metadata.ArtifactMetadata;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.Parent;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.artifact.AttachedArtifact;
import org.apache.maven.project.artifact.ProjectArtifactMetadata;
import org.netbeans.nbm.utils.AbstractNetbeansMojo;
import org.netbeans.nbm.utils.ExamineManifest;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Input;
import org.apache.tools.ant.taskdefs.PathConvert;
import org.apache.tools.ant.types.FileSet;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
/**
* A goal for identifying NetBeans modules from the installation and populating the local
* repository with them. Optionally you can also deploy to a remote repository.
* <p>
* If you are looking for an existing remote repository for NetBeans artifacts, check out
* <a href="http://bits.netbeans.org/nexus/content/groups/netbeans/">http://bits.netbeans.org/nexus/content/groups/netbeans/</a>,
* it contains API artifacts for multiple releases.
* <a href="http://bits.netbeans.org/netbeans/trunk/maven-snapshot/">http://bits.netbeans.org/netbeans/trunk/maven-snapshot/</a>
* may also be used for <code>SNAPSHOT</code> artifacts if you wish to test development builds.
* </p><p>
* See this <a href="http://mojo.codehaus.org/nbm-maven/nbm-maven-plugin/repository.html">HOWTO</a> on how to generate the NetBeans binaries required
* by this goal.
* </p>
*
* @author <a href="mailto:mkleint@codehaus.org">Milos Kleint</a>
*/
@Mojo(name="populate", aggregator=true, requiresProject=false)
public class PopulateRepositoryMojo
extends AbstractNetbeansMojo
{
private static final String GROUP_API = ".api";
private static final String GROUP_IMPL = ".modules";
private static final String GROUP_EXTERNAL = ".external";
private static final String GROUP_CLUSTER = ".cluster";
/**
* a prefix for groupId of generated content,
* eg. for org.netbeans value will generate org.netbeans.cluster groupId for clusters and org.netbeans.modules for module artifacts.
* @since 1.2
*/
@Parameter(property="groupIdPrefix", defaultValue = "org.netbeans")
private String groupIdPrefix;
/**
* an url where to deploy the NetBeans artifacts. Optional, if not specified, the artifacts will be only installed
* in local repository, if you need to give credentials to access remote repo, the id of the server is hardwired to "netbeans".
*/
@Parameter(property="deployUrl")
private String deployUrl;
/**
* By default the generated metadata is installed in local repository.
* Setting this parameter to false will avoid installing the bits. Only meaningful together with
* a defined "deployUrl" parameter.
* @since 3.0
*/
@Parameter(defaultValue="false", property="skipInstall")
private boolean skipLocalInstall;
/**
* Location of NetBeans installation
*/
@Parameter(property="netbeansInstallDirectory", required=true)
protected File netbeansInstallDirectory;
/**
* If you want to install/deploy also NetBeans api javadocs, download the javadoc zip file from netbeans.org
* expand it to a directory, it should contain multiple zip files. Define this parameter as absolute path to the zip files folder.
*
*/
@Parameter(property="netbeansJavadocDirectory")
protected File netbeansJavadocDirectory;
/**
* Assumes a folder with &lt;code-name-base&gt;.zip files containing sources for modules.
*/
@Parameter(property="netbeansSourcesDirectory")
protected File netbeansSourcesDirectory;
/**
* If defined, will match the nbm files found in the designated folder with the modules
* and upload the nbm file next to the module jar in local and remote repositories.
*
* Assumes a folder with &lt;code-name-base&gt;.nbm files containing nbm files for modules.
* @since 3.0
*/
@Parameter(property="netbeansNbmDirectory", required=true)
protected File netbeansNbmDirectory;
/**
* When specified, will force all modules to have the designated version.
* Good when depending on releases. Then you would for example specify RELEASE50 in this parameter and
* all modules get this version in the repository. If not defined, the maven version is
* derived from the OpenIDE-Module-Specification-Version manifest attribute.
* <p>
* Highly Recommended!
* </p>
*/
@Parameter(property="forcedVersion")
protected String forcedVersion;
/**
* When specified it points to a directory containing a Maven Indexer
* (Nexus) Lucene index. This index will be used to find external libraries that
* are referenced by NetBeans modules and populate the POM metadata with correct
* dependencies. Any dependencies not found this way, will be generated with a unique
* id under the org.netbeans.external groupId.
* <p/>
* Use the {@code download} goal to retrieve the index.
* @since 3.0
*/
@Parameter(property="nexusIndexDirectory")
private File nexusIndexDirectory;
/**
* Whether to create cluster POMs in the {@code org.netbeans.cluster} group.
* Only meaningful when {@code forcedVersion} is defined.
* @since 3.7
*/
@Parameter(defaultValue="true", property="defineCluster")
private boolean defineCluster;
/**
* Optional remote repository to use for inspecting remote dependencies.
* This may be used to populate just part of an installation,
* when base modules are already available in Maven format.
* Currently only supported when {@code forcedVersion} is defined.
* @since 3.7
*/
@Parameter(property="dependencyRepositoryUrl")
private String dependencyRepositoryUrl;
/**
* Repository ID to use when inspecting remote dependencies.
* Only meaningful when {@code dependencyRepositoryUrl} is defined.
* @since 3.7
*/
@Parameter(defaultValue="temp", property="dependencyRepositoryId")
private String dependencyRepositoryId;
/**
* Colon separated artefact coordinate groupId:artefactId:version that
* represent parent to be used
*
* @since 1.4
*/
@Parameter(property = "parentGAV", required = false)
private String parentGAV;
// <editor-fold defaultstate="collapsed" desc="Component parameters">
/**
* Local maven repository.
*/
@Parameter(required=true, readonly=true, defaultValue="${localRepository}")
protected ArtifactRepository localRepository;
/**
* Maven ArtifactFactory.
*/
@Component
private ArtifactFactory artifactFactory;
/**
* Maven ArtifactInstaller.
*/
@Component
private ArtifactInstaller artifactInstaller;
/**
* Maven ArtifactDeployer.
*
*/
@Component
private ArtifactDeployer artifactDeployer;
/**
* Maven ArtifactHandlerManager
*
*/
@Component
private ArtifactHandlerManager artifactHandlerManager;
/**
* Maven ArtifactRepositoryFactory.
*
*/
@Component
private ArtifactRepositoryFactory repositoryFactory;
@Component
private ArtifactResolver artifactResolver;
@Component
private ArtifactRepositoryLayout artifactRepositoryLayout;
// </editor-fold>
// parent handler in case we have one
private Parent artefactParent = null;
@Override
public void execute()
throws MojoExecutionException
{
getLog().info( "Populate repository with NetBeans modules" );
Project antProject = antProject();
ArtifactRepository deploymentRepository = null;
if (parentGAV != null)
{
// populate artefactParent
artefactParent = new Parent();
String[] split = parentGAV.split(":");
if (split.length != 3) {
throw new MojoExecutionException(
"parentGAV should respect the following format groupId:artefactId:version" );
}
artefactParent.setGroupId( split[0] );
artefactParent.setArtifactId( split[1] );
artefactParent.setVersion( split[2] );
}
if ( deployUrl != null )
{
ArtifactRepositoryLayout layout = new DefaultRepositoryLayout();
deploymentRepository = repositoryFactory.createDeploymentArtifactRepository(
"netbeans", deployUrl, layout, true );
}
else if ( skipLocalInstall )
{
throw new MojoExecutionException(
"When skipping install to local repository, one shall define the deployUrl parameter" );
}
IndexSearcher searcher = null;
if ( nexusIndexDirectory != null && nexusIndexDirectory.exists() )
{
try
{
Directory nexusDir = FSDirectory.open( nexusIndexDirectory.toPath() );
IndexReader nexusReader = DirectoryReader.open( nexusDir );
searcher = new IndexSearcher( nexusReader );
getLog().info( "Opened index with " + nexusReader.numDocs() + " documents" );
}
catch ( IOException ex )
{
getLog().error( "Could not open " + nexusIndexDirectory, ex );
}
}
if ( netbeansInstallDirectory == null )
{
Input input = (Input) antProject.createTask( "input" );
input.setMessage( "Please enter NetBeans installation directory:" );
input.setAddproperty( "installDir" );
try
{
input.execute();
}
catch ( BuildException e )
{
getLog().error( "Cannot run ant:input" );
throw new MojoExecutionException( e.getMessage(), e );
}
String prop = antProject.getProperty( "installDir" );
netbeansInstallDirectory = new File( prop );
}
File rootDir = netbeansInstallDirectory;
if ( !rootDir.exists() )
{
getLog().error( "NetBeans installation doesn't exist." );
throw new MojoExecutionException( "NetBeans installation doesn't exist." );
}
getLog().info( "Copying NetBeans artifacts from " + netbeansInstallDirectory );
PathConvert convert = (PathConvert) antProject.createTask( "pathconvert" );
convert.setPathSep( "," );
convert.setProperty( "netbeansincludes" );
FileSet set = new FileSet();
set.setDir( rootDir );
set.createInclude().setName( "**/modules/*.jar" );
set.createInclude().setName( "*/core/*.jar" );
set.createInclude().setName( "platform*/lib/*.jar" );
convert.createPath().addFileset( set );
try
{
convert.execute();
}
catch ( BuildException e )
{
getLog().error( "Cannot run ant:pathconvert" );
throw new MojoExecutionException( e.getMessage(), e );
}
String prop = antProject.getProperty( "netbeansincludes" );
StringTokenizer tok = new StringTokenizer( prop, "," );
HashMap<ModuleWrapper, Artifact> moduleDefinitions = new HashMap<ModuleWrapper, Artifact>();
HashMap<String, Collection<ModuleWrapper>> clusters = new HashMap<String, Collection<ModuleWrapper>>();
while ( tok.hasMoreTokens() )
{
String token = tok.nextToken();
File module = new File( token );
String clust = module.getAbsolutePath().substring( rootDir.getAbsolutePath().length() + 1 );
clust = clust.substring( 0, clust.indexOf( File.separator ) );
ExamineManifest examinator = new ExamineManifest( getLog() );
examinator.setPopulateDependencies( true );
examinator.setJarFile( module );
examinator.checkFile();
if ( examinator.isNetBeansModule() || examinator.isOsgiBundle() )
{
//TODO get artifact id from the module's manifest?
String artifact = module.getName().substring( 0, module.getName().indexOf( ".jar" ) );
if ( "boot".equals( artifact ) )
{
artifact = "org-netbeans-bootstrap";
}
if ( "core".equals( artifact ) )
{
artifact = "org-netbeans-core-startup";
}
if ( "core-base".equals( artifact ) )
{
artifact = "org-netbeans-core-startup-base";
}
String version = forcedVersion == null ? examinator.getSpecVersion() : forcedVersion;
String group = groupIdPrefix + (examinator.isOsgiBundle() ? GROUP_EXTERNAL : examinator.hasPublicPackages() ? GROUP_API : GROUP_IMPL);
Artifact art = createArtifact( artifact, version, group );
if ( examinator.isOsgiBundle() )
{
Dependency dep = findExternal( searcher, module );
if ( dep != null )
{
// XXX use those coords instead of publishing this
// (for now all bundles are from Orbit, which does not publish to Central, or specially built)
}
}
ModuleWrapper wr = new ModuleWrapper( artifact, version, group, examinator, module );
wr.setCluster( clust );
moduleDefinitions.put( wr, art );
Collection<ModuleWrapper> col = clusters.get( clust );
if ( col == null )
{
col = new ArrayList<ModuleWrapper>();
clusters.put( clust, col );
}
col.add( wr );
}
}
List<ModuleWrapper> wrapperList = new ArrayList<ModuleWrapper>( moduleDefinitions.keySet() );
int count = wrapperList.size() + 1;
int index = 0;
File javadocRoot = null;
if ( netbeansJavadocDirectory != null )
{
javadocRoot = netbeansJavadocDirectory ;
if ( !javadocRoot.exists() )
{
javadocRoot = null;
throw new MojoExecutionException(
"The netbeansJavadocDirectory parameter doesn't point to an existing folder" );
}
}
File sourceRoot = null;
if ( netbeansSourcesDirectory != null )
{
sourceRoot = netbeansSourcesDirectory;
if ( !sourceRoot.exists() )
{
sourceRoot = null;
throw new MojoExecutionException(
"The netbeansSourceDirectory parameter doesn't point to an existing folder" );
}
}
File nbmRoot = null;
if ( netbeansNbmDirectory != null )
{
nbmRoot = netbeansNbmDirectory;
if ( !nbmRoot.exists() )
{
nbmRoot = null;
throw new MojoExecutionException(
"The nbmDirectory parameter doesn't point to an existing folder" );
}
}
List<ExternalsWrapper> externals = new ArrayList<ExternalsWrapper>();
try
{
for ( Map.Entry<ModuleWrapper, Artifact> elem : moduleDefinitions.entrySet() )
{
ModuleWrapper man = elem.getKey();
Artifact art = elem.getValue();
index = index + 1;
getLog().info( "Processing " + index + "/" + count );
File pom = createMavenProject( man, wrapperList, externals, searcher );
ArtifactMetadata metadata = new ProjectArtifactMetadata( art, pom );
art.addMetadata( metadata );
File javadoc = null;
Artifact javadocArt = null;
if ( javadocRoot != null )
{
File zip = new File( javadocRoot, art.getArtifactId() + ".zip" );
if ( zip.exists() )
{
javadoc = zip;
javadocArt = createAttachedArtifact( art, javadoc, "jar", "javadoc" );
}
}
File source = null;
Artifact sourceArt = null;
if ( sourceRoot != null )
{
File zip = new File( sourceRoot, art.getArtifactId() + ".zip" );
if ( zip.exists() )
{
source = zip;
sourceArt = createAttachedArtifact( art, source, "jar", "sources" );
}
}
File nbm = null;
Artifact nbmArt = null;
if ( nbmRoot != null )
{
File zip = new File( nbmRoot, art.getArtifactId() + ".nbm" );
if ( !zip.exists() )
{
zip = new File( nbmRoot,
man.getCluster() + File.separator + art.getArtifactId() + ".nbm" );
}
if ( zip.exists() )
{
nbm = zip;
nbmArt = createAttachedArtifact( art, nbm, "nbm-file", null );
if ( nbmArt.getArtifactHandler().getExtension().equals( "nbm-file" ) )
{
// Maven 2.x compatibility.
nbmArt = createAttachedArtifact( art, nbm, "nbm", null );
}
assert nbmArt.getArtifactHandler().getExtension().equals( "nbm" );
}
}
File moduleJar = man.getFile();
File moduleJarMinusCP = null;
if ( ! man.getModuleManifest().getClasspath().isEmpty() )
{
try
{
moduleJarMinusCP = File.createTempFile( man.getArtifact(), ".jar" );
moduleJarMinusCP.deleteOnExit();
InputStream is = new FileInputStream( moduleJar );
try
{
OutputStream os = new FileOutputStream( moduleJarMinusCP );
try
{
JarInputStream jis = new JarInputStream( is );
Manifest mani = new Manifest( jis.getManifest() );
mani.getMainAttributes().remove( Attributes.Name.CLASS_PATH );
if ( !man.deps.isEmpty() )
{ // MNBMODULE-132
StringBuilder b = new StringBuilder();
for ( Dependency dep : man.deps )
{
if ( b.length() > 0 )
{
b.append( ' ' );
}
b.append( dep.getGroupId() ).append( ':' ).append( dep.getArtifactId() ).append( ':' ).append( dep.getVersion() );
if (dep.getClassifier() != null) {
b.append(":").append(dep.getClassifier());
}
}
mani.getMainAttributes().putValue( "Maven-Class-Path", b.toString() );
}
else
{
getLog().warn( "did not find any external artifacts for " + man.getModule() );
}
JarOutputStream jos = new JarOutputStream( os, mani );
JarEntry entry;
while ( ( entry = jis.getNextJarEntry() ) != null )
{
if ( entry.getName().matches( "META-INF/.+[.]SF" ) )
{
throw new IOException( "cannot handle signed JARs" );
}
jos.putNextEntry( entry );
byte[] buf = new byte[(int) entry.getSize()];
int read = jis.read( buf, 0, buf.length );
if ( read != buf.length )
{
throw new IOException( "read wrong amount" );
}
jos.write( buf );
}
jos.close();
}
finally
{
os.close();
}
}
finally
{
is.close();
}
}
catch ( IOException x )
{
getLog().warn( "Could not process " + moduleJar + ": " + x, x );
moduleJarMinusCP.delete();
moduleJarMinusCP = null;
}
}
try
{
if ( !skipLocalInstall )
{
install( moduleJarMinusCP != null ? moduleJarMinusCP : moduleJar, art );
if ( javadoc != null )
{
install( javadoc, javadocArt );
}
if ( source != null )
{
install( source, sourceArt );
}
if ( nbm != null )
{
install( nbm, nbmArt );
}
}
try
{
if ( deploymentRepository != null )
{
artifactDeployer.deploy( moduleJarMinusCP != null ? moduleJarMinusCP : moduleJar, art,
deploymentRepository, localRepository );
if ( javadoc != null )
{
artifactDeployer.deploy( javadoc, javadocArt, deploymentRepository, localRepository );
}
if ( source != null )
{
artifactDeployer.deploy( source, sourceArt, deploymentRepository, localRepository );
}
if ( nbm != null )
{
artifactDeployer.deploy( nbm, nbmArt, deploymentRepository, localRepository );
}
}
}
catch ( ArtifactDeploymentException ex )
{
throw new MojoExecutionException( "Error Deploying artifact", ex );
}
}
finally
{
if ( moduleJarMinusCP != null )
{
moduleJarMinusCP.delete();
}
}
}
}
finally
{
/*if ( searcher != null )
{
try
{
searcher.close();
}
catch ( IOException ex )
{
getLog().error( ex );
}
}*/
}
//process collected non-recognized external jars..
if ( externals.size() > 0 )
{
index = 0;
count = externals.size();
for ( ExternalsWrapper ex : externals )
{
Artifact art = createArtifact( ex.getArtifact(), ex.getVersion(), ex.getGroupid() );
index = index + 1;
getLog().info( "Processing external " + index + "/" + count );
File pom = createExternalProject( ex );
ArtifactMetadata metadata = new ProjectArtifactMetadata( art, pom );
art.addMetadata( metadata );
if ( !skipLocalInstall )
{
install( ex.getFile(), art );
}
try
{
if ( deploymentRepository != null )
{
artifactDeployer.deploy( ex.getFile(), art,
deploymentRepository, localRepository );
}
}
catch ( ArtifactDeploymentException exc )
{
throw new MojoExecutionException( "Error Deploying artifact", exc );
}
}
}
if ( ! defineCluster )
{
getLog().info( "Not creating cluster POMs." );
}
else if ( forcedVersion == null )
{
getLog().warn( "Version not specified, cannot create cluster POMs." );
}
else
{
for ( Map.Entry<String, Collection<ModuleWrapper>> elem : clusters.entrySet() )
{
String cluster = stripClusterName( elem.getKey() );
Collection<ModuleWrapper> modules = elem.getValue();
getLog().info( "Processing cluster " + cluster );
Artifact art = createClusterArtifact( cluster, forcedVersion );
File pom = createClusterProject( art, modules );
ProjectArtifactMetadata metadata = new ProjectArtifactMetadata( art, pom );
art.addMetadata( metadata );
if ( !skipLocalInstall )
{
install( pom, art );
}
try
{
if ( deploymentRepository != null )
{
artifactDeployer.deploy( pom, art, deploymentRepository, localRepository );
}
}
catch ( ArtifactDeploymentException ex )
{
throw new MojoExecutionException( "Error Deploying artifact", ex );
}
}
}
}
void install( File file, Artifact art )
throws MojoExecutionException
{
assert localRepository != null;
try
{
artifactInstaller.install( file, art, localRepository );
}
catch ( ArtifactInstallationException e )
{
// TODO: install exception that does not give a trace
throw new MojoExecutionException( "Error installing artifact", e );
}
}
//performs the same tasks as the MavenProjectHelper
Artifact createAttachedArtifact( Artifact primary, File file, String type, String classifier )
{
assert type != null;
ArtifactHandler handler;
handler = artifactHandlerManager.getArtifactHandler( type );
if ( handler == null )
{
getLog().warn( "No artifact handler for " + type );
handler = artifactHandlerManager.getArtifactHandler( "jar" );
}
Artifact artifact = new AttachedArtifact( primary, type, classifier, handler );
artifact.setFile( file );
artifact.setResolved( true );
return artifact;
}
private File createMavenProject( ModuleWrapper wrapper, List<ModuleWrapper> wrapperList,
List<ExternalsWrapper> externalsList, IndexSearcher searcher )
throws MojoExecutionException
{
Model mavenModel = new Model();
mavenModel.setGroupId( wrapper.getGroup() );
mavenModel.setArtifactId( wrapper.getArtifact() );
mavenModel.setVersion( wrapper.getVersion() );
mavenModel.setPackaging( "jar" );
mavenModel.setModelVersion( "4.0.0" );
if ( artefactParent != null ) {
mavenModel.setParent( artefactParent );
}
ExamineManifest man = wrapper.getModuleManifest();
List<Dependency> deps = new ArrayList<Dependency>();
if ( !man.getDependencyTokens().isEmpty() )
{
for ( String elem : man.getDependencyTokens() )
{
// create pseudo wrapper
ModuleWrapper wr = new ModuleWrapper( elem );
int index = wrapperList.indexOf( wr );
if ( index > -1 )
{
wr = wrapperList.get( index );
Dependency dep = new Dependency();
dep.setArtifactId( wr.getArtifact() );
dep.setGroupId( wr.getGroup() );
dep.setVersion( wr.getVersion() );
dep.setType( "jar" );
//we don't want the API modules to depend on non-api ones..
// otherwise the transitive dependency mechanism pollutes your classpath..
if ( wrapper.getModuleManifest().hasPublicPackages() && !wr.getModuleManifest().hasPublicPackages() )
{
dep.setScope( "runtime" );
}
deps.add( dep );
}
else if ( dependencyRepositoryUrl != null )
{
Dependency dep = new Dependency();
dep.setType( "jar" );
String artifactId = elem.replace( '.', '-' );
dep.setArtifactId( artifactId );
if ( forcedVersion == null )
{
throw new MojoExecutionException( "Cannot use dependencyRepositoryUrl without forcedVersion" );
}
dep.setVersion( forcedVersion );
ArtifactRepositoryPolicy policy = new ArtifactRepositoryPolicy();
List<ArtifactRepository> repos = Collections.singletonList(
repositoryFactory.createArtifactRepository( dependencyRepositoryId, dependencyRepositoryUrl, artifactRepositoryLayout, policy, policy) );
try
{
artifactResolver.resolve( artifactFactory.createBuildArtifact( groupIdPrefix + GROUP_API, artifactId, forcedVersion, "pom" ), repos, localRepository );
dep.setGroupId( groupIdPrefix + GROUP_API );
}
catch ( AbstractArtifactResolutionException x )
{
try
{
artifactResolver.resolve( artifactFactory.createBuildArtifact( groupIdPrefix + GROUP_IMPL, artifactId, forcedVersion, "pom" ), repos, localRepository );
dep.setGroupId( groupIdPrefix + GROUP_IMPL );
if ( wrapper.getModuleManifest().hasPublicPackages() )
{
dep.setScope( "runtime" );
}
}
catch ( AbstractArtifactResolutionException x2 )
{
try
{
artifactResolver.resolve( artifactFactory.createBuildArtifact( groupIdPrefix + GROUP_EXTERNAL, artifactId, forcedVersion, "pom" ), repos, localRepository );
dep.setGroupId( groupIdPrefix + GROUP_EXTERNAL );
if ( wrapper.getModuleManifest().hasPublicPackages() )
{
dep.setScope( "runtime" );
}
}
catch ( AbstractArtifactResolutionException x3 )
{
getLog().warn( x3.getOriginalMessage() );
throw new MojoExecutionException( "No module found for dependency '" + elem + "'", x );
}
}
}
deps.add( dep );
}
else
{
getLog().warn( "No module found for dependency '" + elem + "'" );
}
}
}
//need some generic way to handle Classpath: items.
//how to figure the right version?
String cp = wrapper.getModuleManifest().getClasspath();
if ( !cp.isEmpty() )
{
StringTokenizer tok = new StringTokenizer( cp );
while ( tok.hasMoreTokens() )
{
String path = tok.nextToken();
File f = new File( wrapper.getFile().getParentFile(), path );
if ( f.exists() )
{
Dependency dep = findExternal( searcher, f );
if ( dep != null )
{
deps.add( dep );
// XXX MNBMODULE-170: repack NBM with *.external
}
else
{
ExternalsWrapper ex = new ExternalsWrapper();
ex.setFile( f );
String artId = f.getName();
if ( artId.endsWith( ".jar" ) )
{
artId = artId.substring( 0, artId.length() - ".jar".length() );
}
ex.setVersion( wrapper.getVersion() );
ex.setArtifact( artId );
ex.setGroupid( groupIdPrefix + GROUP_EXTERNAL );
externalsList.add( ex );
dep = new Dependency();
dep.setArtifactId( artId );
dep.setGroupId( groupIdPrefix + GROUP_EXTERNAL );
dep.setVersion( wrapper.getVersion() );
dep.setType( "jar" );
deps.add( dep );
}
}
}
}
wrapper.deps = deps;
mavenModel.setDependencies( deps );
FileWriter writer = null;
File fil = null;
try
{
MavenXpp3Writer xpp = new MavenXpp3Writer();
fil = File.createTempFile( "maven", ".pom" );
fil.deleteOnExit();
writer = new FileWriter( fil );
xpp.write( writer, mavenModel );
}
catch ( IOException ex )
{
ex.printStackTrace();
}
finally
{
if ( writer != null )
{
try
{
writer.close();
}
catch ( IOException io )
{
io.printStackTrace();
}
}
}
return fil;
}
private Dependency findExternal( IndexSearcher searcher, File f )
{
if ( searcher == null )
{
return null;
}
try
{
MessageDigest shaDig = MessageDigest.getInstance( "SHA1" );
InputStream is = new FileInputStream( f );
try {
OutputStream os = new DigestOutputStream( new NullOutputStream(), shaDig );
IOUtil.copy( is, os );
os.close();
}
finally
{
is.close();
}
String sha = encode( shaDig.digest() );
TermQuery q = new TermQuery( new Term( "1", sha ) );
TopScoreDocCollector collector = TopScoreDocCollector.create( 5 );
searcher.search(q, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;
if ( hits.length >= 1 )
{
int docId = hits[0].doc;
Document doc = searcher.doc(docId);
IndexableField idField = doc.getField( "u" );
if ( idField != null )
{
String id = idField.stringValue();
String[] splits = StringUtils.split( id, "|" );
Dependency dep = new Dependency();
dep.setArtifactId( splits[1] );
dep.setGroupId( splits[0] );
dep.setVersion( splits[2] );
dep.setType( "jar" );
if ( splits.length > 3 && !"NA".equals( splits[3] ) )
{
dep.setClassifier( splits[3] );
}
getLog().info( "found match " + splits[0] + ":" + splits[1] + ":" + splits[2] + " for " + f.getName() );
return dep;
}
else
{
getLog().error( "no idField for " + q );
}
}
else
{
getLog().info( "no repository match for " + f.getName() );
}
}
catch ( Exception x )
{
getLog().error( x );
}
return null;
}
File createExternalProject( ExternalsWrapper wrapper )
{
Model mavenModel = new Model();
mavenModel.setGroupId( wrapper.getGroupid() );
mavenModel.setArtifactId( wrapper.getArtifact() );
mavenModel.setVersion( wrapper.getVersion() );
mavenModel.setPackaging( "jar" );
mavenModel.setModelVersion( "4.0.0" );
if ( artefactParent != null ) {
mavenModel.setParent( artefactParent );
}
mavenModel.setName(
"Maven definition for " + wrapper.getFile().getName() + " - external part of NetBeans module." );
mavenModel.setDescription(
"POM and identification for artifact that was not possible to uniquely identify as a maven dependency." );
FileWriter writer = null;
File fil = null;
try
{
MavenXpp3Writer xpp = new MavenXpp3Writer();
fil = File.createTempFile( "maven", ".pom" );
fil.deleteOnExit();
writer = new FileWriter( fil );
xpp.write( writer, mavenModel );
}
catch ( IOException ex )
{
ex.printStackTrace();
}
finally
{
if ( writer != null )
{
try
{
writer.close();
}
catch ( IOException io )
{
io.printStackTrace();
}
}
}
return fil;
}
private File createClusterProject( Artifact cluster, Collection<ModuleWrapper> mods )
{
Model mavenModel = new Model();
mavenModel.setGroupId( cluster.getGroupId() );
mavenModel.setArtifactId( cluster.getArtifactId() );
mavenModel.setVersion( cluster.getVersion() );
// mavenModel.setPackaging("nbm-application");
mavenModel.setPackaging( "pom" );
mavenModel.setModelVersion( "4.0.0" );
if ( artefactParent != null ) {
mavenModel.setParent( artefactParent );
}
List<Dependency> deps = new ArrayList<Dependency>();
for ( ModuleWrapper wr : mods )
{
Dependency dep = new Dependency();
dep.setArtifactId( wr.getArtifact() );
dep.setGroupId( wr.getGroup() );
dep.setVersion( wr.getVersion() );
if ( wr.getModuleManifest().isNetBeansModule() )
{
dep.setType( "nbm-file" );
}
deps.add( dep );
}
mavenModel.setDependencies( deps );
//
//
// Build build = new Build();
// Plugin plg = new Plugin();
// plg.setGroupId("org.codehaus.mojo");
// plg.setArtifactId("nbm-maven-plugin");
// plg.setVersion("2.7-SNAPSHOT");
// plg.setExtensions(true);
// build.addPlugin(plg);
// mavenModel.setBuild(build);
FileWriter writer = null;
File fil = null;
try
{
MavenXpp3Writer xpp = new MavenXpp3Writer();
fil = File.createTempFile( "maven", ".pom" );
fil.deleteOnExit();
writer = new FileWriter( fil );
xpp.write( writer, mavenModel );
}
catch ( IOException ex )
{
ex.printStackTrace();
}
finally
{
IOUtil.close( writer );
}
return fil;
}
Artifact createArtifact( String artifact, String version, String group )
{
return artifactFactory.createBuildArtifact( group, artifact, version, "jar" );
}
private Artifact createClusterArtifact( String artifact, String version )
{
return artifactFactory.createBuildArtifact( groupIdPrefix + GROUP_CLUSTER, artifact, version, "pom" );
}
private static Pattern PATTERN_CLUSTER = Pattern.compile( "([a-zA-Z]+)[0-9\\.]*" );
static String stripClusterName( String key )
{
Matcher m = PATTERN_CLUSTER.matcher( key );
if ( m.matches() )
{
return m.group( 1 );
}
return key;
}
private static class ExternalsWrapper
{
private File file;
private String artifact;
private String groupid;
public String getArtifact()
{
return artifact;
}
public void setArtifact( String artifact )
{
this.artifact = artifact;
}
public File getFile()
{
return file;
}
public void setFile( File file )
{
this.file = file;
}
public String getGroupid()
{
return groupid;
}
public void setGroupid( String groupid )
{
this.groupid = groupid;
}
public String getVersion()
{
return version;
}
public void setVersion( String version )
{
this.version = version;
}
private String version;
}
private static class ModuleWrapper
{
ExamineManifest man;
private String artifact;
private String version;
private String group;
private File file;
private String cluster;
String module;
List<Dependency> deps;
public ModuleWrapper( String module )
{
this.module = module;
}
public ModuleWrapper( String art, String ver, String grp, ExamineManifest manifest, File fil )
{
man = manifest;
artifact = art;
version = ver;
group = grp;
file = fil;
}
@Override
public int hashCode()
{
return getModule().hashCode();
}
@Override
public boolean equals( Object obj )
{
return obj instanceof ModuleWrapper && getModule().equals( ( (ModuleWrapper) obj ).getModule() );
}
public String getModule()
{
return module != null ? module : getModuleManifest().getModule();
}
public ExamineManifest getModuleManifest()
{
return man;
}
private String getArtifact()
{
return artifact;
}
private String getVersion()
{
return version;
}
private String getGroup()
{
return group;
}
private File getFile()
{
return file;
}
void setCluster( String clust )
{
cluster = clust;
}
String getCluster()
{
return cluster;
}
}
private static class NullOutputStream
extends OutputStream
{
@Override
public void write( int b )
throws IOException
{
}
}
/**
* Encodes a 128 bit or 160-bit byte array into a String.
*
* @param binaryData Array containing the digest
* @return Encoded hex string, or null if encoding failed
*/
static String encode( byte[] binaryData )
{
int bitLength = binaryData.length * 8;
if ( bitLength != 128 && bitLength != 160 )
{
throw new IllegalArgumentException(
"Unrecognised length for binary data: " + bitLength + " bits" );
}
return String.format( "%0" + bitLength / 4 + "x", new BigInteger( 1, binaryData ) );
}
}