How to use filelist as fileset in uptodate Ant command? - ant

I have a target of build.xml that creates a Zip file. To avoid creating the Zip if no file has been updated, I'd like to check for updates beforehand. AFAIK, uptodate is the task to use.
Here is the relevant (simplified) script sections:
<filelist id="zip-files">
<file name="C:/main.exe" />
<file name="D:/other.dll" />
</filelist>
<target name="zip" depends="zip-check" unless="zip-uptodate">
<zip destfile="${zip-file}" >
<filelist refid="zip-files" />
</zip>
</target>
<target name="zip-check">
<uptodate property="zip-uptodate"
targetfile="${zip-file}">
<srcfiles refid="zip-files" />
</uptodate>
</target>
However, uptodate fails because srcfiles must reference a fileset, not a filelist. Still, I can't use a fileset because it would require a dir attribute, which I can't set because source files do not share a base directory.
Of course, I could just copy all files to a common directory before zipping them, thus being able to use fileset, but I was wondering whether there was an alternative solution.
I'm using Ant 1.8.1

Instead of using <srcfiles>, try using <srcresources>. <srcfiles> must be a fileset, but <srcresource> can be a union of any collection of resources, and that should include a filelist.
I can't do any test right now, but it should look something like this:
<filelist id="zip-files">
<file name="C:/main.exe" />
<file name="D:/other.dll" />
</filelist>
<target name="zip" depends="zip-check" unless="zip-uptodate">
<zip destfile="${zip-file}" >
<filelist refid="zip-files" />
</zip>
</target>
<target name="zip-check">
<union id="zip-union">
<filelist refid="zip-files"/>
</union>
<uptodate property="zip-uptodate"
targetfile="${zip-file}">
<srcresources refid="zip-union" />
</uptodate>
</target>
Hope it works for you.

Related

Exclude files in ant-migration tool while deploying

I am new to salesforce. We are using ant-migration tool. There are a few classes/dashboards/triggers that we are trying to exclude using file sets. All of the below folders are inside src.
<property file="build.properties"/>
<property name="src.dir" value="../src"/>
<fileset dir="${src.dir}" casesensitive="yes">
<echo message="Inside file set"/>
<exclude name="**/classes/Abs*.cls"/>
</fileset>
<target name="deploy">
<sf:deploy
username="${sf.username}.${org}"
password="${sf.password}${sf.securitytoken}"
serverurl="${sf.serverurl}"
checkOnly="${checkOnly}"
maxPoll="${maxPoll}"
deployRoot="${src.dir}"
allowMissingFiles="${allowMissingFiles}"
ignoreWarnings="${ignoreWarnings}"
testLevel="${testLevel}" />
</target>
It looks like I am unable to exclude the same.
Never used filesets, sorry.
My Ant pulls project's structure from Git to temp directory so in the build.xml we just delete stuff which we know is pain to deploy. We still want these files in the repo for ease of use / repo completeness.
<target name="deploy_target">
...
<delete file="${src.dir}/workflows/Reply.workflow" />
<delete file="${src.dir}/workflows/Question.workflow" />
<delete file="${src.dir}/layouts/SocialPost-Social Post Layout.layout" />
<delete file="${src.dir}/layouts/CommunityMemberLayout-Community Member Layout.layout" />
</target>

How to make ant not fail if folder on classpath is not found

I'm trying to modify my ant script so that it will build without error whether or not a local lib folder exists. I want to use the same script on multiple wars, some of which will have WEB-INF/lib, and some of which won't. If the folder exists, include it in the classpath, if not, do not include it. I have tried putting but I can't figure out where it should go. I think this should be a lot simpler than I'm making it out to be but my Googl Fu is failing me.
<property name="local.libs" value="WebContent/WEB-INF/lib" />
<path id="local.libs.path">
<fileset dir="${local.libs}" includes="*.jar" />
</path>
<target name="compile">
<mkdir dir="${build.classes.dir}"/>
<javac srcdir="${src.java.dir}" destdir="${build.classes.dir}" debug="true" includeantruntime="false">
<compilerarg value="-Xlint:-path" />
<classpath refid="local.libs.path" />
<classpath refid="server.libs.path" /> <!-- not referenced in snippet -->
</javac>
</target>
I ended up solving this by making the value of local.libs just WebContent/WEB-INF:
<property name="local.libs" value="WebContent/WEB-INF" />
and then the fileset
<fileset dir="${local.libs}" includes="*lib/*.jar" />
Then it would build whether or not the lib folder existed.

How to preserve file order in Ant concat?

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" />

Ant concat task complain on missing files

