Using a tstamp to delete files has started failing - ant

I use a tstamp to build a fileset of old files to delete. This has been working well, but since around the start of the month it fails.
The error is:
Date of 08/09/2021 01:25 PM Cannot be parsed correctly. It should be in MM/DD/YYYY HH:MM AM_PM format.
<target name="RemoveOldBackups" >
<tstamp>
<format property="BKRetention" pattern="MM/dd/yyyy hh:mm a" locale="en,UK" offset="-${Backup.Retention.Number}" unit="${Backup.Retention.Unit}"/>
</tstamp>
<for list="${Database.List}" param="database" parallel="${parallel}" threadCount="${threadCount}">
<sequential>
<echo message="Working on Database: #{database} Full path: ${Database.List.#{database}.Location}${Database.List.#{database}.FileName}" />
<delete>
<fileset dir="${Database.List.#{database}.LocalBackup}" includes="**/*.bkp">
<date datetime="${BKRetention}" when="before"/>
</fileset>
</delete>
</sequential>
</for>
</target>
The script itself hasn't changed in that time period, so it must be something environment related.

After further investigation I established that the machine was running a version on Ant from 2012. After updating to the latest release the problem is fixed.

https://ant.apache.org/manual/Tasks/tstamp.html has "aa" instead of "a" in the pattern. Might be worth a try. An the locale should be "en,GB" from my point of view (or that is the actual issue and should be de,DE).

Related

Using Ant, can I change a property name if it already exists?

I currently have a batch file that will copy some test results to a directory. That directory will have a date (yyyy-mm-dd). If that date already exists, it will create a new folder with that same date, but append a run number (yyyy-mm-dd run 2, yyyy-mm-dd run 3)
#echo off
title Copy the FF results to the results folder
set "date=%date:~10,4%-%date:~4,2%-%date:~7,2%"
set "run="
set "browser=FF"
set "results_paste=C:\TestProject\Results"
:loop
if "%run%"=="1" set "date=%date%_run "
if "%run%"=="1" set "run=2"
if EXIST "%results_paste%\%date%%run%\%browser%\" set /a run+=1&goto loop
REM Create HTML directory and copy results
xcopy "%workspace%\test-output\html\*.*" "%results_paste%\%date%%run%\%browser%\"
REM Create screenshot directory and copy results
xcopy "%workspace%\test-output\XML\screenshots\*.*" "%results_paste%\%date%%run%\XML\screenshots\"
How would I accomplish this same functionality using ANT? Here is what I have so far. I'm not sure how to check if the date folder already exists, and if it does, to create a run 2 folder.
<project default="CopyResults">
<property name="Run" value="" />
<tstamp>
<format property="Date" pattern="yyyy-mm-dd" locale="en,US,WIN" />
</tstamp>
<copy todir="C:/Results/${Date}${Run}/${Project}/${Browser}">
<fileset dir="C:/Program Files (x86)/Jenkins/jobs/${PROJECT_NAME}/workspace/test-output/html/*.*">
</copy>
<dirname property="directoryProperty" file="C:/Program Files (x86)/Jenkins/jobs/$PROJECT_NAME/workspace/test-output/${XML}/screenshots"/>
<mkdir dir="${directoryProperty}"/>
<copy todir="C:/Results/${Date}${Run}/${Project}/${XML}/screenshots/">
<fileset dir="C:/Program Files (x86)/Jenkins/jobs/${PROJECT_NAME}/workspace/test-output/${XML}/screenshots/*.*">
</copy>
here is how an example could look like:
<project default="CopyResults">
<property name="target" location="c:/temp/anttests"/>
<property name="source" location="C:/temp/source"/>
<target name="CopyResults">
<tstamp>
<!-- uppercase M is month -->
<format property="Date" pattern="yyyy-MM-dd" locale="en,US,WIN" />
</tstamp>
<!-- calculate increment number -->
<resourcecount property="Run">
<dirset dir="${target}">
<include name="${Date}*"/>
</dirset>
</resourcecount>
<copy todir="${target}/${Date}${Run}/">
<fileset dir="${source}">
<include name="**/*"/>
</fileset>
</copy>
<!-- rest goes here -->
</target>
the resourcecount task does the magic. In the dirset all directories with the date and optional number are selected. this is the value for Run
Hope this helps.

Ant: Source and target files are the same. How to detect a change?

