Phing alternative for fixlastline from ant - ant

I'm rewriting build.xml file from Ant to Phing and everything goes fine with one exception.
I need to add new line at the end of each appended file but I can't find any alternative for fixlastline="true".
In Ant it was
<concat destfile="${libraryFilePrefix}.js" fixlastline="yes">
<!-- many filesets -->
</concat>
In Phing it's like
<append destfile="${libraryFilePrefix}.js">
<!-- many filesets -->
</append>
Is there any attribute that works like fixlastline or maybe I need to find another way to achieve this?

I believe, one of the approaches (and possibly the only one) is applying replaceregexp filter on each fileset. You only need to apply filterchain at the beginning and it will do the job for each fileset, like this:
<append destfile="${libraryFilePrefix}.js">
<filterchain>
<replaceregexp>
<regexp pattern="([^\n])$" replace="$1${line.separator}" ignoreCase="true"/>
</replaceregexp>
</filterchain>
<!-- many filesets -->
</append>

As of Phing 3.x the AppendTask is aware of the fixlastline attribute. Your Ant script provided is now working as expected
<project name="concat-supports-fixlastline" default="concat-fixed-lastline" basedir=".">
<target name="concat-fixed-lastline">
<concat destfile="${libraryFilePrefix}.js" fixlastline="yes">
<!-- many filesets -->
</concat>
</target>
</project>

Related

how to pass parameters to ant task's depends field

I have a build.xml that should receive dynamically parameters to the depends field.
I define this parameter in some other app.xml such as:
ops=op1, op2, op3,op4,op5,.... opn
then I import this app.xml into build.xml and want to use the parameter ops there.
<project name="Project" basedir="." default="help">
<target name="test" depends="{$ops}" description="executea series of commands in ant">
<echo message="batch operation job done. tasks = {$ops}"/>
</target>
</project>
How can I pass a parameter from one ant file to another?
The depends parameter does not take properties.
Ant uses a dependency matrix to determine what should be built and in what order. This matrix is calculated before any part of the build file itself is executed, so properties aren't even set when this is done.
What are you trying to accomplish? Maybe if we have a better idea what you want, we can help you with it. Ant isn't a scripting language like BASH or Python.
As already mentioned, you can't put properties into the Depends field. However, if you are setting a property, you can use it in the If field. Example
<project name="appProject">
<target name="test" depends="target1,target2,target3" description="execute series of commands"/>
<target name="target1" if="do.target1">
<echo message="Target1 executed." />
</target>
<target name="target2" if="do.target2">
<echo message="Target2 executed." />
</target>
<target name="target3" if="do.target3">
<echo message="Target3 executed." />
</target>
</project>
Then you set in your build.xml the given target flag do.target1, do.target2 or do.target3 and it gets executed. Basically what you wanted to have. In the If field properties are only checked for value. Also, you don't have to use the ${ } construction for the properties.

how to call multiple ant targets for foreach

here is what am trying to do, I want to replace name and address from my large number of property files during build, but unfortunately I cant do this, is there a better way of doing this without having to copy paste the foreach twice. can someone help?
<target name="replace" >
<foreach target="replace.name,replace.address" param="foreach.file" inheritall="true">
<path>
<fileset dir="${build.tmp.dir}/resource">
<!-- some complicated conditions go here -->
</path>
</foreach>
</target>
<target name="replace.address">
<echo>replacing #Address# for ${foreach.file}</echo>
<replace file="${foreach.file}" token="#Address#" value="${address}" />
</target>
<target name="replace.name">
<echo>replacing #Name# for ${foreach.file}</echo>
<replace file="${foreach.file}" token="#Name#" value="${Name}" />
</target>
.properties file looks like
name=#Name#
address=#Address#
target of foreach is not designed to take more than one target name. It only iterates through the provided list, not the provided targets.
To make the implementation more DRY, you may
use a for loop instead of foreach with two antcalls;
use macrodef with for loop -- macrodef can pack several ant xml code into a task-like thing
Actually, for the two targets -- replace.address and replace.name, are you sure that you want to call them from the commandline?
If not, name them -replace.address and -replace.name or use macrodef -- exposing the iteration body of foreach is not a good practice.

