I'm going to post a question that I've seen variants of elsewhere, but where I've not quite seen the answer I came up with. I'll subsequently post my answer.
In order to modularize my build script using macros, I would like to put both the updatetask and the task I want to execute if it is not up to date, in the same macro.
How do I do this - utilizing the script tag is ok - if the only unique attribute being passed in is a path containing backslashes, and I need to be able pass different values to the script tag on different invocations. I need to avoid any issues that might happen with string literals when a backslash is involved. Using the unique attribute I need to work around the ant immutable property behavior, and work around the ant pattern that typically uses 2 targets to handle uptodate processing decisions and need to work around the javascript handling of backslashes in string literals.
Note I'm working with ant 1.7. With local scoping in Ant 1.8 there are some additional options so that immutability is not such a big challenge, but some of these other tips will still be helpful.
First, regarding the issue of optionally executing a task based on the results of uptodate within a macro - which means you don't need 2 targets. To do this, use the condition tag. The <or> tag will cause it to only execute the second condition if the first condition fails. The <scriptcondition> tag allows to use javascript to execute other ant tasks. Here's an example (@ tags indicate macrodef attributes):
Now, if you are like me, you may want to do some processing with the attributes that are your macrodef inputs and produce some derived values which can be referenced in your macrodef script. If you are processing simply involves concatentation of attributes and strings, you can do that in the block were you specify your attributes be specifying a second set of attributes with a default setting that contains the concatentation steps. However, if you need to do something that you can't plug into an attribute default, you will need to put it in a property. Because properties are immutable, you need to take some extra steps to give your property unique names. The tstamp comes in handy to help with this. Typically some combination of the parameters passed to your macro will be unique, but if this unique combination icludes backslashes, you'll want to derive a secondary unique identifier using the tstamp tag so that you don't run into backslash issues in your javascript when you want to use these derived properties. Here's how to create your unique properties which you can easily reference in your script.
Before I came up with the above solution, I came up with a hack style of solution for overriding an ant property with a new value. While you may find this useful to override a property, because I'm making a direct call to an ant class, there is a risk that this might not work the same in future versions of ant. Because this seems like more of a hack, my intent is to use the 2 macrodef approach listed above rather than this approach when possible. Note this particular variation doesn't support backslash characters because the attributes are directly referenced in a javascript string literal. I used this simple variation initially to create my unique prefix, which prevented the need to a 2 macrodef approach to working around property immutability. You could however adapt this macrodef to use a 2nd macrodef and unique prefix in order to get the "@{value}" into the javascript using a project.getProperty command.
At first blush, some of this may seem a bit complex, but if you do your macrodef work right and build component style macros (i.e. don't put spaghetti code in your macro), your ant scripts should actually become shorter, easier to understand and easier to maintain and the logs will be easier to follow. Tip - only use javascript when necessary and when you use it, it is preferrable to use it within a macro so that it is encapsulated and hidden away from the main 'logic' of your ant script, thereby aiding in the self documenting and readable nature of your main 'logic'. Use comments when things are not obvious.