org.codehaus.mojo.natives.plugin.NativeLinkMojo Maven / Gradle / Ivy
package org.codehaus.mojo.natives.plugin;
/*
* The MIT License
*
* Copyright (c) 2004, The Codehaus
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.plugin.MojoExecutionException;
import org.codehaus.mojo.natives.NativeBuildException;
import org.codehaus.mojo.natives.linker.Linker;
import org.codehaus.mojo.natives.linker.LinkerConfiguration;
import org.codehaus.mojo.natives.manager.LinkerManager;
import org.codehaus.mojo.natives.manager.NoSuchNativeProviderException;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.StringUtils;
/**
* Link all previously built object and dependent library files into final build
* artifact
*
* @goal link
* @phase package
* @requiresDependencyResolution
*/
public class NativeLinkMojo
extends AbstractNativeMojo
{
/**
* Override this property if permitted by compilerProvider
*
* @parameter default-value="generic"
* @required
* @since 1.0-alpha-2
*/
private String compilerProvider;
/**
* Default value is ${compilerProvider}
*
* @parameter
* @since 1.0-alpha-2
*/
private String linkerProvider;
/**
* Override this property if permitted by linkerProvider. Default to compilerType if not provided
*
* @parameter
* @since 1.0-alpha-2
*/
private String linkerExecutable;
/**
* Additional linker command options
* @parameter
* @since 1.0-alpha-2
*/
private List linkerStartOptions;
/**
* Additional linker command options
* @parameter
* @since 1.0-alpha-2
*/
private List linkerMiddleOptions;
/**
* Additional linker command options
* @parameter
* @since 1.0-alpha-2
*/
private List linkerEndOptions;
/**
* Option to reorder dependency list, each item has the format of
* ${groupId}:${artifactId}
*
* @parameter
* @since 1.0-alpha-2
*/
private List linkingOrderLibs;
/**
* Comma separated extension type to be installed/deployed. Use this option
* to deploy library file produced by dll build on windows
*
* @parameter default-value=""
* @since 1.0-alpha-2
*/
private String linkerSecondaryOutputExtensions = "";
/**
* Where to place the final packaging
* @parameter default-value="${project.build.directory}"
* @required
* @since 1.0-alpha-2
*/
protected File linkerOutputDirectory;
/**
* Internal
* @component
* @since 1.0-alpha-2
*/
private LinkerManager manager;
/**
* Internal
* @component
* @since 1.0-alpha-2
*/
private ArtifactFactory artifactFactory;
/**
* Dependent libraries with version + classifier removed are copied to this
* directory to be linked to the build artifact
*
* @parameter default-value="${project.build.directory}/lib"
* @required
*/
private File externalLibDirectory;
/**
* Option to install primary artifact as a classifier, useful to install/deploy
* debug artifacts
* @parameter
* @since 1.0-alpha-2
*/
private String classifier = null;
/**
* Attach the linker's outputs to maven project be installed/deployed. Turn this off if you have
* other mean of deployment, for example using maven-assembly-plugin to deploy your own bundle
* @parameter default-value="true"
* @since 1.0-alpha-2
*/
private boolean attach = true;
public void execute()
throws MojoExecutionException
{
if ( StringUtils.isEmpty( this.classifier ) )
{
this.classifier = null;
}
Linker linker = this.getLinker();
this.config = this.createLinkerConfiguration();
try
{
List allCompilerOuputFiles = this.getAllCompilersOutputFileList();
File outputFile = linker.link( config, allCompilerOuputFiles );
//to be used by post linker mojo like native:manifest
this.getPluginContext().put( AbstractNativeMojo.LINKER_OUTPUT_PATH, outputFile );
}
catch ( IOException ioe )
{
throw new MojoExecutionException( ioe.getMessage(), ioe );
}
catch ( NativeBuildException nbe )
{
throw new MojoExecutionException( nbe.getMessage(), nbe );
}
if ( this.attach )
{
this.attachPrimaryArtifact();
this.attachSecondaryArtifacts();
}
}
private LinkerConfiguration createLinkerConfiguration()
throws MojoExecutionException
{
LinkerConfiguration config = new LinkerConfiguration();
config.setWorkingDirectory( this.workingDirectory );
config.setExecutable( this.linkerExecutable );
config.setStartOptions( removeEmptyOptions( this.linkerStartOptions ) );
config.setMiddleOptions( removeEmptyOptions( this.linkerMiddleOptions ) );
config.setEndOptions( removeEmptyOptions( this.linkerEndOptions ) );
config.setOutputDirectory( this.linkerOutputDirectory );
config.setOutputFileName( this.project.getBuild().getFinalName() );
config.setOutputFileExtension( this.project.getArtifact().getArtifactHandler().getExtension() );
config.setExternalLibDirectory( this.externalLibDirectory );
config.setExternalLibFileNames( this.getLibFileNames() );
config.setEnvFactory( this.getEnvFactory() );
return config;
}
private Linker getLinker()
throws MojoExecutionException
{
Linker linker;
try
{
if ( this.linkerProvider == null )
{
this.linkerProvider = this.compilerProvider;
}
linker = this.manager.getLinker( this.linkerProvider );
}
catch ( NoSuchNativeProviderException pe )
{
throw new MojoExecutionException( pe.getMessage() );
}
return linker;
}
/**
*
*/
private void attachPrimaryArtifact()
{
Artifact artifact = this.project.getArtifact();
if ( null == this.classifier )
{
artifact.setFile( new File( this.linkerOutputDirectory + "/" + this.project.getBuild().getFinalName() + "."
+ this.project.getArtifact().getArtifactHandler().getExtension() ) );
}
else
{
//install primary artifact as a classifier
DefaultArtifact clone = new DefaultArtifact( artifact.getGroupId(), artifact.getArtifactId(), artifact
.getVersionRange().cloneOf(), artifact.getScope(), artifact.getType(), classifier, artifact
.getArtifactHandler(), artifact.isOptional() );
clone.setRelease( artifact.isRelease() );
clone.setResolvedVersion( artifact.getVersion() );
clone.setResolved( artifact.isResolved() );
clone.setFile( artifact.getFile() );
if ( artifact.getAvailableVersions() != null )
{
clone.setAvailableVersions( new ArrayList( artifact.getAvailableVersions() ) );
}
clone.setBaseVersion( artifact.getBaseVersion() );
clone.setDependencyFilter( artifact.getDependencyFilter() );
if ( artifact.getDependencyTrail() != null )
{
clone.setDependencyTrail( new ArrayList( artifact.getDependencyTrail() ) );
}
clone.setDownloadUrl( artifact.getDownloadUrl() );
clone.setRepository( artifact.getRepository() );
clone.setFile( new File( this.linkerOutputDirectory + "/" + this.project.getBuild().getFinalName() + "."
+ this.project.getArtifact().getArtifactHandler().getExtension() ) );
project.setArtifact( clone );
}
}
private void attachSecondaryArtifacts()
{
String[] tokens = StringUtils.split( this.linkerSecondaryOutputExtensions, "," );
for ( int i = 0; i < tokens.length; ++i )
{
// TODO: shouldn't need classifier
Artifact artifact = artifactFactory.createArtifact( project.getGroupId(), project.getArtifactId(), project
.getVersion(), this.classifier, tokens[i].trim() );
artifact.setFile( new File( this.linkerOutputDirectory + "/" + this.project.getBuild().getFinalName() + "."
+ tokens[i].trim() ) );
project.addAttachedArtifact( artifact );
}
}
private List getLibFileNames()
throws MojoExecutionException
{
List libList = new ArrayList();
Set artifacts = this.project.getArtifacts();
for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
if ( INCZIP_TYPE.equals( artifact.getType() ) )
{
continue;
}
String libFileName = FileUtils.filename( this.getDependencyFile( artifact, true ).getPath() );
libList.add( libFileName );
}
libList = this.reorderLibDependencies( libList );
return libList;
}
/**
* convert dependencyLinkingOrders to a file list
*
* @return
*/
private List getDependenciesFileOrderList()
throws MojoExecutionException
{
List list = new ArrayList();
if ( this.linkingOrderLibs != null )
{
for ( Iterator i = linkingOrderLibs.iterator(); i.hasNext(); )
{
String element = i.next().toString();
Artifact artifact = lookupDependencyUsingGroupArtifactIdPair( element );
if ( artifact != null )
{
String libFileName = FileUtils.filename( this.getDependencyFile( artifact, false ).getPath() );
list.add( libFileName );
}
else
{
throw new MojoExecutionException( element + " not found on project dependencies." );
}
}
}
return list;
}
/**
* Look up library in dependency list using groupId:artifactId key
* Note: we can not use project.artifactMap due the introduction of inczip dependency
* where 2 dependency with the same artifactId and groupId, but differs by extension type
* make the map not suitable for lookup
*
* @param groupArtifactIdPair
* @return
* @throws MojoExecutionException
*/
private Artifact lookupDependencyUsingGroupArtifactIdPair( String groupArtifactIdPair )
throws MojoExecutionException
{
String [] tokens = StringUtils.split( groupArtifactIdPair, ":" );
if ( tokens.length != 2 )
{
throw new MojoExecutionException( "Invalid groupId and artifactId pair: " + groupArtifactIdPair );
}
Set allDependencyArtifacts = project.getDependencyArtifacts();
for ( Iterator iter = allDependencyArtifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
if ( INCZIP_TYPE.equals( artifact.getType() ) )
{
continue;
}
if ( tokens[0].equals( artifact.getGroupId()) && tokens[1].equals( artifact.getArtifactId() ) )
{
return artifact;
}
}
return null;
}
private List reorderLibDependencies( List libs )
throws MojoExecutionException
{
List requestedOrderList = getDependenciesFileOrderList();
if ( requestedOrderList.size() != 0 )
{
// remove from original list first
for ( Iterator i = requestedOrderList.iterator(); i.hasNext(); )
{
libs.remove( i.next() );
}
for ( Iterator i = libs.iterator(); i.hasNext(); )
{
requestedOrderList.add( i.next() );
}
return requestedOrderList;
}
else
{
return libs;
}
}
private File getDependencyFile( Artifact artifact, boolean doCopy )
throws MojoExecutionException
{
File newLocation = artifact.getFile();
newLocation = new File( this.externalLibDirectory, artifact.getArtifactId() + "."
+ artifact.getArtifactHandler().getExtension() );
try
{
if ( doCopy && ( !newLocation.exists() || newLocation.lastModified() <= artifact.getFile().lastModified() ) )
{
FileUtils.copyFile( artifact.getFile(), newLocation );
}
}
catch ( IOException ioe )
{
throw new MojoExecutionException( "Unable to copy dependency to staging area. Could not copy "
+ artifact.getFile() + " to " + newLocation, ioe );
}
return newLocation;
}
////////////////////////////////////// UNIT TEST HELPERS //////////////////////////////////
/**
* For unittest only
*/
private LinkerConfiguration config;
protected LinkerConfiguration getLgetLinkerConfiguration()
{
return this.config;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy