Ant flaka: declare variable with dynamic name - ant

I'm using ant with flaka.
How can I declare a variable with dynamic name (retrieved from another variable)?
I would like to do something like that:
<fl:let>
#{varname} = value
</fl:let>
however, i think it's illegal.
How can i do that?
thanks!

second anwser :
your question is not clear to me :
#{variablename} = value
would overwrite an existing variable variablename, so my second guess is with "based on" you meant something like :
<project xmlns:fl="antlib:it.haefelinger.flaka">
<fl:let>
varname = 'foo'
; declare variable based on other variable
#{varname}bar = 'whatever'
</fl:let>
<fl:echo>
#{varname}
#{foobar}
</fl:echo>
</project>
output :
[fl:echo] foo
[fl:echo] whatever
first answer :
Here's the FAQ entry from the official Ant FAQ solved with Flaka :
<project xmlns:fl="antlib:it.haefelinger.flaka">
<fl:install-property-handler />
<property name="foo" value="foo.value" />
<property name="var" value="foo" />
<echo> #{${var}} = foo.value </echo>
</project>

Related

ANT Build: Can the token itself be parsed from other values from within the property file?

Can the token itself be parsed from other values from within the property file?
Is it possible to evaluate the token key, without hardcoding the token? Can the token itself be parsed from other values from within the property file?
For example, if the properties file has the following tokens (test.properties):
module_no = 01
module_code = bb
title_01_aa = ABC
title_02_aa = DEF
title_03_aa = GHI
title_01_bb = JKL
title_02_bb = MNO
title_03_bb = PQR
Contents of build.xml
<?xml version="1.0" encoding="utf-8"?>
<project default="repl">
<property file="test.properties" />
<target name="repl">
<replace file="test.txt" token="module_title" value="title_${module_no}_${module_code}" />
</target>
</project>
Sample content with text:
Welcome to module_title.
The replace task will result in:
Welcome to title_01_bb.
How to achieve this instead?
Welcome to JKL.
This might be very basic, but please do guide me in the right direction. Thank you.
Nested property expansion does not work by default in Ant as described in the documentation:
Nesting of Braces
In its default configuration Ant will not try to balance braces in property expansions, it will only consume the text up to the first closing brace when creating a property name. I.e. when expanding something like ${a${b}} it will be translated into two parts:
the expansion of property a${b - likely nothing useful.
the literal text } resulting from the second closing brace
This means you can't use easily expand properties whose names are given by properties, but there are some workarounds for older versions of Ant. With Ant 1.8.0 and the the props Antlib you can configure Ant to use the NestedPropertyExpander defined there if you need such a feature.
If you check the workarounds link, one solution is to use a macrodef to copy the property:
<property file="test.properties" />
<target name="repl">
<gettitleprop name="titleprop" moduleno="${module_no}" modulecode="${module_code}" />
<replace file="test.txt" token="module_title" value="${titleprop}" />
</target>
<macrodef name="gettitleprop">
<attribute name="name"/>
<attribute name="moduleno"/>
<attribute name="modulecode"/>
<sequential>
<property name="#{name}" value="${title_#{moduleno}_#{modulecode}}"/>
</sequential>
</macrodef>

Referencing global Ant property after <local> is used

