How to preserve file order in Ant concat? - ant

How to preserve file order in Ant concat?
Simple concat with fileset & includesfile produces rather "random" order, as order is not guaranteed:
<concat destfile="C:/targetdir/concatenated.file">
<fileset dir="C:/sourcedir/">
<includesfile name="C:/targetdir/includes.file" />
</fileset>
</concat>
What I need is concatenation in specific order that the files are listed in the includes file.
So far I've found resourcelist, which should preserve order, but I can't seem to be able to produce any concatenated file with it. :/
<concat destfile="C:/targetdir/concatenated.file">
<resourcelist>
<file file="C:/targetdir/includes.file"/>
<filterchain>
<striplinecomments>
<comment value="#"/>
</striplinecomments>
<prefixlines prefix="C:/sourcedir/"/>
</filterchain>
</resourcelist>
</concat>
Plus, the resourcelist can't seem to handle rows like
LibraryX/A/Stuff/Morestuff/*
Instead the row just produces a ".../Morestuff/* does not exist." -error
Includes file has list of relative paths:
LibraryX/A/Stuff/FileA.txt
LibraryX/A/Stuff/FileB.txt
LibraryX/A/Stuff/FileC.txt
LibraryX/A/Stuff/FileY.txt

I was able to get a filelist working pretty easily:
<concat destfile="C:/targetdir/concatenated.file">
<filelist dir="C:/sourcedir/">
<file name="i.txt" />
<file name="n.txt" />
<file name="o.txt" />
<file name="r.txt" />
<file name="d.txt" />
<file name="e.txt" />
<file name="r.txt" />
</filelist>
</concat>
Hope that helps!

If you are using Ant 1.7+, you can use the sort command
<concat destfile="C:/targetdir/concatenated.file">
<sort>
<fileset dir="C:/sourcedir/">
<include name="C:/targetdir/*.file" />
</fileset>
</sort>
</concat>
You can find the documentation of sort here

[On Ant 1.8.2+] You can also pass the fileset via a sort, and sort on filename, like below:
<concat destfile="./${dir.publish}/${dir.js}/b.main-${build.number}.debug.js">
<sort xmlns:rcmp="antlib:org.apache.tools.ant.types.resources.comparators">
<fileset dir="./${dir.publish}/">
<include name="**/${dir.js.main}/**/*.js"/>
<exclude name="**/${dir.js.main}/**/*.min.js"/>
</fileset>
<rcmp:name />
</sort>
</concat>
Couple of things to watch out for:
Directories are sorted before files
Capitals come before lowercase
UPDATE: Another alternative if you need to manually specify order:
<!-- create a ordered list of all the build files so that CIAPI & CIAPI.widget are built first
(can't find a smarter way to do this, since ant filesets are unordered) -->
<fileset id="a" dir="."><include name="CIAPI/build.project.xml"/></fileset>
<fileset id="b" dir="."><include name="CIAPI.widget/build.project.xml"/></fileset>
<fileset id="c" dir=".">
<include name="**/build.project.xml"/>
<exclude name="CIAPI/build.project.xml" />
<exclude name="CIAPI.widget/build.project.xml" />
</fileset>
<union id="all_build_files">
<fileset refid="a"/>
<fileset refid="b"/>
<fileset refid="c"/>
</union>
Ugly, but, erm, this is ant?

try this, put in alphabetical order
<project name="concatPath" default="full">
<target name="full">
<fileset id="fs" dir="./files" />
<pathconvert refid="fs" property="concatList" pathsep=";" targetos="unix"/>
<echo>${concatList}</echo>
</target>
</project>
this can be used with hierarchical structure of directories, and the order will be the exposed by David.

Remember that XML is not order-dependent, by definition.
To concatenate files in a sorted order, consider using <replace> instead.
Create an order file that defines the order. Then, in your build file:
Copy the order file to the destination file with <copy>
Concatenate your files together into a temporary file with <concat>
Load the files into properties with <loadfile>
Insert the text from those files into the destination file with <replace>
Example order file order_file.txt:
FILE_A_HERE
CONCAT_FILES_HERE
Example ant build file build.xml:
<copy file="order_file.txt" tofile="destination.txt" overwrite="yes">
<concat destfile="tempfile.txt">
<fileset dir="includes/">
<include name="*.txt">
<exclude name="fileA.txt">
</fileset>
</concat>
<loadfile property="fileA" srcFile="includes/fileA.txt" />
<loadfile property="concatFile" srcFile="tempfile.txt" />
<replace file="destination.txt" token="FILE_A_HERE" value="fileA" />
<replace file="destination.txt" token="CONCAT_FILES_HERE" value="concatFile" />

Related

Ant: how to remove the first and last lines of files in a folder and concatenate them all together?

I wrote sth. like this:
<project>
<concat destfile="myDir/concat_file.txt" append="true">
<fileset dir="myDir">
<include name="**/*.txt" />
<exclude name="**/concat_file.txt” />
</fileset>
<filterchain>
<headfilter lines="-1" skip="1" />
<tailfilter lines="-1" skip="1" />
</filterchain>
</concat>
</project>
I can concatenate all the files in the folder, but the filterchain part works only for the first file. How can I make it iteratively for all the files in the folder and then do the concatenation?

Ant concat exclude directory

My application folder structure looks like this...
-js
-libs
-jquery.js
-jquery-ui.js
-app.js
-ui.js
I wish to concatenate the .js files that are in the /js directory but not those in the /js/libs directory. I am using the following code, but it is ignoring the exclude statement:
<concat destfile="${build.dir}/js/foot-${build.major}-${build.minor}.concat.js">
<fileset dir="${build.dir}/js">
<exclude name="**/libs/**" />
</fileset>
</concat>
The <fileset> should specify both include and exclude patterns. In addition, it may be good to specify a destination directory for <concat> separate from the <fileset> input directory.
<target name="concat-test">
<concat destfile="${basedir}/concat.js" fixlastline="yes">
<fileset dir="${basedir}/js">
<include name="**/*.js" />
<exclude name="**/libs/**" />
</fileset>
</concat>
</target>

How to to control the order of merge in Ant file

I have this code which takes all the files in the folder collection and merges them with the covers.js file. The problem is there are 2 files inside of collections that need to be merged below covers.
But possibly I may want to control the order of how the files are being merged from the collection
folder. IS there a dependency attribute I can use.
<target name="merge box">
<echo>${box.file}</echo>
<concat destfile="${box.file}" fixlastline="yes" append="no">
<fileset dir="${js.src.dir}/components/covers/" includes="**/*.js"/>
<fileset dir="${js.src.dir}/collection/" includes="**/*.js" excludes="base.js"/>
</concat>
</target>
Update
I also tried this but still doesn't work.
<fileset dir="${js.src.dir}/collection" >
<includesfile name="Templates.js" />
<includesfile name="popup.js" />
<includesfile name="popup-extend.js" />
</fileset>
Latest Update
Tried this and it works but it doesn't hold the order of the include files.
<target name="merge box">
<echo>${box.file}</echo>
<concat destfile="${box.file}" fixlastline="yes" append="no">
<fileset dir="${js.src.dir}/components/covers/" includes="**/*.js"/>
<fileset dir="${js.src.dir}/collection" >
<include name="Templates.js" />
<include name="popup.js" />
<include name="popup-extend.js" />
</fileset>
</concat>
</target>
popup-extend is meant to be merged below the popup code but its not doing that matter what order I put them in it will always put it in this order.
Templates
popup
popup-extend
The order I'm trying to get it in is
Templates
popup-extend
popup
Try this:
<target name="merge box">
<echo>${box.file}</echo>
<concat destfile="${box.file}" fixlastline="yes" append="no">
<fileset dir="${js.src.dir}/components/covers/" includes="**/*.js"/>
<fileset file="${js.src.dir}/collection/Templates.js" />
<fileset file="${js.src.dir}/collection/popup.js" />
<fileset file="${js.src.dir}/collection/popup-extend.js" />
</concat>
</target>
Or look here: How to preserve file order in Ant concat?

How can I exclude files from a reference path in Ant?

In a project we have several source paths, so we defined a reference path for them:
<path id="de.his.path.srcpath">
<pathelement path="${de.his.dir.src.qis.java}"/>
<pathelement path="${de.his.dir.src.h1.java}"/>
...
</path>
Using the reference works fine in the <javac> tag:
<src refid="de.his.path.srcpath" />
In the next step, we have to copy non-java files to the classpath folder:
<copy todir="${de.his.dir.bin.classes}" overwrite="true">
<fileset refid="de.his.path.srcpath">
<exclude name="**/*.java" />
</fileset>
</copy>
Unfortunately, this does not work because "refid" and nested elements may not be mixed.
Is there a way I can get a set of all non-java files in my source path without copying the list of source paths into individual filesets?
Here's an option. First, use the pathconvert task to make a pattern suitable for generating a fileset:
<pathconvert pathsep="/**/*,"
refid="de.his.path.srcpath"
property="my_fileset_pattern">
<filtermapper>
<replacestring from="${basedir}/" to="" />
</filtermapper>
</pathconvert>
Next make the fileset from all the files in the paths, except the java sources. Note the trailing wildcard /**/* needed as pathconvert only does the wildcards within the list, not the one needed at the end:
<fileset dir="." id="my_fileset" includes="${my_fileset_pattern}/**/*" >
<exclude name="**/*.java" />
</fileset>
Then your copy task would be:
<copy todir="${de.his.dir.bin.classes}" overwrite="true" >
<fileset refid="my_fileset" />
</copy>
For portability, instead of hard-coding the unix wildcard /**/* you might consider using something like:
<property name="wildcard" value="${file.separator}**${file.separator}*" />

How can I print a fileset to a file, one file name per line?

I have a populated fileset and I need to print the matching filenames into a text file.
I tried this:
<fileset id="myfileset" dir="../sounds">
<include name="*.wav" />
<include name="*.ogg" />
</fileset>
<property name="sounds" refid="myfileset" />
<echo file="sounds.txt">${sounds}</echo>
which prints all the files on a single line, separated by semicolons. I need to have one file per line. How can I do this without resorting to calling OS commands or writing Java code?
UPDATE:
Ah, should have been more specific - the list must not contain directories. I'm marking ChssPly76's as the accepted answer anyway, since the pathconvert command was exactly what I was missing. To strip the directories and list only the filenames, I used the "flatten" mapper.
Here is the script that I ended up with:
<fileset id="sounds_fileset" dir="../sound">
<include name="*.wav" />
<include name="*.ogg" />
</fileset>
<pathconvert pathsep="
" property="sounds" refid="sounds_fileset">
<mapper type="flatten" />
</pathconvert>
<echo file="sounds.txt">${sounds}</echo>
Use the PathConvert task:
<fileset id="myfileset" dir="../sounds">
<include name="*.wav" />
<include name="*.ogg" />
</fileset>
<pathconvert pathsep="${line.separator}" property="sounds" refid="myfileset">
<!-- Add this if you want the path stripped -->
<mapper>
<flattenmapper />
</mapper>
</pathconvert>
<echo file="sounds.txt">${sounds}</echo>
Since Ant 1.6 you can use toString:
<echo file="sounds.txt">${toString:myfileset}</echo>

Resources