Filtering Files In-Place with Ant? - ant

I have a directory of files for which I'd like to do "in-place" string filtering using Apache Ant (version 1.7.1 on Linux).
For example, suppose that in directory mydir I have files foo, bar, and baz. Further suppose that all occurences of the regular expression OLD([0-9]) should be changed to NEW\1, e.g. OLD2 → NEW2. (Note that the replace Ant task won't work because it does not support regular expression filtering.)
This test situation can be created with the following Bash commands (ant will be run in the current directory, i.e. mydir's parent directory):
mkdir mydir
for FILE in foo bar baz ; do echo "A OLD1 B OLD2 C OLD3" > mydir/${FILE} ; done
Here is my first attempt to do the filtering with Ant:
<?xml version="1.0"?>
<project name="filter" default="filter">
<target name="filter">
<move todir="mydir">
<fileset dir="mydir"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="OLD([0-9])" replace="NEW\1" flags="g"/>
</tokenfilter>
</filterchain>
</move>
</target>
</project>
Running this first Ant script has no effect on the files in mydir. The overwrite parameter is true by default with the move Ant task. I even fiddled with the granularity setting, but that didn't help.
Here's my second attempt, which "works," but is slightly annoying because of temporary file creation. This version filters the content properly by moving the content to files with a filtered suffix, then the filtered content is "moved back" with original filenames:
<?xml version="1.0"?>
<project name="filter" default="filter">
<target name="filter">
<move todir="mydir">
<globmapper from="*" to="*.filtered"/>
<fileset dir="mydir"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="OLD([0-9])" replace="NEW\1" flags="g"/>
</tokenfilter>
</filterchain>
</move>
<move todir="mydir">
<globmapper from="*.filtered" to="*"/>
<fileset dir="mydir"/>
</move>
</target>
</project>
Can the first attempt (without temporary files) be made to work?

See the replace task:
<replace
dir="mydir"
includes="foo, bar, baz">
<replacefilter token="OLD" value="NEW" />
</replace>
or the replaceregexp task:
<replaceregexp
file="${src}/build.properties"
match="OldProperty=(.*)"
replace="NewProperty=\1"
byline="true"/>

Related

File delete is not working via ant script

I have written an Ant script in which there is some block of codes which create a temp file and apply ant filters to that temp file and generate new one.
following is the code:
<copy tofile="${file.report.name}.html" file="${file.report.name}-temp.html">
<filterchain>
<tokenfilter>
<replaceregex pattern="\[(echo|script|apply|copy)\]" replace="" />
</tokenfilter>
</filterchain>
<filterchain>
<linecontains negate="true">
<contains value="Copying"/>
</linecontains>
</filterchain>
</copy>
<antcall target="final.cleanup"/>
and then i call a target for deletion of generated temp file. but its giving me some error saying that script is unable to delete the respected file.
Following code block i am using for deletion of temp file:
<target name="final.cleanup">
<delete file="reports/report-temp.html"/>
</target>
What went wrong? Is this file is being used in some process that's why it giving me the error !

ANT replacing strings in specified files using file with properties

I have a properties in file dev.properties and they look like this:
test.url=https://www.example.com/
[...]
and in project files there is a token [[test.url]] which I want to replace by https://www.example.com/. I just want to define all tokens in dev.properties and use them in build script, but without modifying build script and I want to replace those tokens in a specified files like *.php, *.html, etc.
Can someone give me a suggestions how to do it? Thanks.
try this:
<copy file="input.txt" tofile="output.txt">
<filterchain>
<replaceregex pattern="\$\{" replace="{" />
<filterreader classname="org.apache.tools.ant.filters.ReplaceTokens">
<param type="propertiesfile" value="properties.txt"/>
<param type="tokenchar" name="begintoken" value="{"/>
<param type="tokenchar" name="endtoken" value="}"/>
</filterreader>
</filterchain>
</copy>
Founded here: Ant replace token from properties file
In the following Ant script, replace the src-root property with the root directory containing the tokenized files:
<project name="ant-replace-tokens-with-copy-task" default="run">
<target name="run">
<!-- The <copy> task cannot "self-copy" files. So, for each -->
<!-- matched file we'll have <copy> read the file, replace the -->
<!-- tokens, and write the result to a temporary file. Then, we'll -->
<!-- use the <move> task to replace the original files with the -->
<!-- modified files. -->
<property name="src-root" location="src"/>
<property name="filtered-file.extension" value="*.filtered-file"/>
<copy todir="${src-root}">
<fileset dir="${src-root}">
<include name="**/*.html"/>
<include name="**/*.php"/>
</fileset>
<globmapper from="*" to="${filtered-file.extension}"/>
<filterchain>
<filterreader classname="org.apache.tools.ant.filters.ReplaceTokens">
<param type="propertiesfile" value="dev.properties"/>
</filterreader>
</filterchain>
</copy>
<move todir="${src-root}">
<fileset dir="${src-root}" includes="**"/>
<globmapper from="${filtered-file.extension}" to="*"/>
</move>
</target>
</project>
You specified that you do not want to edit your build script so this answer does not qualify but may still be useful to other readers.
If you were willing to edit your target file to use the format ${test.url} instead of [[test.url]] then ExpandProperites would be an excellent choice.

Ant: Apply with fileset, but only exec once on one file?

I'm working on something similar to the question here: ANT script to compile all (css) LESS files in a dir and subdirs with RHINO
However, I'm having a hard time customizing this to one particular requirement:
If any .less files in dir.less change: Run LESS on just one file (as it imports the other less files, making a single, combined output).
This is the state of my current build.xml:
<target name="less" description="Compile LESS files">
<echo message="Checking for LESS file changes..."/>
<apply dir="${dir.less}" executable="${tool.less}" parallel="false" failonerror="true">
<fileset dir="${dir.less}" includes="*.less" />
<srcfile/>
<mapper type="glob" from="*.less" to="${dir.css}/*.css"/>
<targetfile/>
<arg value="-compress" />
</apply>
</target>
This currently builds all of the .LESS files and outputs them toe the appropriate location (Which is livable). If I replace the mapper glob with:
<mapper type="glob" from="MainFileThatImportsOthers.less" to="${dir.css}/MainFileThatImportsOthers.css"/>
The fileset directive is effectively reduced to that one file, and changing the other .LESS files in that directory don't cause output from the task.
Can someone point me in the right direction so I can avoid setting this up wrong and recusing through each .LESS file every time?
I worked out a solution that works correctly, I used an upToDate task to set a property to conditionally trigger Exec for the compiler:
<target name="scanLess" description="Scan for LESS file changes">
<echo message="Checking for LESS file changes..."/>
<uptodate property="tool.less.changed" targetfile="${dir.css}/MyFile.css" >
<srcfiles dir="${dir.less}" includes="*.less" />
</uptodate>
</target>
<target name="less" depends="scanLess" unless="tool.less.changed" description="Compile LESS files" >
<echo message="LESS files changed, running lessc" />
<exec executable="${tool.less}" failonerror="true">
<arg value="${dir.less}/MyFile.less" />
<arg value="${dir.css}/MyFile.css" />
<arg value="-compress" />
</exec>
</target>
Investigate how selectors work in ANT

How to apply an Ant task to a list of values in a string

I am working on an Ant script that aims to mimic the 'shadow folder' concept of VSS as a stop-gap solution to migrating from VSS to Subversion (without needing to reconfigure our build management software). The script is fairly straightforward:
create build folder
extract source files from Subversion into build folder
translate source files
copy source and object code files from build folder to final spot used for deployment
All works 'well' in the case where I pull down the entire trunk into the build folder and go from there...except that it takes 30+ minutes to 'build' and I was hoping to kick this off as part of the post-commit event (again, to mimic VSS's 'shadow folder' feature, which keeps a 'most recent' copy of all files in a folder independent of the VSS database and is updated in response to all check-ins).
I've been hacking away at the script with the goal to perform a more targeted download of just the files that have been changed (svn diff gives me the list of files, svn export can be used to pull them down individually, I believe).
Now, to the question: is there a way, with Ant Core, to 'iteratively' invoke targets for each element of a list? This is a repeat of the question posted here:
In ant, how to apply a target on a list of files (without ant-contrib)?
but I refuse to accept that this cannot be done natively. This post:
How to distribute each element of a list to argument of a task Ant?
gives me hope, but I lack the fundamental understanding of how Ant works (or was designed) to give up. I'm holding out hope that I can do something like:
<?xml version="1.0" encoding="UTF-8"?>
<project name="Test XmlProperty" default="test" basedir=".">
<target name="test">
<xmlproperty file="log.xml" collapseAttributes="true" />
<echo>Affected resources: ${log.logentry.paths.path}</echo>
<macrodef name="svnExportFile">
<attribute name="svnRepoUrls"/>
<sequential>
<loadresource property="lead.path">
<string value="${svnRepoUrls}"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="(\w+)[,${line.separator}]*.*" replace="\1" flags="g"/>
</tokenfilter>
</filterchain>
</loadresource>
<loadresource property="rest.paths">
<string value="${svnRepoUrls}"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="(\w+)[,${line.separator}]*(.*)" replace="\2" flags="g"/>
</tokenfilter>
</filterchain>
</loadresource>
<echo message="${lead.path}"/>
<echo message="${rest.paths}"/>
<svnExportFile svnRepoUrls="${rest.paths}"/>
</sequential>
</macrodef>
<svnExportFile svnRepoUrls="${log.logentry.paths.path}"/>
</target>
</project>
though I don't have the regular expression working quite right. Is this a major violation of Ant? Should I give up hope and simply run with Ant-contrib? I've been slow to adopt it, because it appears there have been no updates since 2008 and I was hoping to limit the amount of dependencies required for all of this stuff to work.
Any thoughts?
Edit: I am getting closer (sort of)...the code above wasn't quoted correctly in the initial post and I hadn't had a chance to try it out before posting (needed to leave and didn't want to lose all I had typed). Anyway, there is no way to stop recursing (and I suspect the properties are immutable, thus will not reset as I'd like them to), so it doesn't work (yet?).
I tried to accomplish the same basic concept as above with (I know it's frowned upon, but it's quite convenient in that it allows you to conditionally execute tasks via 's if/unless attributes) -- this does not work, though, because Ant doesn't want to allow recursion, apparently:
'antcall task calling its own parent target'
and trying to kick off recursion via depends:
'Circular dependency: svn.export.file <- svn.export.file'
In case anyone is curious, here is the version:
<?xml version="1.0" encoding="UTF-8"?>
<project name="Test XmlProperty" default="test" basedir=".">
<target name="test">
<xmlproperty file="log.xml" collapseAttributes="true" />
<echo>Affected resources: ${log.logentry.paths.path}</echo>
<antcall target="svn.export.file" inheritAll="false">
<param name="svnRepoUrls" value="${log.logentry.paths.path}"/>
</antcall>
</target>
<target name="svn.export.file" if="svnRepoUrls">
<loadresource property="lead.path">
<string value="${svnRepoUrls}"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="(\w+)[,${line.separator}]*.*" replace="\1" flags="g"/>
</tokenfilter>
</filterchain>
</loadresource>
<loadresource property="rest.paths">
<string value="${svnRepoUrls}"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="(\w+)[,${line.separator}]*(.*)" replace="\2" flags="g"/>
</tokenfilter>
</filterchain>
</loadresource>
<echo message="${lead.path}"/>
<echo message="${rest.paths}"/>
<antcall target="svn.export.file" inheritAll="false">
<param name="svnRepoUrls" value="${rest.paths}"/>
</antcall>
</target>
</project>
I admit, it's ugly...and I'm not too certain if I'm going to stick with it as my solution (I think I might go ahead and install ant-contrib, since this 'code' is both ugly and confusing) -- but it seems to do the trick and it sort of proves my theory that, yes, you can invoke a target for each element in a list without relying on !
<?xml version="1.0" encoding="UTF-8"?>
<project name="Test XmlProperty" default="test" basedir=".">
<target name="test">
<xmlproperty file="log.xml" collapseAttributes="true" />
<echo>Affected resources: ${log.logentry.paths.path}</echo>
<antcall target="svn.export" inheritAll="false">
<param name="svn.repo.urls" value="${log.logentry.paths.path}"/>
</antcall>
</target>
<target name="svn.export" if="svn.repo.urls">
<macrodef name="svnExportFile">
<attribute name="urls"/>
<sequential>
<macrodef name="parsePath">
<attribute name="property"/>
<attribute name="replacePart"/>
<sequential>
<loadresource property="#{property}">
<string value="#{urls}"/>
<filterchain>
<tokenfilter>
<replaceregex pattern="([^,]+),?(.*)" replace="#{replacePart}" flags="g"/>
</tokenfilter>
</filterchain>
</loadresource>
</sequential>
</macrodef>
<parsePath property="lead.path" replacePart="\1"/>
<fail>
<condition>
<not>
<isset property="lead.path"/>
</not>
</condition>
</fail>
<parsePath property="rest.paths" replacePart="\2"/>
<echo>lead.path:${lead.path}</echo>
<echo>rest.paths:${rest.paths}</echo>
<antcall target="svn.export.deux"/>
</sequential>
</macrodef>
<svnExportFile urls="${svn.repo.urls}"/>
</target>
<target name="svn.export.deux" if="rest.paths">
<echo>rest.paths:${rest.paths}</echo>
<echo>svn.repo.urls:${svn.repo.urls}</echo>
<antcall target="svn.export" inheritAll="false">
<param name="svn.repo.urls" value="${rest.paths}"/>
</antcall>
</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