<concat destfile="dist/external.js">
<fileset dir=".">
<include name="a.js" />
<include name="b.js" />
</fileset>
</concat>
This won't fail if a or b is missing. I've tried setting optional="false" or asis="true" and it always complains that those attributes don't exist.
If you just want to see a warning from the 'concat' task when a file is missing, you can use afilelistresource collection in place of the 'fileset':
<concat destfile="dist/external.js">
<filelist dir=".">
<file name="a.js" />
<file name="b.js" />
</filelist>
</concat>
Whenb.jsdoesn't exist, that gives the message:
[concat] /Path/.../b.js does not exist.
But proceeds anyway, which is probably not what you want.
One method of checking for the presence of all the files in a resource collection is as follows. Note that you need to add the "antlib:org.apache.tools.ant.types.resources.selectors" namespace to the project to use the resource selectors shown below. (This won't work for Ant versions older than 1.7.0.) Use the Ant fail task to check that no resources are missing.
<project name="stack_overflow"
xmlns:rsel="antlib:org.apache.tools.ant.types.resources.selectors">
<filelist id="my.js.files" dir=".">
<file name="a.js" />
<file name="b.js" />
</filelist>
<restrict id="missing.js.files">
<filelist refid="my.js.files"/>
<rsel:not>
<rsel:exists/>
</rsel:not>
</restrict>
<property name="missing.files" refid="missing.js.files" />
<fail message="These files are missing: ${missing.files}">
<condition>
<length string="${missing.files}" when="greater" length="0" />
</condition>
</fail>
<concat destfile="dist/external.js">
<filelist refid="my.js.files" />
</concat>
</project>
When run, as before withb.jsmissing, this fails the build before the 'concat' task with:
BUILD FAILED
/Path/.../build.xml:17: These files are missing: /Path/.../b.js

How do I "expand" an ant path (accessed with refId=..) to all files in the path except some?

I am trying to get ant4eclipse to work and I have used ant a bit, but not much above a simple scripting language. We have multiple source folders in our Eclipse projects so the example in the ant4eclipse documentation needs adapting:
Currently I have the following:
<target name="build">
<!-- resolve the eclipse output location -->
<getOutputpath property="classes.dir" workspace="${workspace}" projectName="${project.name}" />
<!-- init output location -->
<delete dir="${classes.dir}" />
<mkdir dir="${classes.dir}" />
<!-- resolve the eclipse source location -->
<getSourcepath pathId="source.path" project="." allowMultipleFolders='true'/>
<!-- read the eclipse classpath -->
<getEclipseClasspath pathId="build.classpath"
workspace="${workspace}" projectName="${project.name}" />
<!-- compile -->
<javac destdir="${classes.dir}" classpathref="build.classpath" verbose="false" encoding="iso-8859-1">
<src refid="source.path" />
</javac>
<!-- copy resources from src to bin -->
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset refid="source.path">
<include name="**/*"/>
<!--
patternset refid="not.java.files"/>
-->
</fileset>
</copy>
</target>
The task runs successfully, but I cannot get the to work - it is supposed to copy all non-java files over too to emulate the behaviour of eclipse.
So, I have a pathId named source.path which contains multiple directories, which I somehow needs to massage into something the copy-task like. I have tried nesting which is not valid, and some other wild guesses.
How can I do this - thanks in advance.
You might consider using pathconvert to build a pattern that fileset includes can work with.
<pathconvert pathsep="/**/*," refid="source.path" property="my_fileset_pattern">
<filtermapper>
<replacestring from="${basedir}/" to="" />
</filtermapper>
</pathconvert>
That will populate ${my_fileset_pattern} with a string like:
1/**/*,2/**/*,3
if source.path consisted of the three directories 1, 2, and 3 under the basedir. We're using the pathsep to insert wildcards that will expand to the full set of files later.
The property can now be used to generate a fileset of all the files. Note that an extra trailing /**/* is needed to expand out the last directory in the set. Exclusion can be applied at this point.
<fileset dir="." id="my_fileset" includes="${my_fileset_pattern}/**/*">
<exclude name="**/*.java" />
</fileset>
The copy of all the non-java files then becomes:
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset refid="my_fileset" />
</copy>
That will copy the source files over retaining the source directory structure under todir. If needed, the flatten attribute of the copy task can be set to instead make all the source files copy directly to todir.
Note that the pathconvert example here is for a unix fileseystem, rather than windows. If something portable is needed, then the file.separator property should be used to build up the pattern:
<property name="wildcard" value="${file.separator}**${file.separator}*" />
<pathconvert pathsep="${wildcard}," refid="source.path" property="my_fileset">
...
You could use the foreach task from the ant-contrib library:
<target name="build">
...
<!-- copy resources from src to bin -->
<foreach target="copy.resources" param="resource.dir">
<path refid="source.path"/>
</foreach>
</target>
<target name="copy.resources">
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset dir="${resource.dir}" exclude="**/*.java">
</copy>
</target>
If your source.path contains file paths as well then you could the if task (also from ant-contrib) to prevent attempting to copy files for a file path, e.g.
<target name="copy.resources">
<if>
<available file="${classes.dir}" type="dir"/>
<then>
<copy todir="${classes.dir}" preservelastmodified="true">
<fileset dir="${resource.dir}" exclude="**/*.java">
</copy>
</then>
</if>
</target>

Resources