需求:
这个问题一度困扰了我好几个小时,我一开始使用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,现在我们来看下如何使用这个属性。很显然,在不看代码之前,我们很容易猜想到,它肯定影响了最终打包的行为,正如我们所期望的一样。