Changing property value in Ant

I don't want to use propertyregex in the AntContrib task, but I need to modify a property. I am using the cabarc command (I can't get the <cab> task to work), and I need to strip out the drive name.
${basedir} = "D:\some\directory\blah\blah"
${cwd} = some\directory\blah\blah"
I need this in order to strip out the path in cabarc (but still using directories). I've ended up doing the following:
<!-- Create a property set with just basedir -->
<!-- Needed for loadproperties to work -->
<propertyset id="cwd">
<propertyref name="basedir"/>
</propertyset>
<loadproperties>
<propertyset refid="cwd"/>
<filterchain>
<tokenfilter>
<replaceregex pattern=".:\\"
replace="cwd="/>
</tokenfilter>
</filterchain>
</loadproperties>
That works, but it's a little complex and will be hard to maintain.
Is there an easier way to do this?
get into the groove ;-)
<groovy>
properties.'cwd' = properties.'basedir'[3..-1]
</groovy>
or with Ant Plugin Flaka :
<project xmlns:fl="antlib:it.haefelinger.flaka" name="World">
<!-- simple echo -->
<fl:echo>#{replace('${basedir}', '$1' , '.:\\\\(.+)' )}</fl:echo>
<!-- set property -->
<fl:let>cwd := replace('${basedir}', '$1' , '.:\\\\(.+)' )</fl:let>
</project>
Disclosure = i'm participating as committer in the Flaka project

Ant manifestclasspath: property already set

I want to use manifestclasspath Ant task. I have a very large build.xml file with a couple of imported other build files and when I run it I get this:
build.xml:1289: The following error occurred while executing this line:
build.xml:165: Property 'some.property' already set!
I am sure that this property is defined only in manifestclasspath task. Here is my code:
<manifestclasspath property="some.property" jarfile="some.jar">
<classpath refid="some.classpath"/>
</manifestclasspath>
This code is located inside of <project>.
What am I doing wrong? Is there a way to add something like condition to set property only if it is not already set? I don't want to use custom Ant tasks such as Ant Contrib's if if there is other way around.
Antcall opens a new project scope, but by default, all of the properties of the current project will be available in the new project. Also if you used something like =
<antcall target="whatever">
<param name="some.property" value="somevalue"/>
</antcall>
in the calling project then ${some.property} is also already set and won't be overwritten, as properties once set are immutable in ant by design.
Alternatively, you may set the inheritAll attribute to false and only "user" properties (those passed on the command-line with -Dproperty=value) will be passed to the new project.
So, when ${some.property} ain't no user property, then use inheritAll="false" and you're done.
btw. it's better to use a dependency between targets via depends="..." attribute than to use antcall, because it opens a new project scope and properties set in the new project won't get back to the calling target because it lives in another project scope..
Following a snippet, note the difference, first without inheritAll attribute
<project default="foo">
<target name="foo">
<property name="name" value="value1" />
<antcall target="bar"/>
</target>
<target name="bar">
<property name="name" value="value2" />
<echo>$${name} = ${name}</echo>
</target>
</project>
output :
[echo] ${name} = value1
second with inheritAll=false
<project default="foo">
<target name="foo">
<property name="name" value="value1" />
<antcall target="bar" inheritAll="false" />
</target>
<target name="bar">
<property name="name" value="value2" />
<echo>$${name} = ${name}</echo>
</target>
</project>
output :
[echo] ${name} = value2
some rules of thumb for antcall, it's rarely used for good reasons :
1. it opens a new project scope (starting a new 'ant -buildfile yourfile.xml yourtarget') so it uses more memory, slowing down your build
2. depending targets of the called target will be called also !
3. properties don't get passed back to the calling target
In some cases it might be ok when calling the same 'standalone' target (a target that has no target it depends on) with different params for reuse. Normally macrodef or scriptdef are used for that purpose. So, think twice before using antcall which also puts superfluous complexity to your scripts, because it works against the normal flow.
Answer to your question in the comment, using a dependency graph instead of antcall
you have some target that holds all conditions and sets the appropriate properties which may be evaluated by targets via if and unless attributes to control the further flow
<project default="main">
<target name="some.target">
<echo>starting..</echo>
</target>
<!-- checking requirements.. -->
<target name="this.target">
<condition property="windowsbuild">
<os family="windows"/>
</condition>
<condition property="windowsbuild">
<os family="unix"/>
</condition>
<!-- ... -->
</target>
<!-- alternatively
<target name="yet.another.target" depends="this.target" if="unixbuild">
-->
<target name="another.target" depends="this.target" unless="windowsbuild">
<!-- your unixspecific stuff goes here .. -->
</target>
<!-- alternatively
<target name="yet.another.target" depends="this.target" if="windowsbuild">
-->
<target name="yet.another.target" depends="this.target" unless="unixbuild">
<!-- your windowspecific stuff goes here .. -->
</target>

