I am testing Flyway for the first time, version 2.1.1.
I am using the Ant task migrate which should create the schema_version table if it does not already exist (and it does not exists in my schema), and I get this error:
C:\Users\dmusiani\Desktop\flyaway-test>ant
Buildfile: build.xml
migrate-db:
[flyway:migrate] com.googlecode.flyway.core.api.FlywayException: Found non-empty
schema "SYSTEM" without metadata table! Use init() first to initialize the meta
data table.
BUILD FAILED
C:\Users\dmusiani\Desktop\flyaway-test\build.xml:37: Flyway Error: com.googlecod
e.flyway.core.api.FlywayException: Found non-empty schema "SYSTEM" without metad
ata table! Use init() first to initialize the metadata table.
Total time: 0 seconds
C:\Users\dmusiani\Desktop\flyaway-test>
I tried adding the init before the migration, and the first time it all works, but as I launch the build a second time, I get an error from the init sayng the table already exists.
Here is my Ant target:
<target name="migrate-db">
<path id="flyway.lib.path">
<fileset dir="./lib">
<include name="**/flyway*.jar"/>
</fileset>
</path>
<path id="flyway.classpath">
<fileset dir="./lib" includes="ojdbc6-11.2.0.3.jar"/>
</path>
<taskdef uri="antlib:com.googlecode.flyway.ant"
resource="com/googlecode/flyway/ant/antlib.xml"
classpathref="flyway.lib.path"/>
<flyway:init driver="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#localhost:1521:WBMD"
user="system"
password="manager"
initVersion="0"
initDescription="Version table initialization (table "USERNAME"."schema_version" )"/>
<flyway:migrate driver="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:#localhost:1521:WBMD"
user="system"
password="manager"
sqlMigrationPrefix="patch" >
<locations>
<location path="integrations-runtime/HELIOS/1-9-0/nlip-0-5-0/migration/system"/>
</locations>
</flyway:migrate>
</target>
Any suggestion on how to fix it?
While waiting for 2.2, I have successfully tested (to an oracle DB) the following "automatic" way to initialize Flyway metadata table:
<target name="flyway.init.check">
<!-- Select on the DB to see if the metadata table is already in place-->
<sql driver="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#localhost:1521:WBMD"
userid="user"
password="pwd"
print="yes"
output="temp.properties"
expandProperties="true"
showheaders="false"
showtrailers="false"
classpathref="flyway.classpath">
<![CDATA[
select 'flyway.metadata.initialized=true' from user_tables where table_name = 'schema_version';
]]>
</sql>
<!-- load as properies the output from the select -->
<property file="temp.properties" />
<delete file="temp.properties" quiet="true"/>
</target>
<target name="flyway.init" depends="flyway.init.check" unless="flyway.metadata.initialized">
<flyway:init driver="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#localhost:1521:WBMD"
user="user"
password="pwd"
initVersion="0"
initDescription="Version table initialization"/>
</target>
<target name="migrate-db" depends="flyway.init">
......
</target>
Enjoy if you like it (maybe using ant-contrib you could get a simpler and more compact solution)
Davide
You have to init the db once for Flyway. That is when Flyway creates the table used to track the migrations. As you have noticed, any attempt to init again fails because the table already exists.
I suggest making a separate ant task that calls Flyway's init that you can run manually to initialize Flyway, something along the lines of:
<target name="init-flyway">
<path id="flyway.lib.path">
<fileset dir="./lib">
<include name="**/flyway*.jar"/>
</fileset>
</path>
<path id="flyway.classpath">
<fileset dir="./lib" includes="ojdbc6-11.2.0.3.jar"/>
</path>
<taskdef uri="antlib:com.googlecode.flyway.ant"
resource="com/googlecode/flyway/ant/antlib.xml"
classpathref="flyway.lib.path"/>
<flyway:init driver="oracle.jdbc.OracleDriver"
url="jdbc:oracle:thin:#localhost:1521:WBMD"
user="system"
password="manager"
initVersion="0"
initDescription="Version table initialization (table "USERNAME"."schema_version" )"/>
</target>
Related
Within ant, I have a macrodef.
Assuming I have to use this macrodef, and there is a item inside said macrodef that I want to run if the property special.property exists and is true, what do I do?
I currently have
<macrodef name="someName">
<sequential>
<someMacroDefThatSetsTheProerty />
<some:thingHereThatDependsOn if="special.property" />
<sequential>
</macrodef>
Which doesn't work - the some:thingHereThatDependsOn doesnt have an "if" attribute, and I cannot add one to it.
antcontrib is not available.
With a target I can give the target an "if", what can I do with a macrodef?
In Ant 1.9.1 and higher, there is now a new implementation of if and unless attributes. This might be what you're thinking of.
First, you need to put them into your namespace. Add them to your <project> header:
<project name="myproject" basedir="." default="package"
xmlns:if="ant:if"
xmlns:unless="ant:unless">
Now, you can add them to almost any Ant task or sub entity:
<!-- Copy over files from special directory, but only if it exists -->
<available property="special.dir.available"
file="${special.dir} type="dir"/>
<copy todir="${target.dir}>
<fileset dir="${special.dir}" if:true="special.dir.available"/>
<fileset dir="${other.dir}"/>
</copy>
<!-- FTP files over to host, but only if it's on line-->
<condition property="ftp.available">
<isreachable host="${ftp.host}"/>
</condition>
<ftp server="${ftp.host}"
userid="${userid}"
passowrd="${password}"
if:true="ftp.available">
<fileset dir=".../>
</ftp>
This is only possible if the ANT "thingHereThatDependsOn" task supports an "if" attribute.
As stated above, conditional execution in ANT, normally, only applies to targets.
<target name="doSomething" if="allowed.to.do.something">
..
..
</target>
<target name="doSomethingElse" unless="allowed.to.do.something">
..
..
</target>
<target name="go" depends="doSomething,doSomethingElse"/>
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.
I have an ant task that executes some command on a list of files.
I would like, on consecutive builds, to avoid from re-running the command on files that have passed the command with success and haven't changed.
For example: (here the command is xmllint)
<target name="xmllint-files">
<apply executable="xmllint">
<srcfile/>
<fileset dir="." includes="*.xml">
<modified/>
</fileset>
</apply>
</target>
The problem is that even the files where xmlint fails are considered as modified and therefore xmllint will not be re-run on them on consecutive builds. Obviously, this is not the desired behavior.
Two remarks:
I am looking for a general solution and not only a solution for xmllint.
I want to solve the problem totally inside ant without creating
external scripts.
This code uses the Groovy ANT task to do the following:
Implement a custom groovy selector, selecting the XML files to be processed based on a MD5 checksum check.
Invoke xmllint on each file and store it's checksum upon successful completion (This prevents re-execution of xmllint unless the file's contents are changed.
Example:
<project name="demo" default="xmllint">
<!--
======================
Groovy task dependency
======================
-->
<path id="build.path">
<pathelement location="jars/groovy-all-1.8.6.jar"/>
</path>
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>
<!--
==============================================
Select files to be processed
MD5 checksums located in "checksums" directory
==============================================
-->
<target name="select-files">
<fileset id="unprocessedfiles" dir=".">
<include name="*.xml"/>
<exclude name="build.xml"/>
<scriptselector language="groovy" classpathref="build.path">
def ant = new AntBuilder()
ant.checksum(file:filename, toDir:"checksums", verifyProperty:"isMD5ok")
self.selected = (ant.project.properties.isMD5ok == "false") ? true : false
</scriptselector>
</fileset>
</target>
<!--
=============================================================
Process each file
Checksum is saved upon command success, prevents reprocessing
=============================================================
-->
<target name="xmllint" depends="select-files">
<groovy>
project.references.unprocessedfiles.each { file ->
ant.exec(executable:"xmllint", resultproperty:"cmdExit") {
arg(value:file)
}
if (properties.cmdExit == "0") {
ant.checksum(file:file.toString(), toDir:"checksums")
}
}
</groovy>
</target>
</project>
Note:
This complex requirement cannot be implemented using the original apply ANT task. One call to xmllint command might succeed whereas another might fail.
A subdirectory called "checksums" is created to store the MD5 checksum files.
The groovy jar can be downloaded from Maven Central
Original answer
Use the ANT modified selector
<project name="demo" default="xmllint">
<target name="xmllint">
<apply executable="xmllint">
<srcfile/>
<fileset dir="." includes="*.xml">
<modified/>
</fileset>
</apply>
</target>
</project>
A property file called "cache.properties" will be created in the build directory. It records file digests, used determine if the file has been changed since the last build run.
I need to write an ant task to selectively delete files.
In a directory, I have the following jars:
acme.jar
acme-201105251330.jar
I want to delete acme.jar because acme-*.jar exists.
Here's what I've tried:
<target name="-check-use-file">
<available property="file.exists">
<filepath> <fileset dir=".">
<include name="./test-*.jar"/> </fileset>
</filepath>
</available>
</target>
<target name="use-file" depends="-check-use-file" if="file.exists">
<!-- do something requiring that file... -->
</target>
Thanks
Have a look at If/Unless Attributes, examples given there seem to be exactly what you are looking for.
How can i overwrite some existing property with a newly created properties file?
Here is the required structure:
initially load Master.properties
generate new.properties
load new.properties and master.properties
run master.xml (ANT script)
The idea is that Master.properties generates some product version which should be replaced by new.properties. However, other properties in Master.properties should be kept the same.
Reading this does not help as i do not know how can i load the new.properties file
EDIT Here is ANT Script:
<project name="nightly_build" default="main" basedir="C:\Work\NightlyBuild">
<target name="init1">
<sequential>
<property file="C:/Work/NightlyBuild/master.properties"/>
<exec executable="C:/Work/Searchlatestversion.exe">
<arg line='"/SASE Lab Tools" "${Product_Tip}/RELEASE_"'/>
</exec>
<sleep seconds="10"/>
<property file="C:/Work/new.properties"/>
</sequential>
</target>
<target name="init" depends="init1">
<sequential>
<echo message="The product version is ${Product_Version}"/>
<exec executable="C:/Work/checksnapshot.exe">
<arg line='-NightlyBuild ${Product_Version}-AppsMerge' />
</exec>
<sleep seconds="10"/>
<property file="C:/Work/checksnapshot.properties"/>
<tstamp>
<format property="suffix" pattern="yyyy-MM-dd.HHmm"/>
</tstamp>
</sequential>
</target>
<target name="main" depends="init">
<echo message="loading properties files.." />
<echo message="Backing up folder" />
<move file="C:\NightlyBuild\NightlyBuild" tofile="C:\NightlyBuild\NightlyBuild.${suffix}" failonerror="false" />
<exec executable="C:/Work/sortfolder.exe">
<arg line="6" />
</exec>
<exec executable="C:/Work/NightlyBuild/antc.bat">
</exec>
</target>
</project>
in the above script, <exec executable="C:/Work/NightlyBuild/antc.bat"> will run Master.xml ANT script. This Master.xml will load up Master.properties:
<project name="Master ANT Build" default="main" >
<taskdef name="CFileEdit" classname="com.ANT_Tasks.CFileEdit"/>
<!-- ========================================================== -->
<!-- init: sets global properties -->
<!-- ========================================================== -->
<target name="init">
<property environment="env"/>
<!-- ========================================================== -->
<!-- Set the timestamp format -->
<!-- ========================================================== -->
<property file="Master.properties"/>
...
</project>
You should be able to resolve this by looking at the order in which you load (or otherwise specify) your property values. You probably don't need to override property values at all, which something not supported by core Ant.
Maybe you can split your Master.properties into two files - one loaded before you generate new.properties and one loaded after?
Maybe you don't need to generate new.properties at all.
Could you give some more detail on what you need to do?
Since you eventually fork a new Ant process (exec antc.bat), does that not start a fresh environment anyway? If it just loads Master.properties, those are the only properties it will have.
Not sure what your antc.bat does, but it's pretty unusual to exec Ant from Ant in this way. There are two standard tasks which might be useful - Ant and AntCall.
OK running on from your later comments...
Let's say that instead of doing this:
<exec executable="antc.bat">
you instead did something like this:
<ant file="Master.xml" inheritall="false">
<property name="Product_Version" value="${Product_Version}"/>
</ant>
I think that is getting towards what you want. You selectively pass specific values that you have obtained by loading new.properties. See the documentation for the Ant task.
If you still have the problem that you already defined Product_Version before loading new.properties, then I would say get the script you have that produces new.properties to output the version with a different name, e.g. New_Product_Version. Then invoke your master build something like this:
<ant file="Master.xml" inheritall="false">
<property name="Product_Version" value="${New_Product_Version}"/>
</ant>
May be this is a old question. Hopefully OP is reading this.
You can just use the ant task "propertyfile". reference
it can read properties from the file and write back updated values to them.