How to translate this MSBuild script to F#/FAKE? - f#

What is the translation of the following MSBuild script into F#/FAKE?
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<CurrentMode>None</CurrentMode>
</PropertyGroup>
<Target Name="Compile_A">
<Message Text="Hello from Compile_A" />
<CallTarget Targets="SetToA"/>
<CallTarget Targets="IntermediateStage"/>
</Target>
<Target Name="Compile_B">
<Message Text="Hello from Compile_B" />
<CallTarget Targets="SetToB"/>
<CallTarget Targets="IntermediateStage"/>
</Target>
<Target Name="IntermediateStage">
<Message Text="Hello from IntermediateStage" />
<CallTarget Targets="Compile"/>
</Target>
<Target Name="Compile">
<Message Text="Hello from Compile. I'm using $(CurrentMode)" />
</Target>
<!-- The following Targets are only necessary due to a MSBuild bug (CallTarget and CreateProperty cannot be combined) -->
<Target Name="SetToA">
<CreateProperty Value="A">
<Output TaskParameter="Value" PropertyName="CurrentMode" />
</CreateProperty>
</Target>
<Target Name="SetToB">
<CreateProperty Value="B">
<Output TaskParameter="Value" PropertyName="CurrentMode" />
</CreateProperty>
</Target>
</Project>
My main goal is to set a property in the topmost targets with different values (CurrentMode is either A or B) and consume it in the deepest target (Compile).

The best answer will probably differ based on what is your actual scenario. In particular, you might not even need separate targets for the different steps of your process if you do not ever plan to run them separately (in which case, just using a function that takes the mode as a parameter and invoking that from CompileA and CompileB would work fine).
However, if you want to keep separate targets for all the steps, you could do something like this:
#load ".fake/build.fsx/intellisense.fsx"
open Fake.Core
open Fake.Core.TargetOperators
let mutable CurrentMode = "None"
Target.create "SetA" (fun _ ->
CurrentMode <- "A"
)
Target.create "SetB" (fun _ ->
CurrentMode <- "B"
)
Target.create "IntermediateStage" (fun _ ->
printfn "In the intermediate stage"
)
Target.create "Compile" (fun _ ->
printfn "Compiling using mode %s" CurrentMode
)
Target.create "CompileA" ignore
Target.create "CompileB" ignore
"SetA" ==> "CompileA"
"SetB" ==> "CompileB"
"IntermediateStage" ==> "Compile" ==> "CompileA"
"IntermediateStage" ==> "Compile" ==> "CompileB"
"SetA" ?=> "IntermediateStage"
"SetB" ?=> "IntermediateStage"
Target.runOrDefault "CompileA"
This uses mutable variable CurrentMode that is set by SetA or SetB targets (arguably, not very functional, but it captures what you're doing).
The dependencies between targets are specified using ==>. Note that SetA has to happen before CompileA (and similar for B) and IntermediateStage needs to go before Compile which is pre-requisite for both kinds of compiles.
There is one subtle trick - you don't want to say that SetA and SetB are required for IntermediateStep, because then FAKE would run both in non-deterministic order. the ?=> opreator lets you specify soft dependencies which say that if both IntermediateStep and SetA are to be executed, then SetA has to go first - so the last two lines are not adding dependencies, but making ordering explicit.

Related

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.

ant - Running a target at the end of every build

Is there a way to always run a target at the end of every build?
I know I can do something like this...
<target name="runJob" depends="actuallyRunJob, teardown"/>
... but that's sloppy, since I'd need a wrapper for every target that needs a teardown.
Any ideas?
Thanks,
Roy
use a buildlistener, f.e. the exec-listener which provides a taskcontainer for each build result ( BUILD SUCCESSFUL | BUILD FAILED ) where you can put all your needed tasks in
see Conditional Task on exec failure in Ant for further details
or roll your own build listener, see =
http://ant.apache.org/manual/develop.html
and the api docs from your ant installation =
$ANT_HOME/docs/manual/api/org/apache/tools/ant/BuildListener.html
In the same spirit as Rebse's answer, you can write a BuildListener in Javascript as follows (if you don't mind trading an Ant extension against some code in your makefile):
<project name="test-ant" default="build">
<target name="init">
<script language="javascript"> <![CDATA[
function noop () {}
var listener = new org.apache.tools.ant.BuildListener() {
buildFinished: function(e) {
project.executeTarget("_finally");
},
buildStarted: noop,
messageLogged: noop,
targetStarted: noop,
targetFinished: noop,
taskStarted: noop,
taskFinished: noop
}
project.addBuildListener(listener)
]]></script>
</target>
<target name="build" depends="init"/>
<target name="fail" depends="init">
<fail message="expected failure"/>
</target>
<target name="_finally">
<echo message="executing _finally target..."/>
</target>
</project>
Intercepting other events should be quite easy as you can see.
I had a similar need and ended up writing a custom task, which looks like this:
<!-- a task that executes the embedded sequential element at the end of the build,
but only if the nested condition is true; in this case, we're dumping out the
properties to a file but only if the target directory exists (otherwise, the clean
target would also generate the file and we'd never really be clean!) -->
<build:whendone>
<condition>
<available file="${project_target-dir}" />
</condition>
<sequential>
<mkdir dir="${project_final-build-properties-file}/.." />
<echoproperties destfile="${project_final-build-properties-file}" />
</sequential>
</build:whendone>
In this case, I wanted a record of all of the Ant properties that contributed to a build, but doing that at the beginning of the build misses quite a few (if they're initialized as part of targets, after dumping them to the file).
Unfortunately, I can't share specific code, but this is nothing more than an Ant Task that implements SubBuildListener, specifically buildFinished(BuildEvent). The listener tests the embedded condition and then, if true, executes the embedded sequential.
I'd love to know if there's a better way.
If it's an android project you can easily override the "-post-build" target in your local "build.xml" file. This target is just for this purpose.

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>

In what order are Ant target's "if" and "depends" evaluated?

That is, will calling the following target when testSetupDone evaluates to false, execute the targets in dependency chain?
<target name="-runTestsIfTestSetupDone" if="testSetupDone" depends="-runTests" />
Yes, the dependencies are executed before the conditions get evaluated.
From the Ant manual:
Important: the if and unless attributes only enable or disable the target to which they are attached. They do not control whether or not targets that a conditional target depends upon get executed. In fact, they do not even get evaluated until the target is about to be executed, and all its predecessors have already run.
Here is an example:
<project>
<target name="-runTests">
<property name="testSetupDone" value="foo"/>
</target>
<target name="runTestsIfTestSetupDone" if="testSetupDone" depends="-runTests">
<echo>Test</echo>
</target>
</project>
The property testSetupDone is set within the target in depends, and the output is:
Buildfile: build.xml
-runTests:
runTestsIfTestSetupDone:
[echo] Test
BUILD SUCCESSFUL
Total time: 0 seconds
Target -runTests is executed, even though testSetupDone is not set at this moment. runTestsIfTestSetupDone is executed afterwards, so depend is evaluated before if.
From the docs:
Ant tries to execute the targets in the depends attribute in the order they
appear (from left to right). Keep in mind that it is possible that a
target can get executed earlier when an earlier target depends on it:
<target name="A"/>
<target name="B" depends="A"/>
<target name="C" depends="B"/>
<target name="D" depends="C,B,A"/>
Suppose we want to execute target D. From its depends attribute,
you might think that first target C, then B and then A is executed.
Wrong! C depends on B, and B depends on A,
so first A is executed, then B, then C, and finally D.
Call-Graph: A --> B --> C --> D

Resources