I have the following code:
new AntBuilder().zip( destFile: "${file}.zip" ) {
fileset( dir: srcDir ) {
include( name:pattern )
}
}
In this example I'd like ant to create a zip with the same name as the original file, but with a .zip added to the end. Is there a way to do this without knowing the original file's name ahead of time in ant? I'd like to be able to do the same thing with other ant tasks as well.
To put it another way, I'd like the filename to become whatever "pattern" resolves to for each file.
Something like this?
<target name="zip-files">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<dirset id="dirsToZip" dir="src">
<include name="dir*"/>
</dirset>
<groovy>
project.references.dirsToZip.each {
ant.zip(destfile: "${it}.zip", basedir: it)
}
</groovy>
</target>
If find the groovy task's ability to iterate thru a fileset or dirset a very useful feature.
Related
I am new to ANT.
I have a very specific scenario to handle in this:
STEP-1: I need to look for the pattern of filenames in certain ear files. If the pattern matches then I need to extract those files.
STEP-2: And if any file is extracted from a certain ear (similar to zip-file) file, then I need to search for another set of files, and copy those set of files too.
The case to handle is "How to identify if a file is copied from a particular archive" if found then proceed to step 2, else move to next archive.
I have achieved STEP-1 but no idea how to achieve step-2.
STEP-1
<!-- Set via arguments passed -->
<patternset id="pattern.needtocopy" includes="${needtocopyfile.pattern}" excludes="${ignore.pattern}">
</patternset>
<target name="get-binaries-from-baseline">
<for param="binary">
<path>
<fileset dir="${baseline.dir}/target/aaa/bbb/ccc" includes="*.ear" />
</path>
<sequential>
<basename file="#{binary}" property="#{binary}.basename" />
<unzip src="#{binary}" dest="${baseline.dir}">
<patternset refid="pattern.needtocopy" />
<mapper type="flatten" />
</unzip>
</sequential>
</for>
</target>
STEP-2:
????
Need help in this.
Thanks.
Well I resolved the same, using a groovy script based on the resources I could find.
<target name="findJars">
<zipfileset id="found" src="${ear-name}">
<patternset refid="${patternsetref}" />
</zipfileset>
<groovy>
project.references.found.each {
println it.name
println project.properties.'ear-name'
println project.properties.'dest.dir'
}
</groovy>
</target>
And then I added another task which takes this filename and ear-file-name as input and extracts the related jars based on file to search pattern.
I'm facing a very simple problem with ANT script. I have a script that loads and sets many properties loaded from several property files in file system. This properties are used to preconfigure a new project.
The question is: can I write a new property file persisting all the properties that starts with a given prefix (for example "ref.proj.*")?
The number and the name of the properties is variable and so I cannot use the
<propertyfile file="my.properties">
<entry key="ref.proj.first" value="${ref.first}"/>
...
<entry key="ref.proj.n" value="${ref.n}"/>
</propertyfile>
It's possibile to apply a filter to a propertyfile task?
Thanks in advance!
It's taking too long for me to work out all of the kinks. Sorry...
You should look at the <echoproperties> task. This will let you select the various properties and print them out in property = value format.
You could use that as your properties file itself.
The following example uses the groovy ANT task:
<path id="build.path">
<pathelement location="lib/groovy-all-2.1.0.jar"/>
</path>
<target name="create-properties">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<groovy>
new File("my.properties").withWriter { writer ->
properties.findAll { it.key.startsWith("ref.proj") }.each {
writer.println it
}
}
</groovy>
</target>
I have two directory trees:
source/aaa/bbb/ccc/file01.txt
source/aaa/bbb/file02.txt
source/aaa/bbb/file03.txt
source/aaa/ddd/file03.txt
source/file01.txt
and
template/aaa/bbb/ccc/file01.txt
template/aaa/bbb/DELETE-file03.txt
template/aaa/DELETE-ddd
template/DELETE-file01.txt
Using Ant, I want to do three things. First, I want to copy any files from "template" into "source", such that all files not starting with "DELETE-" are replaced. For example, "source/aaa/bbb/ccc/file01.txt" would be replaced. This is straightforward with:
<copy todir="source" verbose="true" overwrite="true">
<fileset dir="template">
<exclude name="**/DELETE-*"/>
</fileset>
</copy>
Second, I want to delete all files in the "source" tree whose name matches a "DELETE-" file in the corresponding directory of the "template" tree. For example, both "source/aaa/bbb/file03.txt" and "source/file01.txt" will be deleted. I have been able to accomplish this with:
<delete verbose="true">
<fileset dir="source">
<present present="both" targetdir="template">
<mapper type="regexp" from="(.*[/\\])?([^/\\]+)" to="\1DELETE-\2"/>
</present>
</fileset>
</delete>
Third, I'd like to delete any directories (empty or not) whose names match in the same way. For example, "template/aaa/DELETE-ddd" and all file(s) under it would be deleted. I'm not sure how to construct a fileset that matches directories (and all the files under them) in the "source" tree where the directory has a DELETE-* file in the "template" tree.
Is this third task even possible with Ant (1.7.1)? I'd preferrably like to do this without writing any custom ant tasks/selectors.
It seems the root issue that makes this difficult is that ant drives selectors/filesets based on files found within the target directory of fileset. Normally, however, one would want to drive things from the list of DELETE-* marker files.
The best solution I've found so far does require some custom code. I chose the <groovy> task, but also could have used <script>.
The gist: create a fileset, use groovy to add a series of excludes that skip files and directories with a DELETE-* marker, then perform the copy. This accomplishes the second and third task from my question.
<fileset id="source_files" dir="source"/>
<!-- add exclude patterns to fileset that will skip any files with a DELETE-* marker -->
<groovy><![CDATA[
def excludes = []
new File( "template" ).eachFileRecurse(){ File templateFile ->
if( templateFile.name =~ /DELETE-*/ ){
// file path relative to template dir
def relativeFile = templateFile.toString().substring( "template".length() )
// filename with DELETE- prefix removed
def withoutPrefix = relativeFile.replaceFirst( "DELETE-", "")
// add wildcard to match all files under directories
def exclude = withoutPrefix + "/**"
excludes << exclude
}
}
def fileSet = project.getReference("source_files")
fileSet.appendExcludes(excludes as String[])
]]></groovy>
<!-- create a baseline copy, excluding files with DELETE-* markers in the template directories -->
<copy todir="target">
<fileset refid="source_files"/>
</copy>
To delete a directory and its contents use delete with nested fileset, i.e. :
<delete includeemptydirs="true">
<fileset dir="your/root/directory" defaultexcludes="false">
<include name="**/DELETE-*/**" />
</fileset>
</delete>
With attribute includeemptydirs="true" the directories will be deleted too.
I'm using Ant 1.7, want to copy files from different paths (they have no relationship, so i cannot use the include selector to filter them out of their root directory). I try to use the <path> inside the <copy> instead of <fileset>, because with <path> i can specify multi paths which is in <fileset> not possible. My ant script looks like this, but it doesn't work.
<target name="copytest">
<!-- copy all files in test1 and test2 into test3 -->
<copy todir="E:/test3">
<path>
<pathelement path="C:/test1;D:/test2"></pathelement>
</path>
</copy>
</target>
Anybody has idea about how to use the <path> inside <copy>? Or maybe anybody has the advise about how to copy files from different source without selector?
Btw, i don't want to hard code the source directories, they will be read from a propertiy file, so writing multi <fileset> inside <copy> should not be considered.
thanks in advance!
This only works if the flatten attribute is set to true:
<copy todir="E:/test3" flatten="true">
<path>
<pathelement path="C:/test1;D:/test2"></pathelement>
</path>
</copy>
This is documented in the Examples section of the Ant Copy task documentation.
<pathelement> generally uses it's path attribute as a reference to classpath or some other predefined location, if you want to give specific file locations outside of the classpath try with location attribute
<pathelement location="D:\lib\helper.jar"/>
The location attribute specifies a single file or directory relative
to the project's base directory (or an absolute filename), while the
path attribute accepts colon- or semicolon-separated lists of
locations. The path attribute is intended to be used with predefined
paths - in any other case, multiple elements with location attributes
should be preferred.
We have the same problem
A bit more complicated that we need to add a specified pattern set to each fileset converted from path
For example, this is the incoming data
<path id="myDirList" path="C:/test1;D:/test2" />
<patternset id="myPatterns" includes="*.html, *.css, etc, " />
We wrote a script to solve this problem
<resources id="myFilesetGroup">
<!-- mulitiple filesets to be generated here
<fileset dir="... dir1, dir2 ...">
<patternset refid="myPatterns"/>
</fileset>
-->
</resources>
<script language="javascript"><![CDATA[
(function () {
var resources = project.getReference("myFilesetGroup");
var sourceDirs = project.getReference("myDirList").list();
var patterRef = new Packages.org.apache.tools.ant.types.Reference(project, "myPatterns");
for (var i = 0; i < sourceDirs.length; i++) {
var fileSet = project.createDataType("fileset");
fileSet.dir = new java.io.File(sourceDirs[i]);
fileSet.createPatternSet().refid = patterRef;
resources.add(fileSet);
}
})();
]]></script>
now you can use this resources in you copy task
<!-- copy all files in test1 and test2 into test3 -->
<copy todir="E:/test3">
<resources refid="myFilesetGroup">
</copy>
I tried this and works fine
<fileset file="${jackson.jaxrs.lib}"/>
For a java project I'd like to merge all third-party jars it depends on into the main jar created by Apache Ant, which I already managed to do.
The problem is that some of these jar-files have signature-files in their META-INF-directories, so when I try to run my jar-file, I get the error message "Invalid signature file digest for Manifest main attributes". After I delete the signature-files manually the error is gone.
I tried to filter the signature files out in my ant-file with an excludes-attribute or an exclude-tag, but nothing seems to have any effect.
This is the ant-task:
<target name="jar" description="Creates the jar file">
<mkdir dir="${jar}"/>
<jar destfile="${jar}/${ant.project.name}.jar" level="9" filesetmanifest="mergewithoutmain">
<zipgroupfileset dir="${lib}" includes="*.jar"/>
<zipfileset dir="${class}"/>
<manifest>
<attribute name="Main-Class" value="${mainclass}"/>
</manifest>
</jar>
</target>
How can I filter files from the resulting jar in this ant-task? Thanks for your help!
carej is right. I've been trying to do this, merging other jars into my application jar excluding some files, and there is no way to use <zipgroupfileset> for it.
My solution is a variant of the unzip/clean-up/jar method: I first merge all the external library jars into one with <zipgroupfileset>, then merge it into mine with <zipfileset> which does allow filtering. In my case it works noticeably faster and is cleaner than unzipping the files to disk:
<jar jarfile="${dist}/lib/external-libs.jar">
<zipgroupfileset dir="lib/">
<include name="**/*.jar"/>
</zipgroupfileset>
</jar>
<sleep seconds="1"/>
<jar jarfile="${dist}/lib/historadar-${DSTAMP}.jar" manifest="Manifest.txt">
<fileset dir="${build}" includes="**/*.*"/>
<zipfileset src="${dist}/lib/external-libs.jar">
<exclude name="*"/>
</zipfileset>
</jar>
The first <jar> puts all the jars it finds in lib/ into external-libs.jar, then I make it wait for one second to avoid getting warnings about the files having modification dates in the future, then I merge my class files from the build/ directory with the content of external-libs.jar excluding the files in its root, which in this case were README files and examples.
Then I have my own README file that lists all information needed about those libraries I include in my application, such as license, website, etc.
To the best of my knowledge there's no way to filter when using <zipgroupfileset>: the include/excludes used there apply to the zips to be merged, not the content within them.
If you have a well-known set of JARs to merge you could use individual <zipset> entries for each one; this approach allows using include/exclude to filter the contents of the source archive.
An alternative approach is to simply unzip everything into a temporary location, remove/modify the unwanted bits, then zip everything back up.
You can use the exclude parameter in zipfileset tag to remove content from merged external JAR files, as this:
<jar jarfile="${dist}/lib/external-libs.jar">
<zipgroupfileset dir="lib/" excludes="META-INF/**/*">
<include name="**/*.jar"/>
</zipgroupfileset>
</jar>
The resulting JAR file will be unsigned.
Alberto's answer works fine but takes time to unzip&rezip the archive. I implemented a new Ant task to use built-in filtering functions, that results in much faster execution:
public class FilterZipTask extends Task {
private Zip zipTask;
private List<FileSet> groupfilesets = new ArrayList<FileSet>();
private String excludes;
public void setExcludesInZips(String excludes) {
this.excludes = excludes;
}
public void addZipGroupFileset(FileSet set) {
groupfilesets.add(set);
}
public void addZip(Zip zipTask) {
this.zipTask = zipTask;
}
#Override
public void execute() throws BuildException {
for (FileSet fileset : groupfilesets) {
Iterator<FileResource> iterator = fileset.iterator();
while (iterator.hasNext()) {
ZipFileSet zfs = new ZipFileSet();
FileResource resource = iterator.next();
zfs.setSrc(resource.getFile());
zfs.setExcludes(excludes);
zipTask.addZipfileset(zfs);
}
}
zipTask.execute();
}
}
And use it in build file as follows:
<taskdef name="filterzip" classname="FilterZipTask"/>
<filterzip excludesInZips="META-INF/*.*">
<zipgroupfileset dir="${deps.dir}" includes="*.jar" />
<zip destfile="${destjar}" />
</filterzip>
Have been struggling with the same issue for a few hours, so ended up writing a new task by extending the existing one:
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import org.apache.tools.ant.taskdefs.Jar;
import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.ZipFileSet;
public class CustomizedJarTask extends Jar {
protected Set<String> filters;
#Override
public void add(ResourceCollection resources) {
if (filters != null && resources instanceof ZipFileSet) {
ZipFileSet set = ZipFileSet.class.cast(resources);
for (String filter : filters)
set.createExclude().setName(filter);
}
super.add(resources);
}
public void setFilters(String patterns) {
StringTokenizer tokenizer = new StringTokenizer(patterns, ", ", false);
while (tokenizer.hasMoreTokens()) {
if (filters == null)
filters = new HashSet<>();
filters.add(tokenizer.nextToken());
}
}
}
With the above, all I need in the build file is:
<taskdef name="customized-jar" classname="CustomizedJarTask" classpath="${basedir}/bin/" />
<customized-jar jarfile="${directory.build}/external-libs.jar" duplicate="fail" filters="META-INF/**">
<zipgroupfileset dir="${directory.libs}">
<include name="**/*.jar" />
</zipgroupfileset>
</customized-jar>
I was also facing same problem. Googled a lot and found something that worked for me.
Un-jar you jar file delete .
META-INF/.SF ,
META-INF/.DSA
files. Jar it again and run it should not show the error message.
Cause of error is explained here: http://qe-cafe.blogspot.in/2010/06/invalid-signature-file-digest-for.html