We are using JiBX. The important thing to know is that JiBX modifies the already compiled class files.
We do our compile:
<javac destdir="${main.destdir}">
<src path="${main.srcdir}"/>
<classpath refid="main.classpath"/>
</javac>
Then, we call JiBX:
<jibx load="true"
binding="{$binding.file}">
<classpath refid="main.classpath"/>
<classpath refid="main.destdir.classpath"/>
</jibx>
This uses an XML file that updates the classfiles compiled by <javac> above. The problem is how do I know that the files have been compiled, but not processed by JiBX? I'd like to put some logic in my program, so that files are not updated twice by JiBX. Besides, it's bad form to duplicate work that already been done.
After the jibx build step, generate a marker file, e.g.
<touch file="${target.dir}/jibx.marker" />
Only perform the jibx build step if that marker file is older than the .class files (indicating that the javac ran more recently than the last jibx).
For that bit of logic, you can use the traditional ant way:
<uptodate property="jibx.uptodate" targetfile="${target.dir}/jibx.marker">
<srcfiles dir="${main.destdir}" includes="...../*.class" />
</uptodate>
And then use the property with an unless clause when invoking the jixb target.
Or, you can use Antcontrib's outofdate alternative:
<outofdate>
<sourcefiles>
<fileset dir="${main.destdir}" includes="...../*.class" />
</sourcefiles>
<targetfiles>
<fileset dir="${target.dir}" includes="jibx.marker"/>
</targetfiles>
<sequential>
<jibx load="true"
binding="{$binding.file}">
<classpath refid="main.classpath"/>
<classpath refid="main.destdir.classpath"/>
</jibx>
</sequential>
</outofdate>
I'm giving this to Patrice M. because his suggestion put me on the right track. However, it didn't quite work out as he stated. (Sorry, if I got he pronoun wrong, but Patrice can be both a male or female name.)
What I had to do was create two watch files: One for the Java compile, and one for the JiBX changes.
<!-- Check if Javac is out of date. If so, create javac watcher -->
<outofdate verbose="true">
<sourcefiles>
<fileset dir="${main.srcdir}">
<include name="*.java"/>
</fileset>
</sourcefiles>
<mapper type="regexp"
from="${main.srcdir}/(.*)\.java"
to="${main.destdir}/(\1).class"/>
<sequential>
<echo message="Java compiled"/>
<echo message="Java compiled"
file="${target.dir}/${javac.monitor.file}"/>
</sequential>
</outofdate>
<javac destdir="${main.destdir}"
debug="${javac.debug}">
<src path="${main.srcdir}"/>
<classpath refid="main.classpath"/>
</javac>
<!-- Compare javac and jibx monitoring file -->
<!-- If out of date, rerun jibx -->
<outofdate>
<sourcefiles>
<fileset dir="${target.dir}">
<include name="${javac.monitor.file}"/>
</fileset>
</sourcefiles>
<targetfiles>
<fileset dir="${target.dir}">
<include name="${jibx.monitor.file}"/>
</fileset>
</targetfiles>
<sequential>
<jibx load="true"
binding="${target.dir}/binding-gg.xml">
<classpath refid="main.classpath"/>
<classpath refid="main.destdir.classpath"/>
</jibx>
<!-- Create JiBX monitoring file -->
<echo message="Compiled and JiBX"
file="${target.dir}/${jibx.monitor.file}"/>
</sequential>
</outofdate>
I create the javac monitoring file if the source is out of date with the classes because that's when I compile. I have to create the JiBX outofdate monitoring file only when I run JiBX and that's inside the <outofdate> for JiBX.
I guess I could also put a source on the XML JiBX files too just to be sure.

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

Running an ant task only when a file has changed

In Ant, I am trying to achieve a simple task: If couple of files are modified a compiler should run. I have seen many solutions using OutOfDate, UpToDate and Modified. I dont want to use OutOfDate and UpToDate because I wont be able to use the task if the files have been modified on the same day. I can use modified but there is no way to call another task - my compiler task, from the modifier task. Is there any other solution apart from these?
Using <uptodate> with a following <antcall> to a conditional <target> will give you what you're looking for:
<project name="ant-uptodate" default="run-tests">
<tstamp>
<format property="ten.seconds.ago" offset="-10" unit="second"
pattern="MM/dd/yyyy hh:mm aa"/>
</tstamp>
<target name="uptodate-test">
<uptodate property="build.notRequired" targetfile="target-file.txt">
<srcfiles dir= "." includes="source-file.txt"/>
</uptodate>
<antcall target="do-compiler-conditionally"/>
</target>
<target name="do-compiler-conditionally" unless="build.notRequired">
<echo>Call compiler here.</echo>
</target>
<target name="source-older-than-target-test">
<touch file="source-file.txt" datetime="${ten.seconds.ago}"/>
<touch file="target-file.txt" datetime="now"/>
<antcall target="uptodate-test"/>
</target>
<target name="source-newer-than-target-test">
<touch file="target-file.txt" datetime="${ten.seconds.ago}"/>
<touch file="source-file.txt" datetime="now"/>
<antcall target="uptodate-test"/>
</target>
<target name="run-tests"
depends="source-older-than-target-test,source-newer-than-target-test"/>
</project>

How can I process only files that have changed?

At the moment I'm doing this:
<delete dir="${RSA.dir}/file1" />
<copy todir="${RSA.dir}/file1" >
<fileset dir="${CLEARCASE.dir}/file1" />
</copy>
and repeating the same thing for other files - but it takes a long time.
I only want to delete and copy files that have been updated, with their modified date in clearcase later than that in RSA.
How can I do that?
Look into the sync task.
If you want to do it based on file contents, and ignore the timestamp, I think this macro will do that:
<macrodef name="mirror" description="Copy files only if different; remove files that do not exist in dir. This works similiar to robocopy /MIR." >
<attribute name="dir"/>
<attribute name="todir"/>
<sequential>
<copy overwrite="true" todir="#{todir}">
<fileset dir="#{dir}">
<different targetdir="${todir}"/>
</fileset>
</copy>
<delete includeemptydirs="true">
<fileset dir="#todir}">
<present targetdir="${dir}" present="srconly"/>
</fileset>
</delete>
</sequential>
</macrodef>
You need to use a selector on a FileSet. Something like this:
<fileset dir="${your.working.dir}/src/main" includes="**/*.java">
<different targetdir="${clean.clearcase.checkout}/src/main"
ignoreFileTimes="false"
ignoreContents="true" />
</fileset>
That compares your working dir to a clean checkout you have elsewhere, and returns the files whose last modified times have changed. You can use the fileset as the argument for a <delete> or a <copy>.

Resources