0

Does anyone know of an Ant task that would compare two (Java) properties files? I could not find any but I would like to be sure before I go off and implement it.

  • Input: two properties files
  • Output: list of property keys that are in one file but not in the other.

Just to be clear: it should perform properties-file-syntax-aware comparison, comparing the existence of keys, but ignoring the values.

Neeme Praks
  • 8,150
  • 5
  • 40
  • 46
  • Similar to this: http://stackoverflow.com/questions/6282542/ant-how-to-compare-contents-of-two-files – Mark O'Connor Jan 17 '13 at 19:49
  • Not really, I'm interested in content-aware comparison. Meaning that it should compare the existence of keys, but ignore the values. Updated the question also. – Neeme Praks Jan 18 '13 at 09:34

3 Answers3

2

The best option is to use PropDiff utility. It has options to compare, combine and intersect Java Properties files. It's open source, so you can modify it according to your requirements.

Here is the documentation for PropDiff.

Asif Arshad
  • 191
  • 10
1

You could try to combine a groovy ant task with the java-diff-utils library

Example

├── build.xml
├── file1.properties
└── file2.properties

Running the build produces the following output:

diff:
   [groovy] [DeleteDelta, position: 1, lines: [two=2]]
   [groovy] [InsertDelta, position: 3, lines: [threeandhalf=3.5]]
   [groovy] [ChangeDelta, position: 4, lines: [five=5] to [five=55555]]

build.xml

<project name="demo" default="diff" xmlns:ivy="antlib:org.apache.ivy.ant">

    <target name="resolve">
        <ivy:cachepath pathid="build.path">
            <dependency org="org.codehaus.groovy" name="groovy-all" rev="2.1.0-rc-1" conf="default"/>
            <dependency org="com.googlecode.java-diff-utils" name="diffutils" rev="1.2.1" conf="default"/>
        </ivy:cachepath>
    </target>

    <target name="diff" depends="resolve">
        <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>

        <groovy>
            import difflib.*

            def original = new File("file1.properties").readLines()
            def revised  = new File("file2.properties").readLines()

            Patch patch = DiffUtils.diff(original, revised)

            patch.getDeltas().each {
                println it
            }
        </groovy>
    </target>

</project>

Notes:

file1.properties

one=1
two=2
three=3
four=4
five=5

file2.properties

one=1
three=3
threeandhalf=3.5
four=4
five=55555

Revised Example

Returns the properties in the first file missing in the second:

diff:
   [groovy] Missing keys: [two]

build.xml

<project name="demo" default="diff" xmlns:ivy="antlib:org.apache.ivy.ant">

    <target name="resolve">
        <ivy:cachepath pathid="build.path">
            <dependency org="org.codehaus.groovy" name="groovy-all" rev="2.1.0-rc-1" conf="default"/>
        </ivy:cachepath>
    </target>

    <target name="diff" depends="resolve">
        <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="build.path"/>

        <groovy>
            def source = new Properties()
            def target = new Properties()

            new File("file1.properties").withInputStream { source.load(it) }
            new File("file2.properties").withInputStream { target.load(it) }

            def diff = source.findResults { k,v ->
                k in target ? null : k
            }

            println "Missing keys: ${diff}"
        </groovy>
    </target>

</project>
Mark O'Connor
  • 72,448
  • 10
  • 129
  • 174
  • Thank you for your thorough answer. While it is good for just comparing text files, it is not the answer I was looking for. I'm interested in content-aware comparison. Meaning that it should compare the existence of keys, but ignore the values. I updated the question also. Sorry for the confusion. – Neeme Praks Jan 18 '13 at 12:09
  • @NeemePraks I've created a second example to find the missing keys. – Mark O'Connor Jan 18 '13 at 21:01
  • Thanks, that seems to work. Although I would prefer a full-blown Ant task, this will suffice for now. – Neeme Praks Jan 23 '13 at 11:07
  • @NeemePraks Nothing stopping you from writing your own custom task. Personally I find it simpler to embed Groovy scripts. It's immediate, simpler to change and groovy integrates very well with ANT. – Mark O'Connor Jan 23 '13 at 13:04
1

Here is another approach that only requires the ant-contrib library:

<target name="checkPropertyFiles">
    <antcall target="ensureTwoFilesHaveSameProperties">
        <param name="file1" value="file1.properties"/>
        <param name="file2" value="file2.properties"/>
    </antcall>
</target>

<target name="ensureTwoFilesHaveSameProperties">
    <loadproperties srcFile="${file1}" prefix="prefixfile1"/>
    <loadproperties srcFile="${file2}" prefix="prefixfile2"/>

    <propertyselector property="file1.list" delimiter="," match="prefixfile1\.(.+)" select="\1"/>
    <propertyselector property="file2.list" delimiter="," match="prefixfile2\.(.+)" select="\1"/>

    <for list="${file1.list}" param="file1.property">
        <sequential>
            <if>
                <not>
                    <matches pattern=",@{file1.property}," string=",${file2.list}," />
                </not>
                <then>
                    <property name="error.encountered" value="true"/>
                    <echo message="Property @{file1.property} is present in ${file1} but not in ${file2}"/>
                </then>
            </if>
        </sequential>
    </for>
    <for list="${file2.list}" param="file2.property">
        <sequential>
            <if>
                <not>
                    <matches pattern=",@{file2.property}," string=",${file1.list}," />
                </not>
                <then>
                    <property name="error.encountered" value="true"/>
                    <echo message="Property @{file2.property} is present in ${file2} but not in ${file1}"/>
                </then>
            </if>
        </sequential>
    </for>

    <fail message="Property files do not have the same set of keys.">
        <condition>
            <isset property="error.encountered"/>
        </condition>
    </fail>

    <echo message="OK: ${file1} has same properties as ${file2}"/>
</target>
Joost
  • 563
  • 1
  • 3
  • 9