add ability to build a JAR with its dependencies unpacked inside.

Currently ignores META-INF in dependencies, though should probably merge things like components.xml


git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@163966 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Brett Leslie Porter 2005-04-18 07:07:58 +00:00
parent 335af74bb5
commit b6b3dafd00
3 changed files with 122 additions and 17 deletions

View File

@ -35,14 +35,19 @@
import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.IOUtil;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/** /**
* @author <a href="mailto:brett@apache.org">Brett Porter</a> * @author <a href="mailto:brett@apache.org">Brett Porter</a>
@ -52,6 +57,7 @@
* @description assemble an application bundle or distribution * @description assemble an application bundle or distribution
* @parameter name="basedir" type="String" required="true" validator="" expression="#basedir" description="" * @parameter name="basedir" type="String" required="true" validator="" expression="#basedir" description=""
* @parameter name="outputDirectory" type="java.io.File" required="true" validator="" expression="#project.build.directory" description="" * @parameter name="outputDirectory" type="java.io.File" required="true" validator="" expression="#project.build.directory" description=""
* @parameter name="workDirectory" type="java.io.File" required="true" validator="" expression="#project.build.directory/assembly/work" description="Directory to unpack JARs into if needed"
* @parameter name="descriptor" type="java.io.File" required="false" validator="" expression="#maven.assembly.descriptor" description="" * @parameter name="descriptor" type="java.io.File" required="false" validator="" expression="#maven.assembly.descriptor" description=""
* @parameter name="finalName" type="String" required="true" validator="" expression="#project.build.finalName" description="" * @parameter name="finalName" type="String" required="true" validator="" expression="#project.build.finalName" description=""
* @parameter name="descriptorId" type="String" required="false" validator="" expression="#maven.assembly.descriptorId" description="" * @parameter name="descriptorId" type="String" required="false" validator="" expression="#maven.assembly.descriptorId" description=""
@ -64,10 +70,7 @@ public class AssemblyMojo
private String basedir; private String basedir;
/** private File outputDirectory;
* @todo use java.io.File
*/
private String outputDirectory;
private File descriptor; private File descriptor;
@ -77,6 +80,8 @@ public class AssemblyMojo
private Set dependencies; private Set dependencies;
private File workDirectory;
public void execute() public void execute()
throws PluginExecutionException throws PluginExecutionException
{ {
@ -136,8 +141,8 @@ else if ( descriptorId != null )
// TODO: use component roles? Can we do that in a mojo? // TODO: use component roles? Can we do that in a mojo?
Archiver archiver = createArchiver( format ); Archiver archiver = createArchiver( format );
processFileSets( archiver, assembly.getFileSets() ); processFileSets( archiver, assembly.getFileSets(), assembly.isIncludeBaseDirectory() );
processDependencySets( archiver, assembly.getDependencySets() ); processDependencySets( archiver, assembly.getDependencySets(), assembly.isIncludeBaseDirectory() );
archiver.setDestFile( new File( outputDirectory, filename ) ); archiver.setDestFile( new File( outputDirectory, filename ) );
archiver.createArchive(); archiver.createArchive();
@ -149,14 +154,14 @@ else if ( descriptorId != null )
} }
} }
private void processDependencySets( Archiver archiver, List dependencySets ) private void processDependencySets( Archiver archiver, List dependencySets, boolean includeBaseDirectory )
throws ArchiverException throws ArchiverException, IOException
{ {
for ( Iterator i = dependencySets.iterator(); i.hasNext(); ) for ( Iterator i = dependencySets.iterator(); i.hasNext(); )
{ {
DependencySet depedencySet = (DependencySet) i.next(); DependencySet depedencySet = (DependencySet) i.next();
String output = depedencySet.getOutputDirectory(); String output = depedencySet.getOutputDirectory();
output = getOutputDirectory( output ); output = getOutputDirectory( output, includeBaseDirectory );
AndArtifactFilter filter = new AndArtifactFilter(); AndArtifactFilter filter = new AndArtifactFilter();
filter.add( new ScopeArtifactFilter( depedencySet.getScope() ) ); filter.add( new ScopeArtifactFilter( depedencySet.getScope() ) );
@ -176,13 +181,68 @@ private void processDependencySets( Archiver archiver, List dependencySets )
if ( filter.include( artifact ) ) if ( filter.include( artifact ) )
{ {
archiver.addFile( artifact.getFile(), output + artifact.getFile().getName() ); String name = artifact.getFile().getName();
if ( depedencySet.isUnpack() )
{
// TODO: something like zipfileset in plexus-archiver
// archiver.addJar( )
File tempLocation = new File( workDirectory, name.substring( 0, name.length() - 4 ) );
boolean process = false;
if ( !tempLocation.exists() )
{
tempLocation.mkdirs();
process = true;
}
else if ( artifact.getFile().lastModified() > tempLocation.lastModified() )
{
process = true;
}
if ( process )
{
unpackJar( artifact.getFile(), tempLocation );
}
archiver.addDirectory( tempLocation, null,
(String[]) getJarExcludes().toArray( EMPTY_STRING_ARRAY ) );
}
else
{
archiver.addFile( artifact.getFile(), output + name );
}
} }
} }
} }
} }
private String getOutputDirectory( String output ) private void unpackJar( File file, File tempLocation )
throws IOException
{
JarFile jar = new JarFile( file );
for ( Enumeration e = jar.entries(); e.hasMoreElements(); )
{
JarEntry entry = (JarEntry) e.nextElement();
if ( entry.isDirectory() )
{
new File( tempLocation, entry.getName() ).mkdir();
}
else
{
IOUtil.copy( jar.getInputStream( entry ),
new FileOutputStream( new File( tempLocation, entry.getName() ) ) );
}
}
}
private List getJarExcludes()
{
List l = new ArrayList( getDefaultExcludes() );
l.add( "META-INF/**" );
return l;
}
private String getOutputDirectory( String output, boolean includeBaseDirectory )
{ {
if ( output == null ) if ( output == null )
{ {
@ -194,13 +254,23 @@ private String getOutputDirectory( String output )
output += '/'; output += '/';
} }
if ( output.startsWith( "/" ) ) if ( includeBaseDirectory )
{ {
output = finalName + output; if ( output.startsWith( "/" ) )
{
output = finalName + output;
}
else
{
output = finalName + "/" + output;
}
} }
else else
{ {
output = finalName + "/" + output; if ( output.startsWith( "/" ) )
{
output = output.substring( 1 );
}
} }
return output; return output;
} }
@ -247,7 +317,10 @@ else if ( format.startsWith( "zip" ) )
else if ( format.startsWith( "jar" ) ) else if ( format.startsWith( "jar" ) )
{ {
// TODO: use MavenArchiver for manifest? // TODO: use MavenArchiver for manifest?
archiver = new JarArchiver(); JarArchiver jarArchiver = new JarArchiver();
jarArchiver.setCompress( true );
archiver = jarArchiver;
} }
else else
{ {
@ -257,7 +330,7 @@ else if ( format.startsWith( "jar" ) )
return archiver; return archiver;
} }
private void processFileSets( Archiver archiver, java.util.List fileSets ) private void processFileSets( Archiver archiver, List fileSets, boolean includeBaseDirecetory )
throws ArchiverException throws ArchiverException
{ {
for ( Iterator i = fileSets.iterator(); i.hasNext(); ) for ( Iterator i = fileSets.iterator(); i.hasNext(); )
@ -280,7 +353,7 @@ private void processFileSets( Archiver archiver, java.util.List fileSets )
output = directory; output = directory;
} }
} }
output = getOutputDirectory( output ); output = getOutputDirectory( output, includeBaseDirecetory );
String[] includes = (String[]) fileSet.getIncludes().toArray( EMPTY_STRING_ARRAY ); String[] includes = (String[]) fileSet.getIncludes().toArray( EMPTY_STRING_ARRAY );
if ( includes.length == 0 ) if ( includes.length == 0 )

View File

@ -29,6 +29,11 @@
<multiplicity>*</multiplicity> <multiplicity>*</multiplicity>
</association> </association>
</field> </field>
<field>
<name>includeBaseDirectory</name>
<type>boolean</type>
<defaultValue>true</defaultValue>
</field>
<field> <field>
<name>fileSets</name> <name>fileSets</name>
<version>1.0.0</version> <version>1.0.0</version>
@ -89,6 +94,11 @@
<version>1.0.0</version> <version>1.0.0</version>
<type>String</type> <type>String</type>
</field> </field>
<field>
<name>unpack</name>
<type>boolean</type>
<defaultValue>false</defaultValue>
</field>
<field> <field>
<name>scope</name> <name>scope</name>
<version>1.0.0</version> <version>1.0.0</version>

View File

@ -0,0 +1,22 @@
<assembly>
<!-- TODO: a jarjar format would be better -->
<id>jar-with-dependencies</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<!-- TODO: use expressions instead: ${project.build.directory}, ${project.build.finalName}, or have a <build /> tag to include the built artifact -->
<directory>target/classes</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>