需求:
这个问题一度困扰了我好几个小时,我一开始使用maven-assembly-plugin构建tar分发包的时候,发现每次最终打包,都会在最外层有个包装层,比如我要构建的tar分发包的artifactId为abc ,那么最终打包完的tar文件总是内含abc目录,然后才是其他子目录sub1,sub2。而我们所希望的是当untar时候,能够直接出来的是子目录(sub1,sub2),而不是abc目录+abc目录里的子目录(/abc/sub1,/abc/sub2)的形式。
解决方案:
其实只要在assembly.xml中加上<includeBaseDirectory>元素,并且让其设为false就可以了,如下:
<assembly>
<id>tarball</id>
<formats>
<format>tar</format>
</formats>
<!--fixed the wrapper folder issue-->
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
...
关于这个参数的含义,可以参见maven-assembly-plugin的官网:
http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html
深入分析:
为什么这样可以呢,我们可以对maven-assembly-plugin的源代码进行研究。
首先,当我们在pom.xml中使用maven-assembly-plugin并且在<descriptor>中配置了assembly.xml文件的位置时候:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
.....
</plugins>
</build>
插件会去调用DefaultAssemblyReader的readAssemblies()方法,然后调用如下代码进行遍历<descriptors>元素:
for ( int i = 0; i < descriptors.length; i++ )
{
getLogger().info( "Reading assembly descriptor: " + descriptors[i] );
addAssemblyFromDescriptor( descriptors[i], locator, configSource, assemblies );
}
}
我们继续跟进到addAssemblyFromDescriptor方法,可以看出它其实是用来读取一个asssembly descriptor文件(也就是我们例子中的assembly.xml),忽略参数检查,它其实核心代码如下:
private Assembly addAssemblyFromDescriptor( final String spec, final Locator locator,
final AssemblerConfigurationSource configSource,
final List<Assembly> assemblies )
throws AssemblyReadException, InvalidAssemblerConfigurationException
{
...
Reader r = null;
try
{
// TODO use ReaderFactory.newXmlReader() when plexus-utils is upgraded to 1.4.5+
r = new InputStreamReader( location.getInputStream(), "UTF-8" );
File dir = null;
if ( location.getFile() != null )
{
dir = location.getFile().getParentFile();
}
final Assembly assembly = readAssembly( r, spec, dir, configSource );
assemblies.add( assembly );
return assembly;
}
...
}
所以这里可以看出,它最终在11行新建InputStreamReader,并在第19行读取assembly descriptor文件,最终读取的结果存储在Assembly对象模型中,而Assembly这个模型是有includeBaseDirectory这个成员变量的:
/**
* Set includes a base directory in the final archive. For
* example,
* if you are creating an assembly named
* "your-app", setting
* includeBaseDirectory to true will create an
* archive that
* includes this base directory. If this option is
* set to false
* the archive created will unzip its content to
* the current
* directory. Default value is true.
*
* @param includeBaseDirectory
*/
public void setIncludeBaseDirectory( boolean includeBaseDirectory )
{
this.includeBaseDirectory = includeBaseDirectory;
} //-- void setIncludeBaseDirectory( boolean )
以上是解析assembly descriptor并且设置了includeBaseDirectory,现在我们来看下如何使用这个属性。很显然,在不看代码之前,我们很容易猜想到,它肯定影响了最终打包的行为,正如我们所期望的一样。