passing properties defined inside antcall target back to calling target

I'm rather new to Ant but I have experienced it's quite good pattern to create generic ant targets which are to be called with antcall task with varying parameters.
My example is compile target, which compiles multiple systems using complex build command which is a bit different for each system. By using pattern described above it's possible not to create copy paste code for that compile command.
My problem here is, that I'm not aware of any way to pass return value (for example the return value of compiler) back to target which called the antcall task. So is my approach pathological and it's simply not possible to return value from antcall task or do you know any workaround?
Thanks,
Use antcallback from the ant-contrib jar instead of antcall
<target name="testCallback">
<antcallback target="capitalize2" return="myKey">
</antcallback>
<echo>a = ${myKey}</echo>
</target>
<target name="capitalize2">
<property name="myKey" value="it works"/>
</target>
Output:
testCallback:
capitalize2:
[echo] a = it works
BUILD SUCCESSFUL
One approach is to write out a property to a temp file using "echo file= ...." or PropertyFile task. Then read the property back in where required. Kludge but works.
Ant tasks are all about stuff goes in, side effect happens. So trying to program in terms of functions (stuff goes in, stuff comes out) is going to be messy.
That said what you can do is generate a property name per invocation and store the result value in that property. You would need to pass in a indentifier so you do not end up trying to create copies of the same property. Something like this:
<target name="default">
<property name="key" value="world"/>
<antcall target="doSomethingElse">
<param name="param1" value="${key}"/>
</antcall>
<echo>${result-${key}}</echo>
</target>
<target name="doSomethingElse">
<property name="hello-${param1}" value="it works?"/>
</target>
But I believe the more typical approach -instead of antcalls- is to use macros. http://ant.apache.org/manual/Tasks/macrodef.html
Antcall can be used from the ant-contrib jar task.
You can get a similar behaviour with the keyword "depends".
<?xml version="1.0" encoding="UTF-8"?>
<project name="test" default="main">
<target name="main">
<antcall target="build-system-with-depends" />
<!-- wait for different results -->
<waitfor checkevery="1000" checkeveryunit="millisecond" maxwaitunit="millisecond" maxwait="2000">
<available file="dummy.not.present.file" classname="" property=""></available>
</waitfor>
<antcall target="build-system-with-depends" />
</target>
<target name="build-system-with-depends" depends="do-compiler-stuff">
<echo>$${compiler.result}=${compiler.result}</echo>
</target>
<target name="do-compiler-stuff">
<!-- simulate different return states -->
<tstamp>
<format pattern="yyyyMMddHHmmss" property="compiler.result" />
</tstamp>
</target>
</project>

Resources