I can create a local property in Ant within a "block" scope.
But how can I now reference the global property within the same block?
<property name="myprop" value="global"/>
...
<sequential>
<local name="myprop"/>
<property name="myprop" value="local"/>
<echo message="my local prop is ${myprop}"/> //<-- this works fine
<echo message="my global prop is ????"/> //<-- HOW?
</sequential/>
No ant-contrib please.
I'd also like to keep this in Ant, not resorting to JS.
The only thing I could think of was "copying" the global property under a different name to be used in this block
<local name="myglobprop"/>
<property name"myglobprop" value="${myprop}"/>
<local name="myprop"/>
<property name="myprop" value="local"/>
<echo message="my global prop is ${myglobprop}"/>
But that is rather unsightly and seems redundant. I am really just looking for an out-of-scope property reference method.
Edit - use case
My attempt to coerce Ant to do delayed expansion:
Let's say I have a property whose value is a combination of several other properties.
<property name="mycmdline" value="${cmd}=${type}"/>
If ${cmd} and ${type} are known before the above property, all is great. However in my case, these values are not defined (no property set). These values only become known at later stage inside a build macrodef.
I have another simple macrodef that will perform delayed expansion:
<property name="mycmdline" value="${cmd}=${type}"/>
...
<macrodef name="property-expand">
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<fail if="#{name}" message="Property #{name} is already set"/>
<property name="#{name}" value="#{value}"/>
</sequential>
</macrodef>
Finally my build macrodef would contain the following snippet:
<local name="cmd"/>
<local name="type"/>
<local name="mycmdline"/>
<property name="cmd" value="#{cmd}"/>
<property name="type" value="#{type}"/>
<property-expand name="mycmdline" value="${mycmdline}"/>
The last line is obviously wrong. I am creating a (now local) property called mycmdline with expanded value of global (now out of scope) ${mycmdline}. The macrodef for delayed expansion works great on it's own, but the problem is that the global ${mycmdline} is out of scope and cannot be referenced.
What I really wanted is:
<property name="mycmdline" value="${cmd}=${type}"/>
...
<!-- In macrodef now -->
<local name="mycmdline"/>
<property-expand name="mycmdline" value="GLOBAL:${mycmdline}"/>
Instead, what I have to do is:
<property name="unexpanded_mycmdline" value="${cmd}=${type}"/>
...
<!-- In macrodef now -->
<local name="mycmdline"/>
<property-expand name="mycmdline" value="${unexpanded_mycmdline}"/>
Why?
It may not look like a lot of difference, but it's about readability. unexpanded_mycmdline and mycmdline are now two different names, when trying to follow the way the value of property gets used through a script, it now makes a disconnected jump from one property name to another (not matter how similar the names may look). The whole unexpanded_ prefix looks out of place and doesn't fit with the rest of the naming conventions, unless I name all my global variables with some prefix, which doesn't make sense either.

Does ANT apply prefixValues if there is no property of the desired name ? Or is this a bug ? (SSCCE provided)

