I'm aware that I can <exec executable="cp" failonerror="true">, however, I'd really rather have a task that I can call from any OS that can use all (or at least most) of the attributes to copy, but which doesn't suck away the permissions on unix.
I am wondering if there is already a solution out there, or will I have to write my own copy2.
As I was kind of afraid, there's nothing "off the shelf". We have this code, but it only handles directory to directory copy or file to file copy, has custom attributes, and doesn't do any of the other neat things copy does.
<!-- ==================================================================== -->
<!-- Copy files from A to B -->
<!-- <copy> would do this job, if it weren't such a useless pile of fail -->
<!-- and could manage to preserve execute bits on Linux -->
<!-- ==================================================================== -->
<macrodef name="internal-copydir">
<attribute name="fromdir" default="NOT SET" />
<attribute name="todir" default="NOT SET" />
<sequential>
<if>
<os family="windows" />
<then>
<copy todir="#{todir}">
<fileset dir="#{fromdir}" />
</copy>
</then>
<else>
<exec executable="rsync" failonerror="true">
<arg value="-a" />
<arg value="#{fromdir}/" />
<arg value="#{todir}/" />
</exec>
</else>
</if>
</sequential>
</macrodef>
<!-- ==================================================================== -->
<!-- Copy file from A to B -->
<!-- <copy> would do this job, if it weren't such a useless pile of fail -->
<!-- and could manage to preserve execute bits on Linux -->
<!-- ==================================================================== -->
<macrodef name="internal-copyfile">
<attribute name="file" default="NOT SET" />
<attribute name="tofile" default="NOT SET" />
<sequential>
<if>
<os family="windows" />
<then>
<copy file="#{file}" tofile="#{tofile}"/>
</then>
<else>
<exec executable="cp" failonerror="true">
<arg value="#{file}" />
<arg value="#{tofile}" />
</exec>
</else>
</if>
</sequential>
</macrodef>
I wrote this one too.
<!-- ==================================================================== -->
<!-- Copy file to a directory -->
<!-- <copy> would do this job, if it weren't such a useless pile of fail -->
<!-- and could manage to preserve execute bits on Linux -->
<!-- ==================================================================== -->
<macrodef name="internal-copyfiletodir">
<attribute name="file" default="NOT SET" />
<attribute name="todir" default="NOT SET" />
<sequential>
<if>
<os family="windows" />
<then>
<copy file="#{file}" todir="#{todir}"/>
</then>
<else>
<exec executable="cp" failonerror="true">
<arg value="#{file}" />
<arg value="#{todir}/" />
</exec>
</else>
</if>
</sequential>
</macrodef>
I'm not aware of one. As mentioned in the Ant documentation, this is because there was no mechanism to manipulate file permissions in the JRE. Ant Copy task
Java 7 brings much better support for this sort of thing, so perhaps in a future version of Ant this will be possible. This will likely take a very long time, as I think Ant is only moving to Java 5 for version 1.9.
I guess you might be able to simulate the behavior you are looking for by conditionally running OS specific commands based on the OS?
It's not ideal, but there is the "chmod" task that you could use to set the permissions on each file after a "copy" or "copydir":
http://ant.apache.org/manual/Tasks/chmod.html
Related
I am using the following code with the idea of finding a file in a directory that is also part of a list in a file:
<loadfile property="ReportFileContent" srcFile="${ReportFile}"/>
<for param="file">
<path>
<fileset dir="${MainDir}" includes="**/**"/>
</path>
<sequential>
<basename file="#{file}" property="#{file}" />
<condition property="found-file${index2}">
<matches pattern="#{file}" string="${ReportFileContent}"/>
</condition>
<if>
<isset property="found-file${index2}"/>
<then>
<echo message=" Found file #{file}" level="warning" />
</then>
<else>
<echo message="Not Found file #{file}" level="warning" />
</else>
</if>
<math result="index2" operand1="${index2}" operation="+" operand2="1" datatype="int" />
</sequential>
</for>
The command is not working though as it is not finding the file that is available in ${ReportFileContent}.
The content of the ReportFileContent property is the following:
c:\___tools\test\file1.txt;2
c:\___tools\test\file2.txt;2
c:\___tools\test\file3.txt;2
Any idea why the condition is not working correctly?
Thanks
Tony
I have a got a ANT build system which invokes builds on different projects using following macro;
<macrodef name="buildComponent">
<attribute name="name"/>
<attribute name="dir"/>
<attribute name="antTarget"/>
<attribute name="antCommonDistDir" />
<sequential>
<available property="build.xml.exists.#{dir}" file="#{dir}/build.xml" />
<if>
<equals arg1="${build.xml.exists.#{dir}}" arg2="true" />
<then>
<java classname="org.apache.tools.ant.launch.Launcher"
fork="true"
failonerror="true"
dir="#{dir}"
timeout="4000000"
output="${common.build.dir}/log/#{name}.log"
taskname="startAnt" >
<jvmarg value="-Dant.home=${ant.home}"/>
<classpath>
<pathelement location="${ant.home}/lib/ant-launcher.jar"/>
</classpath>
<arg value="-Dbasedir=#{dir}"/>
<arg value="#{antTarget}"/>
<arg value="-Dprop1=${prop1}" />
<syspropertyset refid="project.common.properties" />
<sysproperty key="common.dist.dir.os" value="#{antCommonDistDir}" />
</java>
</then>
</if>
</sequential>
</macrodef>
I would like to override properties form command line but the problem is that these properties are not being passed by task and my subsequent build uses the default values. For example I am executing the build as follows;
ant dist -Dprop1=override.prop1 -Dprop2=override.prop2 -Dprop3=override.prop3
As you see currently the only option for me to pass these overridden values from command line for prop2 and prop3 is add <arg /> under <java /> task for each property passed like I have done for 'prop1' which works but not desirable. Is there anyway I can access all properties passed to ANT and simply pass them as is to <java /> task?
You can use the echoproperties task to save all current Ant properties to a file, and then pass that file to the java task to be loaded by the subproject.
<echoproperties destfile="my.properties"/>
Having said this, a better solution instead of executing the java command to invoke another Ant build, you can simply call the ant task which will build your subproject and automatically inherit all properties from the parent project:
<available property="build.xml.exists.#{dir}" file="#{dir}/build.xml" />
<if>
<equals arg1="${build.xml.exists.#{dir}}" arg2="true" />
<then>
<ant antfile="#{dir}/build.xml" target="#{antTarget}"/>
</then>
</if>
I couldn't find any thing which can do this directly. So I ended up writing a javascript and populated a ant property to parse command line options which was stored in env variable and passed it to <java /> task as <arg line="${command.line.properties}" />. Remember to use <arg line="" /> as it trim out all extra spaces etc before invoking a task.
I have a jar file in /programs/src i want my program to print a message that it is present in the directory:
<if>
<available file="**/*.jar" />
<then>
<echo message="Available" />
</then>
<else>
<echo message="Not Available" />
</else>
but it is not working
There's nothing in the documentation for <available> that says it can handle wildcards. You need to use an actual file path.
You may use the builtin ${toString:yourfilesetid} mechanism from ant combined with Ant Addon Flaka like that :
<project name="demo" xmlns:fl="antlib:it.haefelinger.flaka">
<fileset dir="/home/rosebud/temp" includes="**/*.jar" id="foobar"/>
<fl:choose>
<fl:when test=" '${toString:foobar}' ne '' ">
<echo message="Available" />
<!-- .. other stuff -->
</fl:when>
<fl:otherwise>
<echo message="Not Available" />
<!-- .. other stuff -->
</fl:otherwise>
</fl:choose>
</project>
I want do compile all *.less scripts in a specific folder and it subdirs with less-rhino-1.1.3.js.
There is an example on github for doing this for a specific file, which works perfect. But I want to do the same for a complete folder. I tried a lot, here is my last try.
It doesn't work, propertyregex seems not to be standard ANT, I don't want to use such things. I am not even sure if this code would work.
<project name="test" default="main" basedir="../../">
<property name="css.dir" location="public/css"/>
<property name="tool.less" location="bin/less/less-rhino-1.1.3.js"/>
<property name="tool.rhino" location="bin/tools/rhino/js.jar"/>
<macrodef name="lessjs">
<attribute name="input" />
<attribute name="output" />
<sequential>
<java jar="${tool.rhino}" fork="true" output="#{output}">
<arg path="${tool.less}"/>
<arg path="#{input}"/>
</java>
<echo>Lessjs: generated #{output}</echo>
</sequential>
</macrodef>
<target name="main">
<echo>compiling less css</echo>
<fileset dir="${css.dir}" id="myfile">
<filename name="**/*.less" />
</fileset>
<property name="lessfilename" refid="myfile"/>
<propertyregex property="cssfilename"
input="${lessfile}"
regexp="^(.*)\.less$"
replace="^\1\.css$"
casesensitive="true" />
<lessjs input="lessfile" output="cssfilename"/>
</target>
</project>
You could use the <fileset> to include all the less files need to be compiled. Later, you could use<mapper> to mark the corresponding detination css file.
<project name="test" default="main" basedir="../../">
<property name="css.dir" location="public/css"/>
<property name="tool.less" location="bin/less/less-rhino-1.1.3.js"/>
<property name="tool.rhino" location="bin/tools/rhino/js.jar"/>
<target name="less" description="Convert LESS to CSS then concatenate and Minify any stylesheets">
<echo message="Converting LESS to CSS..."/>
<!-- Clear the former compiled css files -->
<delete includeemptydirs="true">
<fileset dir="${css.dir}" includes="*.css, **/*.css" defaultexcludes="false"/>
</delete>
<apply dir="${css.dir}" executable="java" parallel="false" failonerror="true">
<!-- Give the input bundle of less files-->
<fileset dir="${css.dir}">
<include name="*.less"/>
</fileset>
<arg value="-jar" />
<arg path="${tool.rhino}" />
<arg path="${tool.less}" />
<srcfile/>
<!-- Output the compiled css file with corresponding name -->
<mapper type="glob" from="*.less" to="${css.dir}/*.css"/>
<targetfile/>
</apply>
</target>
</project>
I was able to piece together a working solution with the help of a couple of SO answers:
ANT script to compile all (css) LESS files in a dir and subdirs with RHINO
How to correctly execute lessc-rhino-1.6.3.js from command line
I had to download LESS 1.7.5 from GitHub and modify the Ant target to look like this. The -f argument and LESS JavaScript was key:
<property name="css.dir" value="WebContent/css"/>
<property name="less.dir" value="less"/>
<property name="tool.rhino.jar" value="test-lib/rhino-1.7R4.jar"/>
<property name="tool.rhino.lessc" value="test-lib/lessc-rhino-1.7.5.js"/>
<property name="tool.rhino.less" value="test-lib/less-rhino-1.7.5.js"/>
<target name="compile-less" description="compile css using LESS">
<apply dir="${css.dir}" executable="java" parallel="false" failonerror="true">
<fileset dir="${less.dir}">
<include name="styles.less"/>
</fileset>
<arg value="-jar"/>
<arg path="${tool.rhino.jar}"/>
<arg value="-f"/>
<arg path="${tool.rhino.less}"/>
<arg path="${tool.rhino.lessc}"/>
<srcfile/>
<mapper type="glob" from="*.less" to="${css.dir}/*.css"/>
<targetfile/>
</apply>
</target>
If anyone else is coming to this question recently, as I did, they may find that the less-rhino-1.1.3.js file given in the other answers does not work with the latest version of Rhino (which for me, as of now, is 1.7R4 from MDN). But the 1.4.0 version does, which can be obtained from Github here. So the relevant snippet from my build.xml, using these later versions, is shown. Note that I'm only compiling a single .less file to a single .css file, so no iteration or mappers are used (but obviously you can get those from the other answers). Other tweaks I made were to provide the output file as the final arg to less instead of capturing output from the Ant forked process, and to remove the dependency on ant-contrib stuff (not needed for the simple one-file case).
<property name="tool.rhino" value="build/lesscss/rhino1_7R4/js.jar" />
<property name="tool.less" value="build/lesscss/less-rhino-1.4.0.js" />
<property name="single-input-lesscss-file" value="/path/to/my/style.less" />
<property name="single-output-css-file" value="/output/my/style.css" />
<target name="compileLessCss" description="Compile the single less file to css">
<sequential>
<java jar="${tool.rhino}" fork="true">
<arg path="${tool.less}" />
<arg path="${single-input-lesscss-file}" />
<arg path="${single-output-css-file}" />
</java>
</sequential>
</target>
If maven is an option for you, you could try wro4j-maven-plugin or wro4j-runner (which is a command line utility).
Using one of these, all you have do is to create an resource model descriptor (wro.xml):
<groups xmlns="http://www.isdc.ro/wro">
<group name="g1">
<css>/path/to/*.less</css>
</group>
</groups>
The rest will be handled by the wro4j library. No need to carry about how rhino works or other details.
Disclaimer: I'm working on wro4j project
I had the same issue. I developed a solution using ant-contrib. It expects all of your .less files to be in one flat directory and to be moved to another flat directory. It will change the file extension to .css in the process.
<property name="tool.rhino" value="/rhino/js.jar" />
<property name="tool.less" value="src/js/less-rhino-1.1.3.js" />
<property name="tool.ant-contrib" value="/ant-contrib/ant-contrib-1.0b3-1.0b3.jar" />
<property name="less-files-dir" value="src/css/" />
<property name="css-files-dir" value="build/css/" />
<target name="compilecss" depends="setup-ant-contrib-taskdef, get-less-files-in-dir" description="DO THIS THING">
<for list="${less-files-to-convert}" param="file-name" trim="true" delimiter=",">
<sequential>
<propertyregex property="file-name-without-extension"
input="#{file-name}"
regexp="(.*)\..*"
select="\1"
override="yes" />
<java jar="${tool.rhino}" fork="true" output="${css-files-dir}${file-name-without-extension}.css">
<arg path="${tool.less}" />
<arg path="${less-files-dir}#{file-name}" />
</java>
<echo>Lessjs: generated ${css-files-dir}${file-name-without-extension}.css</echo>
</sequential>
</for>
</target>
<target name="check-for-ant-contrib">
<condition property="ant-contrib-available">
<and>
<available file="${tool.ant-contrib}"/>
</and>
</condition>
<fail unless="ant-contrib-available" message="Ant-Contrib is not available."/>
</target>
<target name="setup-ant-contrib-taskdef" depends="check-for-ant-contrib">
<taskdef resource="net/sf/antcontrib/antlib.xml">
<classpath>
<path location="${tool.ant-contrib}" />
</classpath>
</taskdef>
</target>
<target name="get-less-files-in-dir">
<var name="files-list" value="" />
<for param="file">
<path>
<fileset dir="${less-files-dir}" includes="**/*.less" />
</path>
<sequential>
<propertyregex property="file-name-and-relative-path"
input="#{file}"
regexp=".*\\(.*)"
select="\1"
override="yes" />
<echo>file name: ${file-name-and-relative-path}</echo>
<if>
<equals arg1="${files-list}" arg2="" />
<then>
<var name="files-list" value="${file-name-and-relative-path}" />
</then>
<else>
<var name="files-list" value="${files-list},${file-name-and-relative-path}" />
</else>
</if>
</sequential>
</for>
<property name="less-files-to-convert" value="${files-list}" />
<echo>files to convert: ${less-files-to-convert}</echo>
</target>
I was unable to get this to run using a JDK 1.6 since the javascript stuff has been incorporated to the JDK. The JDK does have a jrunscript executable in the distribution but when I try to run the less-rhino.js file it fails to recognize any readFile() function. Has anyone looked into that. Otherwise I may be giving the lesscss-engine a shot and enhancing it to understand filesets.
I am using Ant to do a database build by basically using the exec task to run some SQL scripts.
However, there might be errors generated during the script execution (e.g. could not properly drop a connected user, etc) so I check for this by looking through two output log files.
Here's a snippet of the relevant target:
<target name="build">
<echo message="Add foo bar baz"/>
<exec executable="${db.sqlplus}">
</exec>
<echo message="Load x y z"/>
<exec executable="${db.sqlplus}" dir="foobar">
</exec>
<!--Check the log files here-->
<antcall target="check-log-file">
<param name="file.to.check" value="${output.log.1}"/>
</antcall>
<antcall target="check-log-file">
<param name="file.to.check" value="${output.log.2}"/>
</antcall>
<antcall target="fail-if-error"/>
</target>
<!--=============================================================================
Check the file named in the property file.to.check to see if there are errors.
The way this works is to find all lines containing the text "ERROR" and put
them into a separate file. Then it checks to see if this file has non-zero
length. If so, then there are errors, and it sets the property errors.found.
Then it calls the send-email target, which doesn't execute if the
errors.found property isn't set.
-->
<target name="check-log-file"
description="Checks the file (specified in ${file.to.check}) for errors">
<property name="file.errorcount" value="${file.to.check}.errorcount"
description="The file to hold the error lines"/>
<copy file="${file.to.check}" tofile="${file.errorcount}">
<filterchain>
<linecontains>
<contains value="ERROR"/>
</linecontains>
</filterchain>
</copy>
<condition property="errors.found" value="true">
<length file="${file.errorcount}" when="gt" length="0"/>
</condition>
<antcall target="check-log-file-send-email"/>
</target>
<!--=========================================================================
If there are any errors, send an email to let someone know
-->
<target name="check-log-file-send-email" if="errors.found"
description="Sends an email out if error detected">
<resourcecount property="error.count">
<tokens><!-- default tokenizer is a line tokenizer -->
<file file="${file.to.check}.errorcount"/>
</tokens>
</resourcecount>
<echo
message="Database build (${e1.codeline} - ${error.count} errors found..."/>
<antcall target="mail">
<param name="from-address" value="build"/>
<param name="to-list" value="myemail"/>
<param name="subject"
value="Automated database build error report for ${db.host}"/>
<param name="message"
value="See attached log file, ${error.count} error(s)found..."/>
<param name="attach" value="${file.to.check}"/>
</antcall>
</target>
<!--==========================================================================
Fails the database build if errors were detected.
-->
<target name="fail-if-error" if="errors.found">
<echo message="Errors found - setting database fail flag..."/>
<fail message="Errors detected during ${codeline} database build. Check logs."/>
</target>
When there are errors the build does not fail.
I think it's because the antcall task to check the logs does not return the property error.
Found back to the build target, so when fail-if-error is called, that property is unset.
Is that right?
Is there a way to set it up to fail properly?
The antcall will set the property in the scope of its execution, so when you get to your check it is not set. Instead try using a macrodef, this will run in the current scope and set the errors-found property in that scope so the later check can read it. You'd define the macrodef something like this:
<macrodef name="check-log-file">
<attribute name="fileToCheck"/>
<!--note attributes are referenced with an "#" rather than a "$" -->
<property name="file.errorcount" value="#{fileToCheck}.errorcount"/>
<copy file="#{fileToCheck}" tofile="${file.errorcount}">
...
</macrodef>
and call it like this:
<check-log-file fileToCheck="${output.log.1}"/>
<check-log-file fileToCheck="${output.log.1}"/>
Thanks to Rich Seller, who provided the idea of using a macrodef. The macrodef needed a little cleanup (property not allowed inside a macrodef, tasks need to be wrapped in a sequential tag) so I'm providing it here in full:
<macrodef name="check-log-file">
<attribute name="file.to.check"/>
<attribute name="file.errorcount" default="#{file.to.check}.errorcount" description="The file to hold the error lines"/>
<sequential>
<copy file="#{file.to.check}" tofile="#{file.errorcount}">
<filterchain>
<linecontains>
<contains value="ERROR"/>
</linecontains>
</filterchain>
</copy>
<condition property="errors.found" value="true">
<length file="#{file.errorcount}" when="gt" length="0"/>
</condition>
<antcall target="check-log-file-send-email">
<param name="file.to.check" value="#{file.to.check}"/>
</antcall>
</sequential>
</macrodef>
General log file checking with Errors and Warnings
Here is a general macrodef that can be used to scan files for issues. As long as you can write a regexp for the issue, it can check for it...
It can fail or not if the issue is found.
It summarises the issues found, writing them to the Ant output.
The files to scan can be indicated with wildcards.
Here are example calls to check log files for Oracle errors:
Fail on "SP2-" errors
Warn on "ORA-" errors
Warn on "ERROR:" text.
<check_for_errors file.to.check.dir="${buildlogs}" file.to.check.include="*.log" error.pattern="SP2-" />
<check_for_errors file.to.check.dir="${buildlogs}" file.to.check.include="*.log" error.pattern="ORA-" error.action="warn" />
<check_for_errors file.to.check.dir="${buildlogs}" file.to.check.include="*.log" error.pattern="ERROR:" error.action="warn" />
Here are example calls to check for unreplaced tokens in generated sql files, before execution:
<check_for_errors file.to.check.dir="${distdir}" file.to.check.include="**/\*.sql"
error.name="Token" error.pattern="^(?!--).+#[^# ]+#" error.display.find=".*(#[^# ]+#).*" error.display.show=" Token = '\1'"/>
<check_for_errors file.to.check.dir="${distdir}" file.to.check.include="**/*.sql"
error.name="Token" error.pattern="^(?!--).+#\$\{[^ }]+\}" error.display.find=".*(\$\{[^ }]+\}).*" error.display.show=" Token = '\1'"/>
Here is the macrodef:
<macrodef name="check_for_errors">
<attribute name="file.to.check.dir" default="." />
<attribute name="file.to.check.include" default="*.log" />
<attribute name="file.to.check.exclude" default="" />
<attribute name="error.pattern" default="ERROR" />
<attribute name="error.name" default="ERROR" />
<attribute name="error.action" default="fail" />
<attribute name="error.display.find" default="(.+)" />
<attribute name="error.display.show" default=" \1" />
<sequential>
<echo message="Excluding file ${buildlogfile}" level="debug" />
<for param="file.to.check.name">
<fileset dir="#{file.to.check.dir}">
<include name="#{file.to.check.include}"/>
<exclude name="#{file.to.check.exclude}"/>
<exclude name="${buildlogfile}"/>
<containsregexp expression="#{error.pattern}"/>
</fileset>
<sequential>
<echo message="ERROR: #{error.name} found in file '#{file.to.check.name}' :" level="warn" />
<concat>
<fileset file="#{file.to.check.name}" />
<filterchain>
<linecontainsregexp>
<regexp pattern="#{error.pattern}" />
</linecontainsregexp>
<replaceregex pattern="#{error.display.find}" replace="#{error.display.show}" />
</filterchain>
</concat>
<property name="error.check.foundvalues" value="true" />
</sequential>
</for>
<condition property="error.check.fail">
<and>
<matches string="#{error.action}" pattern="fail" />
<isset property="error.check.foundvalues" />
</and>
</condition>
<fail message="ERROR: Fix the above errors and try again. Exiting..." if="error.check.fail"/>
</sequential>
</macrodef>