How to create an Ant's symlink with wildcard? - ant

I've tried to create a symlink like:
<symlink link="${basedir}/docroot" resource="${basedir}/drupal-7.*" overwrite="true"/>
however, the line doesn't expand the wildcard but creates a link which points literally to drupal-7.*, not to drupal-7.56.
I've tried to use examples with fileset on this page, but it doesn't really cover my scenario.
How can I create an Ant's symlink which points to a dynamic folder (the one expanded by drupal-7.*)?

You should use dirset instead of fileset to include directories, not files. Also, it would probably be a good idea to check for an unexpected number of directories as well.
Here is the example:
<dirset dir="${basedir}" includes="drupal-7.*" id="link.target" />
<fail message="Multiple or zero drupal-7.* directories found.">
<condition>
<not>
<resourcecount refid="link.target" when="equal" count="1" />
</not>
</condition>
</fail>
<symlink link="${basedir}/docroot" resource="${toString:link.target}" />

Here is the solution by invoking shell command:
<exec executable="sh" failonerror="true" dir="${basedir}" outputproperty="drupaldir">
<arg value="-c"/>
<arg value="echo drupal-7*"/>
</exec>
<symlink link="${basedir}/docroot" resource="${basedir}/${drupaldir}" overwrite="true"/>

Related

Intentionally fail Ant build when using <delete> with a <fileset> including missing files

<delete includeEmptyDirs="false" failonerror="true">
<fileset dir="${dest.dir}" includes="a.txt,b.txt,c.abc"/>
</delete>
For example, if file a.txt is changed to a1.txt2 or something then Ant is not failing to find file. What to do?
That is not the purpose of failonerror attribute in this case.
From ant manual delete task :
Controls whether an error (such as a failure to delete a file)
stops the build or is merely reported to the screen. Only relevant if
quiet is "false".
It's not an error, if fileset doesn't match.
Also you don't need to set failonerror=true as it is default.
To make it fail, use fail with condition and resourcecount, f.e.:
<delete includeEmptyDirs="false" failonerror="true">
<fileset dir="${dest.dir}" includes="a.txt,b.txt,c.abc" id="foobar"/>
</delete>
<fail message="Fileset doesn't match !">
<condition>
<resourcecount when="eq" count="0">
<fileset refid="foobar"/>
</resourcecount>
</condition>
</fail>

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

modify ant classpath on the fly

I want to use resolvers (ssh) which are dependant on ant classpath.
Something like
<resolvers>
...
<ssh ...
...
</resolvers>
To use it I need jsch in ant classpath. Ant script should depends only on common lib (which also includes resolved jsch dependencies) - to use it on any client PC. Scenario is:
task to download lib.
Extract libs (jsch and etc.)
ivy:configure
But ivy:configure does not have any classpathref param, so it is unclear for me how to load jars I extracted.
Is it possible?
Or, probably, somehow run ant again internally with extended classpath?
Ok,
so my comment to question looked good for me but at the end it did not work.
The only way I found (working way I mean) is to to run ant script with
Download common-lib (with ) which includes all jar-libs required for optional ivy processing
Construct new classpath and run exec on same build file with required target:
<target name="call.task" if="wrapped.task.name">
<path id="ant.class.path">
<fileset dir="${tools.lib.dir}" >
<include name="*.jar" />
</fileset>
<pathelement location="${java.class.path}" />
</path>
<condition property="append.dest.dir" value="-Ddest.dir=${dest.dir}" else="">
<isset property="dest.dir"/>
</condition>
<exec executable="ant" failonerror="true">
<arg line="-f ivy-build.xml" />
<arg line='-lib "${toString:ant.class.path}"' />
<arg value="${wrapped.task.name}" />
<arg value="${append.dest.dir}" />
</exec>
</target>

Ant check existence for a set of files

In ant, how can i check if a set of files (comma-separated list of paths) exist or not?
For example I need to check if all paths listed in myprop exist and if so i want to set a property pathExist:
<property name="myprop" value="path1,path2,path3"/>
So in the example all of path1 path2 path3 must exist to set pathExist to true, otherwise false.
I discovered that for a single resource I can use the resourceexist task, but i can't figure out how to use that with a comma-separated list of paths.
How can I check the existence for a set of paths? Thanks!
You can use a combination of a filelist, restrict and condition task for this.
In the below example a filelist is created from the property with the comma-separated list of files. Using restrict a list of the files that don't exist is found. This is placed in a property which will be empty if all the files are found.
<property name="myprop" value="path1,path2,path3"/>
<filelist id="my.files" dir="." files="${myprop}" />
<restrict id="missing.files">
<filelist refid="my.files"/>
<not>
<exists/>
</not>
</restrict>
<property name="missing.files" refid="missing.files" />
<condition property="pathExist" value="true" else="false">
<length string="${missing.files}" length="0" />
</condition>
<echo message="Files all found: ${pathExist}" />
You could use something like this to generate a failure message listing the missing files:
<fail message="Missing files: ${missing.files}">
<condition>
<length string="${missing.files}" when="greater" length="0" />
</condition>
</fail>
Bundled conditions are the shortest solution to check for existence of multiple dirs or files :
<condition property="pathExist">
<and>
<available file="/foo/bar" type="dir"/>
<available file="/foo/baz" type="dir"/>
<available file="path/to/foobar.txt"/>
...
</and>
</condition>
To check for a commaseparated list of path use Ant addon Flaka , f.e. :
<project xmlns:fl="antlib:it.haefelinger.flaka">
<!-- when you have a cvs property use split function
to get your list to iterate over -->
<property name="checkpath" value="/foo/bar,/foo/baz,/foo/bazz"/>
<fl:for var="file" in="split('${checkpath}', ',')">
<fl:fail message="#{file} does not exist !!" test="!file.tofile.exists"/>
</fl:for>
</project>
Another possibility is the use of scriptcondition task with a jvm scripting language like groovy,beanshell .. etc.
This can be solved with the set operations of Ant´s resource collections. If you calculate the intersection of the list of required files with the list of existing files it must not differ from the list of required files. This shows how to do it:
<property name="files" value="a.jar,b.jar,c.jar"/>
<target name="missing">
<condition property="missing">
<resourcecount when="ne" count="0">
<difference id="missing">
<intersect>
<filelist id="required" dir="." files="${files}"/>
<fileset id="existing" dir="." includes="*.jar"/>
</intersect>
<filelist refid="required"/>
</difference>
</resourcecount>
</condition>
</target>
<target name="check" depends="missing" if="missing">
<echo message="missing: ${toString:missing}"/>
</target>
The check target reports the list of missing files only if a file is missing.