I have this weird behavior with ant and properties and I'd like to know what do you think. I don't get the logic.
This behavior could be usefull but I would like to know if I can rely on it or if this is a bug.
It looks like ant is applying the prefix when expanding the right hand side of properties if there is no property of the desired name. Here is the SSCCE:
build.properties:
a=A
formula=${a}
build.xml:
<project default="test">
<target name="test">
<property name="test.a" value="[test.a has been used instead of a, why? prefixValues is false]" />
<property file="build.properties" prefix="test" prefixValues="false" />
<echo>${test.formula}</echo>
</target>
</project>
output:
test:
[echo] [test.a has been used instead of a, why? prefixValues is false]
BUILD SUCCESSFUL
Total time: 364 milliseconds
As you can see, test.formula should use "a" and not "test.a" but "a" is never defined. Is it the reason?
Indeed, it seems weird.
In my opinion, the output should be ${a}
I did a few test and I notice that:
If you define a in the build.xml instead of build.properties : it works as expected. i.e. with the following build.xml:
<project default="test">
<target name="test">
<property name="a" value="A" />
<property file="build.properties" prefix="test" prefixValues="false" />
<echo>${test.formula}</echo>
</target>
</project>
and the build.properties
formula=${a}
output is
A
But, if you change to prefixValues="true" the ouput is :
${a}
while I was expecting : ${test.a}
Finally, if you define <property name="test.a" value="some value" /> in the build.xml (always with prefixValues="true") : the output is now (as expected)
some value
So, my conclusion:
prefixValues works fine as soon as the property used on the right side is not defined in the same property file.
prefixValues is ignored for properties used on the right side and defined in the same property file.
Taking a look in Ant code, in properties related classes, on org.apache.tools.ant.property.ResolvePropertyMap class:
public void resolveAllProperties(Map<String, Object> map, String prefix,
boolean prefixValues) {
// The map, prefix and prefixValues flag get used in the
// getProperty callback
this.map = map;
this.prefix = prefix;
this.prefixValues = prefixValues;
for (String key : map.keySet()) {
expandingLHS = true;
Object result = getProperty(key);
String value = result == null ? "" : result.toString();
map.put(key, value);
}
Then, in getProperty(String) method (snippet):
// If the property we are looking up is a key in the map
// (first call into this method from resolveAllProperties)
// or we've been asked to prefix the value side (later
// recursive calls via the GetProperty interface) the
// prefix must be prepended when looking up the property
// outside of the map.
String fullKey = name;
if (prefix != null && (expandingLHS || prefixValues)) {
fullKey = prefix + name;
}
So, as you can see, if the property is present in the property file, it will receive the prefix even if prefixValues is false.
I ran some more test and could get a lot of different results.
After checking the sources, I think that there is a bug when looking for properties while adding them through a file. By modifying some ant source code, I could get it to work.
In the end, I decided to fill a bug report (https://issues.apache.org/bugzilla/show_bug.cgi?id=54769) with a proposed patch.
Thank you all.
It's because properties are immutable. Once set, they're stuck that way for the rest of the build. Check out the docs for 'property' on the Ant manual. It's actually kind of a problem for some people, so the ant-contrib guys included a new task to mimic a variable.
If you change your build around like this:
<project default="test">
<target name="test">
<property file="build.properties" prefix="test" prefixValues="false" />
<property name="test.a" value="[test.a has been used instead of a, why? prefixValues is false]" />
<echo>${test.formula}</echo>
</target>
</project>
You get 'A' on the console. This is because test.a and test.formula got defined in the first call to before your new (ignored) assignment to 'test.a'

The prefix "sonar" for element "sonar:sonar" is not bound

I have a build.xml-file that looks something like this:
<taskdef uri="antlib:org.sonar.ant" resource="org/sonar/ant/antlib.xml" classpath="/path/sonar-ant-task.jar"/>
<target name="sonar">
<sonar:sonar/>
</target>
And when I run the file I get:
The prefix "sonar" for element "sonar:sonar" is not bound.
Any obvious things I'm missing?
You're missing the namespace declaration in the top project element of your Ant script.
xmlns:sonar="antlib:org.sonar.ant" ought to do it.
In ant you can not use .
try below and if you are setting any properties use key value pare in xml tag.
To allocate value use attributes of xml tags.
<sonar:sonar xmlns:sonar="antlib:org.sonar.ant">
</sonar:sonar>

reloading properties after updating a property file

I'm trying to read a property after updating it using propertyfile task. Something like
<property file="test.properties" />
<echo>before :: ${modules}</echo>
<propertyfile file="test.properties" >
<entry key="modules" type="string" operation="+" value="foo" />
</propertyfile>
<property file="${status.path}/test.properties" />
<echo>after :: ${modules}</echo>.
It doesn't seem to load the second time. But the property file is updated.
You can invoke a new ant runtime with the antcall task that ignores the properties of your main target runtime - just make sure to include inheritAll="false"
<target name="main">
<property file="test.properties"/>
<echo>before :: ${modules}</echo>
<propertyfile file="test.properties">
<entry key="modules" type="string" operation="+" value="foo" />
</propertyfile>
<antcall target="second-runtime" inheritAll="false"/>
</target>
<target name="second-runtime">
<property file="${status.path}/test.properties" />
<echo>after :: ${modules}</echo>
</target>
antcall refrence
As sudocode already mentioned, in Core Ant properties are immutable - for good reasons.
With the unset task from Antelope Ant Tasks you're able to unset all properties set in a file with a one liner :
<unset file="test.properties"/>
afterwards
<propertyfile file="test.properties" >
<entry key="modules" type="string" operation="+" value="foo" />
</propertyfile>
will work.
Hint : the task works only for normal properties, not for xmlproperties.
But there's a simple workararound, simply use <echoproperties prefix="..." destfile="foo.properties"/> and afterwards <unset file="foo.properties"/>
If you don't want to use Antelope for that specific task only, you may write a macrodef or own task with similar features.
For this case, when whole properties file is loaded twice, I suggest using different prefixes for the first and second load. First load with aprefix attribute equal to first. Access the properties with this prefix, that is property foo will be accessible as first.foo. Then save the properties file and load again, but this time without a prefix. You will get modified properties in suitable place.
Without using the prefix the second load will do nothing, as ant prevents properties from overriding. Others pointed that already.
Ant properties are immutable - once set, they are fixed. So reloading the properties file will not refresh the value of a property already set.
this macro allow you to change the property value after fixed one
<macrodef name="set" >
<attribute name="name"/>
<attribute name="value"/>
<sequential>
<script language="javascript">
<![CDATA[
project.setProperty("#{name}", "#{value}");
]]>
</script>
</sequential>
</macrodef>
you can create a new properties file and save the property in the new file.
Provide the reference of the file in the next line.
Done :)

Resources