Code generation using Ant - ant

I would like to generate a file from an intermixed content of inline code snippets and contents of other files. Something like:
<target name="generate-js-function">
<concat destfile="mycode.js">
<header trimleading="yes">
// begin auto generated
var create = function() {
function createHtmlSnippet1() {
</header>
<fileset file="snippet1.js"/>
<header>
}
</header>
<header trimleading="yes">
// begin auto generated
var create = function() {
function createHtmlSnippet2() {
</header>
<fileset file="snippet2.js"/>
<header>
}
</header>
return '' + createHtmlSnippet1() + createHtmlSnippet2();
}
// end auto generated
</header>
</concat>
</target>
AFAIK, there can be only one header / footer, so what's the proper way to do it?
Update: if anything in the question isn't clear - please ask - I'll clarify happily.

For the inline snippets you can use the string resource:
<concat destfile="mycode.js">
<string>
// begin auto generated
var create = function() {
function createHtmlSnippet1() {
</string>
<fileset file="snippet1.js"/>
<string>
}
</string>
...
</concat>
The only downside is that it doesn't support the trimleading attribute, but it will allow you to have the code inline in your build file.

Write each inline JS portion into its own file, and concat all the files.
You can use the echo task to write to temp files dynamically from the ant build file, and then concat the snippet files and the temp files.

Related

How to concatenate paths returned from `fileset` into the XML file?

I'm trying to concatenate an unknown number of HTML files into one XML file.
That's no problem with:
<concat destfile="${temp.dir}/file.xml" encoding="UTF-8" outputencoding="UTF-8">
<fileset dir="${html.dir}" includes="**/*.html" />
</concat>
Now what I would like to do is, for each file of the fileset, insert its path into the concatenated file.
Example
I have the following HTML files in C:\whatever\sources:
A.html
B.html
In the result XML file, I'd like to get:
<allfiles>
<html url="C:\whatever\sources\A.html>...content of A.html...</html>
<html url="C:\whatever\sources\B.html>...content of B.html...</html>
</allfiles>
Is there a way to do that simply without reinventing the wheel and if possible without using ant-contrib?
As mentioned, you can use a scriptfilter inside filterchain task to run Javascript inside your Ant build.
For example:
<concat destfile="${temp.dir}/file.xml" encoding="UTF-8" outputencoding="UTF-8">
<fileset dir="${html.dir}" includes="**/*.html" id="my-files"/>
<filterchain>
<tokenfilter>
<filetokenizer />
<scriptfilter language="javascript" byline="false"><![CDATA[
content = self.getToken();
// Modify content of token.
//content=content.replaceAll("(?s)/\\*.*?\\*/","");
self.setToken(content);
]]></scriptfilter>
</tokenfilter>
<striplinecomments>
<comment value="//"/>
</striplinecomments>
<striplinebreaks/>
</filterchain>
</concat>
Find more examples at:
JavaExplorer/blob/master/static/build.xml
Getting file name inside Ant copy task filter
Using Ant scriptfilter to count lines

Ant copy task corrupts UTF-8 symbols

I have a .properties file with translations in Arabic. I am using it to replace strings in an html file. However, when I start the copy task, it completely corrupts the symbols and I get something like this:
اÙÙزادات
Any idea what's causing this and how I can fix it?
build.xml
<target name="copyAndReplace">
<copy todir="..." overwrite="yes" encoding="UTF-8">
<fileset dir="..." includes="*.html"></fileset>
<filterset>
<filtersfile file="***.properties" />
</filterset>
</copy>
</target>
I see some possible problems:
In Java, Properties files are assumed to have ISO-8859-1 encoding. Even if you're not dealing directly with Java, ant is reading a property file. I've run into this problem when opening a property file in Vim and NetBeans editor. Vim saved it in UTF-8 and NetBeans in ISO-8859-1.
You should use the outputencoding attribute of copy task. In Windows, UTF-8 is not the default encoding.
i encountered the same issue, but with images.
In the ant manual i found the following remark:
Note: If you employ filters in your copy operation, you should limit the copy to text files. Binary files will be corrupted by the copy operation. This applies whether the filters are implicitly defined by the filter task or explicitly provided to the copy operation as filtersets. See encoding note.
Maybe that is the source of the problem. I will need to check on my own whether this solves my problem.
Kind regards,
Marc
As mentioned by #Jean Waghetti above, ANT expects the files to be ISO-8859-1 encoded. I posted a similar stack overflow question for Chinese characters.
The only solution I've found is by ensuring my .properties file was ISO-8859-1 and the characters were escaped.
For example مرحبا بالعالم
Would be:
\u0645\u0631\u062D\u0628\u0627 \u0628\u0627\u0644\u0639\u0627\u0644\u0645
This is not ideal as it's not terribly human-readable. I have noticed that eclipse automatically converts it on hover.
You can add some code to translate the utf-8 properties to iso-8859-1 properties and the use the converted and escaped properties
<project name="xyz" default="copyAndReplace">
<property name="srcdir" value="src" />
<property name="propdir" value="src" />
<property name="tmpdir" value="tmp" />
<target name="encodeProps">
<script language="javascript">
importPackage(java.io);
importPackage(java.lang);
var files = new java.io.File(propdir).listFiles();
for (var i in files) {
var f = files[i];
if (!f.getName().endsWith(".properties")) continue;
var io = new InputStreamReader(new FileInputStream(f), "utf-8");
var out = new FileOutputStream(new File(tmpdir, f.getName()));
do {
var c = io.read();
if (c == -1) break;
if (c > 127) {
var s = Integer.toHexString(c);
s = new StringBuilder().append("\\u").append("0000".substring(s.length())).append(s).toString();
out.write(s.getBytes());
} else {
out.write(c);
}
} while (true);
io.close();
out.close();
}
</script>
</target>
<target name="copyAndReplace" depends="encodeProps">
<copy todir="dst" overwrite="yes" encoding="UTF-8" filtering="true">
<fileset dir="${srcdir}" includes="*.html">
</fileset>
<filterset>
<filtersfile file="${tmpdir}/c.properties" />
</filterset>
</copy>
</target>
</project>

Copy one value over to another with xmltask

Is it possible for an xml task to copy the value of one node into another node for each element in a list?
Source XML:
<a>
<b>
<c1>foo</c1>
<c2></c2>
</b>
<b>
<c1>bar</c1>
<c2></c2>
</b>
...
</a>
Destination XML:
<a>
<b>
<c1>foo</c1>
<c2>foo</c2>
</b>
<b>
<c1>bar</c1>
<c2>bar</c2>
</b>
...
</a>
I'm trying to accomplish the above in my ant task, but I con't seem to find a way to do it, here is what I am doing so far,
<target name="mergefile">
<!-- Read the source into a buffer -->
<xmltask source="source.xml" clearBuffers="list">
<copy path="/a" buffer="list" append="true"/>
</xmltask>
<!-- Write them to the output -->
<xmltask source="destination.xml" dest="destination.xml"
outputter="simple">
<!-- First clear all the old paths. -->
<remove path="/a/b"/>
<!-- Then add the resolved ones. -->
<paste path="/a" buffer="list"></paste>
<!-- Copy the value over? -->
<replace path="a/b/c2/text()" withText="No Idea"/>
</xmltask>
</target>
Any idea of how to copy the value from one node to the next for all the elements in the list?
As, I guess, is usually the case, writing my own task was the only way I could see to do it.
#Override
public void execute() throws BuildException {
//Read file line by line, regex test on each line,
//matches get written back twice.
}
Then calling it was,
<copyregmatch file="myfile.xml" regex=".*replace.*" />

Apache Ant add header & footer to EVERY file in concat job

I'm sure that this is trivial - but have been bashing my head against a wall
I'm trying to take a directory full of mustache templates (html files essentially) and combine them into one file - wrapping each one with a tag
Example:
File1 = <a>This is a Link</a>
File2 = <b>This is in bold</b>
I want the output to look like:
<script type="text/mustache" id="File1">
<a>This is a Link</a>
</script>
<script type="text/mustache" id="File2">
<b>This is in bold</b>
</script>
I'm using a concat task
<concat destfile="mustache.js" fixlastline="yes">
<fileset dir="." includes="**/*.mustache"/>
</concat>
but can't figure out how to get the script blocks to display
At first i thought about using concat somehow with header and footer but didn't find a working solution.
If you not shy away from using some Ant addon, here's a solution based on Flaka =
<project name="demo" xmlns:fl="antlib:it.haefelinger.flaka">
<!-- make standard ant tasks understand EL expressions -->
<fl:install-property-handler />
<!-- we use path instead of pure fileset because we need
absolute filenames for loadfile later in for loop -->
<path id="foo">
<fileset dir="/some/path" includes="**/*.mustache"/>
</path>
<!-- iterate over the path/fileset -->
<fl:for var="file" in="split('${toString:foo}', ':')">
<!-- unset property for next loop -->
<fl:unset>content</fl:unset>
<!-- load file contents to property -->
<loadfile property="content" srcFile="#{file}"/>
<echo file="/some/path/foobar/mustache.js" append="true">
<!-- the id attribute gets filled with the basename of the current fileitem -->
<![CDATA[<script type="text/mustache" id="#{replace(file, '$1' , '.+?(\w+)\..+' )}">
#{trim('${content}')}
</script>]]></echo>
</fl:for>
</project>
Note : 1. my leftmost notation within the echo task to avoid unnecessary blanks in the resulting file ! just write as in my example above and your file will look like your wanted output
2. the <![CDATA[...]]> is needed, otherwise you'll get some error like "echo doesn't support the nested "script" element."

Ant: Exclude files from merged jar file

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

Resources