Exclude files in ant-migration tool while deploying - ant

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>

Related

if else condition in ant task produces error

I have a scenario where i need to move a directory from one location to another. If the same directory exists in the destination folder i need to rename the directory name as oldname_1.
So i wrote a snippet as follows:
<target name="Move">
<IF>
<available file="${output.dir}" type="dir" />
<then>
<echo message="Directory exists" />
<rename src="${output.dir}" dest="${output.dir}_1"/>
<property name="newdirectory" value="${dest}"/>
</then>
<ELSE>
<echo message="Directory does not exist" />
</ELSE>
</IF>
<move file="${newdirectory}" todir="C:\reports" />
</target>
The error i am getting is :
Problem: failed to create task
Cause: The name is undefined.
Action: Check the spelling.
Action: Check that any custom tasks/types have been declared.
Action: Check that any / declarations have taken place.
As Ian Roberts has already mentioned, you need the Ant-Contrib jar, and then setup the <taskdef/> to point to this jar. I highly recommend putting it inside your project and checking it into your version control system. This way, when someone checks out your project, they already have the Ant-Contib.jar installed.
My standard is to put all optional jars required for the build (not jars required for compiling) in the directory ${basedir}/antlib, then put each optional jar in its own directory, so I would put ant-contrib-1.0b3.jar into ${basedir}/antlib/antcontrib.
Then I define the task this way:
<property name="antlib.dir" value="${basedir}/antlib"/>
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<fileset dir="${antlib.dir}/antcontrib"/>
</classpath>
</taskdef>
This way, if you update the jar file to a new version of the Ant-Contrib jar, you simply plug it into the directory. You don't have to update the build.xml.
Also note that I use net/sf/antcontrib/antlib.xml and not net/sf/antcontrib/antcontrib.properties. The XML file is what you should use. The directions for this are on the tasks page and differ from the ones on the main page under the installation directions. The reason is that the XML file has the correct definition for the <for> task, and the properties file does not.
However, there is another way to do if and unless in Ant 1.9.1 without the need for optional jar files. These are the new If and Unless entity attributes.
These can be placed in all tasks, or sub-entities, and can usually replace the Ant-Contrib if/else stuff:
<target name="move">
<available file="${output.dir}" type="dir"
property="output.dir.exists"/>
<echo message"Directory exists"
if:true="output.dir.exists"/>
<move file="${output.dir}" tofile="${output.dir}_1"
if:true="output.dir.exists"/>
<property name="newdirectory" value="${dest}"
if:true="output.dir.exists"/>
<echo message="Directory does not exists"
unless:true="output.dir.exists"/>
<move file="${newdirectory}" todir="C:\reports" />
</target>
Not so clean as your example. However, I would instead use the if= and unless= parameters on target names:
<target name="move.test">
<available file="${output.dir}" type="dir"
property="output.dir.exists"/>
</target>
<target name="move"
depends="move.test, move.exists, move.does.not exists">
<move file="${newdirectory}" todir="C:\reports" />
</target>
<target name="move.exists"
if="output.dir.exists">
<echo message="Directory exists" />
<move file="${output.dir}" tofile="${output.dir}_1"/>
<property name="newdirectory" value="${dest}"/>
</move.exists/>
<target name="move.does.not.exists"
unless="output.dir.exists"/>
<echo message="Directory does not exist" />
</target>
If you didn't echo everything, the structure would be a bit cleaner:
<target name="move.test">
<available file="${output.dir}" type="dir"
property="output.dir.exists"/>
</target>
<target name="move"
depends="move.test, backup">
<move file="${newdirectory}" todir="C:\reports" />
</target>
<target name="backup"
if="output.dir.exists">
<move file="${output.dir}" tofile="${output.dir}_1"/>
<property name="newdirectory" value="${dest}"/>
</move.exists/>
The if/else construct is not a native part of Ant out of the box, it is provided by the ant-contrib project, and you need to download a JAR and add the relevant <taskdef> to your build file. For example, if you download ant-contrib-1.0b3.jar and put it in a directory named build in the same directory as your build.xml, then you can say
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="build/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>

Ant With Internal Dependencies