Iterating through a directory with Ant

Let's say I have a collection of PDF files with the following paths:
/some/path/pdfs/birds/duck.pdf
/some/path/pdfs/birds/goose.pdf
/some/path/pdfs/insects/fly.pdf
/some/path/pdfs/insects/mosquito.pdf
What I'd like to do is generate thumbnails for each PDF that respect the relative path structure, and output to another location, i.e.:
/another/path/thumbnails/birds/duck.png
/another/path/thumbnails/birds/goose.png
/another/path/thumbnails/insects/fly.png
/another/path/thumbnails/insects/mosquito.png
I'd like this to be done in Ant. Assume I'm going to use Ghostscript on the command line and I've already worked out the call to GS:
<exec executable="${ghostscript.executable.name}">
<arg value="-q"/>
<arg value="-r72"/>
<arg value="-sDEVICE=png16m"/>
<arg value="-sOutputFile=${thumbnail.image.path}"/>
<arg value="${input.pdf.path}"/>
</exec>
So what I need to do is work out the correct values for ${thumbnail.image.path} and ${input.pdf.path} while traversing the PDF input directory.
I have access to ant-contrib (just installed the "latest", which is 1.0b3) and I'm using Ant 1.8.0. I think I can make something work using the <for> task, <fileset>s and <mapper>s, but I am having trouble putting it all together.
I tried something like:
<for param="file">
<path>
<fileset dir="${some.dir.path}/pdfs">
<include name="**/*.pdf"/>
</fileset>
</path>
<sequential>
<echo message="#{file}"/>
</sequential>
</for>
But unfortunately the #{file} property is an absolute path, and I can't find any simple way of decomposing it into the relative components.
If I can only do this using a custom task, I guess I could write one, but I'm hoping I can just plug together existing components.
In the sequential task you could may be able to use the ant-contrib propertyregex task to map the input paths to output. For example:
<propertyregex override="yes" property="outfile" input="#{file}"
regexp="/some/path/pdfs/(.*).pdf"
replace="/another/path/\1.png" />
Which maps, for example /some/path/pdfs/birds/duck.pdf to /another/path/birds/duck.png.
For the sake of completeness, here's what I came up with for a target based on martin clayton's answer. It only works on Windows for now but that's because I haven't gotten around to installing Ghostscript in a non-proxy way yet on Mac OS X. Note that to be a cross-platform solution I had to "scrub" the file separators to be consistently forward-slash only.
<target name="make-thumbnails" depends="">
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<pathelement location="/path/to/ant-contrib-1.0b3.jar"/>
</classpath>
</taskdef>
<condition property="ghostscript.executable.name" value="/path/to/gswin32c.exe">
<os family="windows"/>
</condition>
<condition property="ghostscript.executable.name" value="">
<os family="mac"/>
</condition>
<for param="file">
<path>
<fileset dir="/path/to/pdfs">
<include name="**/*.pdf"/>
</fileset>
</path>
<sequential>
<propertyregex override="yes" property="file-scrubbed" input="#{file}"
regexp="\\"
replace="/" />
<propertyregex override="yes" property="output-path-directory-fragment" input="${file-scrubbed}"
regexp=".*/pdfs/(.*)/.+\.pdf"
replace="\1" />
<propertyregex override="yes" property="output-path-file-fragment" input="${file-scrubbed}"
regexp=".*/pdfs.*/(.+)\.pdf"
replace="\1.png" />
<mkdir dir="${thumbnails.base.dir}/${output-path-directory-fragment}"/>
<exec executable="${ghostscript.executable.name}">
<arg value="-q"/>
<arg value="-dLastPage=1"/>
<arg value="-dNOPAUSE"/>
<arg value="-dBATCH"/>
<arg value="-dSAFER"/>
<arg value="-r72"/>
<arg value="-sDEVICE=png16m"/>
<arg value="-sOutputFile=${thumbnails.base.dir}/${output-path-directory-fragment}/${output-path-file-fragment}"/>
<arg value="${file-scrubbed}"/>
</exec>
</sequential>
</for>
</target>

Resources