I have a a jar right now that uses external dependencies. I'm trying to create a jar that packages all the external dependencies inside, and will just give me one jar. I saw this question asked multiple times, but I still can't figure it out. I'm using Ant, and copied some of the examples I saw on here. I'm using zipgroupfileset to reference the external(now internal) jars. As soon as I added the zipgroupfileset I got a runtime error that said my Runner class could not be found.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- WARNING: Eclipse auto-generated file.
Any modifications will be overwritten.
To include a user specific buildfile here, simply create one in the same
directory with the processing instruction <?eclipse.ant.import?>
as the first entry and export the buildfile again. -->
<project basedir="." default="build" name="ExcelDemo">
<property environment="env"/>
<property name="ECLIPSE_HOME" value="../../../../Program Files (x86)/eclipse"/>
<property name="debuglevel" value="source,lines,vars"/>
<property name="target" value="1.6"/>
<property name="source" value="1.6"/>
<property name="external-lib-dir" value="lib\poi-3.9" />
<property name="external-lib-dir2" value="lib\poi-3.9\lib" />
<property name="external-lib-dir3" value="lib\poi-3.9\ooxml-lib" />
<path id="ExcelDemo.classpath">
<pathelement location="bin"/>
</path>
<target name="init">
<mkdir dir="bin"/>
<copy includeemptydirs="false" todir="bin">
<fileset dir="src" excludes="**/*.launch, **/*.java"/>
</copy>
</target>
<target name="clean">
<delete dir="bin"/>
</target>
<target depends="clean" name="cleanall"/>
<target depends="build-subprojects,build-project" name="build"/>
<target name="build-subprojects"/>
<target depends="init" name="build-project">
<echo message="${ant.project.name}: ${ant.file}"/>
<javac debug="true" debuglevel="${debuglevel}" destdir="bin" source="${source}" target="${target}">
<src path="src"/>
<classpath refid="ExcelDemo.classpath"/>
</javac>
</target>
<target description="Build all projects which reference this project. Useful to propagate changes." name="build-refprojects">
<ant antfile="${ExcelSensitize.location}/build.xml" inheritAll="false" target="clean"/>
<ant antfile="${ExcelSensitize.location}/build.xml" inheritAll="false" target="build">
<propertyset>
<propertyref name="build.compiler"/>
</propertyset>
</ant>
</target>
<target description="copy Eclipse compiler jars to ant lib directory" name="init-eclipse-compiler">
<copy todir="${ant.library.dir}">
<fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/>
</copy>
<unzip dest="${ant.library.dir}">
<patternset includes="jdtCompilerAdapter.jar"/>
<fileset dir="${ECLIPSE_HOME}/plugins" includes="org.eclipse.jdt.core_*.jar"/>
</unzip>
</target>
<target description="compile project with Eclipse compiler" name="build-eclipse-compiler">
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
<antcall target="build"/>
</target>
<target name="RunnerClass">
<java classname="runner.RunnerClass" failonerror="true" fork="yes">
<classpath refid="ExcelDemo.classpath"/>
</java>
</target>
<target name="jar" description="Create a jar for this project">
<manifestclasspath property="lib.list" jarfile="Test.jar">
<classpath refid="ExcelDemo.classpath" />
</manifestclasspath>
<jar jarfile="Test.jar" includes="*.class" basedir="bin">
<zipgroupfileset dir="${external-lib-dir}" includes="*.jar"/>
<zipgroupfileset dir="${external-lib-dir2}" includes="*.jar"/>
<zipgroupfileset dir="${external-lib-dir3}" includes="*.jar"/>
<manifest>
<attribute name="Class-Path" value="${lib.list}" />
<attribute name="Main-Class" value="runner.RunnerClass" />
</manifest>
</jar>
</target>
</project>
To make things simpler:
Create a separate sources jar for compilation. Then, have a separate compiled jar without the sources.
Don't include the third party jars. Instead, use Ivy with Ant. Ant will automatically download the required jars. In fact, I've see sources that just include the ivy.jar, so Ivy will automatically be configured when you unjar the sources. You type in ant, and everything just builds.
As an alternative, you can look at Maven which is how many projects are now packaged. In fact, if your jar is an open source project, you can probably host it on the OSS Maven repository. This way, no one even needs to manually download your compiled jar. If they want it, they configure their Maven project to do it for them.
i think the problem is that you use basedir="bin" in the your jar task. then path of your zipgroupfileset convert to bin/${external-lib-dir}

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.

ANT Generated jar: is it a namespace issue?

I have a Eclipse-Java-Project with an ANT-build-file. This build file exports a jar of the project without compiling it. So I only export the sources.
<target name="jar">
<mkdir dir="/jar"/>
<jar destfile="/jar/my_test_jarfile.jar" basedir="/src" />
</target>
I use this generated jar in another eclipse java project and set the path to the jar in the build-path-settings of the project. The problem is that eclipse says it cannot resolve the namespace of the imported classes of the jar.
If I export the jar manually by right clicking on the project and then "Export" and putting the jar to the build path of the other project, everything works fine and there are no errors. So the question is now, what am I doing wrong?
So here is my solution. It seems that you have to compile the source first and then pack it into a jar. I don't give a guarantee that this jar is exactly the same like the one you get from eclipse when you do the right click thing and export etc.
But it works for me, there are no namespace errors any longer. so here is a minimum version of my ant targets:
<project default="run" basedir=".">
<property name="src.dir" value="src" />
<property name="classes.dir" value="bin" />
<property name="build.dir" value="build" />
<path id="libs">
<fileset dir="lib">
<include name="*.jar"/>
</fileset>
<pathelement path="${basedir}\${classes.dir}"/>
</path>
<target name="run">
<antcall target="compile"/>
<antcall target="jar"/>
</target>
<target name="compile">
<javac debug="true" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="libs" encoding="UTF-8" />
</target>
<target name="jar">
<jar destfile="${build.dir}/my_jar_file.jar" basedir="${classes.dir}">
</target>
</project>

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