ilscipio/scipio-erp

View on GitHub
common.xml

Summary

Maintainability
Test Coverage
<?xml version="1.0" encoding="UTF-8"?>
<!--
This file is subject to the terms and conditions defined in the
files 'LICENSE' and 'NOTICE', which are part of this source
code package.
-->
<project name="Ant - Common" xmlns:ivy="antlib:org.apache.ivy.ant"
    xmlns:if="ant:if"
    xmlns:unless="ant:unless">
    <dirname property="Ant - Common.dir" file="${ant.file.Ant - Common}" />
    <!-- SCIPIO: NOTE: macros.xml sets ofbiz.home.dir (if not already inherited) -->
    <import file="${Ant - Common.dir}/macros.xml" />

    <property environment="env" />
    <property name="src.dir" value="src" />
    <property name="dtd.dir" value="dtd" />
    <property name="lib.dir" value="lib" />
    <property name="build.dir" value="build" />

    <path id="test.class.path">
        <path refid="local.class.path" />
        <pathelement location="config" />
    </path>
    <filelist id="test.classes" />

    <!-- ================================================================== -->
    <!-- Removes all created files and directories                          -->
    <!-- ================================================================== -->

    <target name="clean">
        <delete dir="${build.dir}" />
    </target>

    <!-- ================================================================== -->
    <!-- Makes sure the needed directory structure is in place              -->
    <!-- ================================================================== -->

    <target name="prepare" depends="init">
        <mkdir dir="${build.dir}/classes" />
        <mkdir dir="${build.dir}/lib" />
    </target>

    <target name="prepare-docs" depends="init">
        <mkdir dir="${build.dir}/javadocs" />
    </target>

    <target name="init" />

    <if>
        <available file="${src.dir}" />
        <then>
            <selector id="src-extra-set">
                <or>
                    <filename name="**/*.properties" />
                    <filename name="**/*.groovy" />
                    <filename name="**/*.xml" />
                    <filename name="**/*.bsh" />
                    <filename name="**/*.logic" />
                    <filename name="**/*.js" />
                    <filename name="**/*.jacl" />
                    <filename name="**/*.py" />
                    <filename name="META-INF/**" />
                </or>
            </selector>
            <property name="src.extra.dir" value="${src.dir}" />
        </then>
        <else>
            <selector id="src-extra-set">
                <filename name="**" negate="true" />
            </selector>
            <property name="src.extra.dir" value="." />
        </else>
    </if>
    
    <!-- ================================================================== -->
    <!-- Compilation of the source files                                    -->
    <!-- ================================================================== -->

    <target name="classes" depends="prepare,check-lib-update">
        <!-- SCIPIO: per-comonent lib update hook -->
        <javac-std />
    </target>

    <target name="jar" depends="classes">
        <main-jar />
    </target>

    <!-- ================================================================== -->
    <!-- Build JavaDoc                                                      -->
    <!-- ================================================================== -->

    <target name="docs" depends="prepare-docs">
        <default-javadoc />
    </target>

    <macrodef name="run-junit">
        <attribute name="build.jar" default="${build.dir}/lib/${name}.jar" />
        <attribute name="build-test.jar" default="${build.dir}/lib/${name}-test.jar" />
        <sequential>
            <mkdir dir="${build.dir}/test-results" />
            <junit fork="on" haltonfailure="on" forkmode="once" showoutput="on" printsummary="off">
                <classpath>
                    <path refid="junit.class.path" />
                    <path refid="test.class.path" />
                    <pathelement location="@{build.jar}" />
                    <pathelement location="@{build-test.jar}" />
                </classpath>
                <sysproperty key="net.sourceforge.cobertura.datafile" file="${build.dir}/test-results/cobertura.dat" />
                <sysproperty key="ofbiz.home" value="${ofbiz.home.dir}" />
                <formatter usefile="false" type="plain" />
                <batchtest>
                    <filelist refid="test.classes" />
                </batchtest>
            </junit>
        </sequential>
    </macrodef>

    <target name="tests" depends="jar">
        <run-junit />
    </target>

    <patternset id="cobertura-src-dirs">
        <include name="src" />
    </patternset>

    <target name="tests-cobertura" depends="jar">
        <mkdir dir="${build.dir}/cobertura-lib" />
        <taskdef resource="tasks.properties" classpathref="cobertura.class.path" />
        <delete file="${build.dir}/test-results/cobertura.dat" />
        <cobertura-instrument datafile="${build.dir}/test-results/cobertura.dat" todir="${build.dir}/cobertura-lib">
            <fileset dir="${build.dir}/lib">
                <include name="*.jar" />
            </fileset>
        </cobertura-instrument>
        <run-junit build.jar="${build.dir}/cobertura-lib/${name}.jar" build-test.jar="${build.dir}/cobertura-lib/${name}-test.jar" />
        <delete dir="${build.dir}/test-results/cobertura-report" />
        <mkdir dir="${build.dir}/test-results/cobertura-report" />
        <cobertura-report datafile="${build.dir}/test-results/cobertura.dat" destdir="${build.dir}/test-results/cobertura-report">
            <dirset dir=".">
                <patternset refid="cobertura-src-dirs" />
            </dirset>

            <include name="**/*.java" />
        </cobertura-report>
    </target>

    <target name="tests-jacoco" depends="jar" xmlns:jacoco="antlib:org.jacoco.ant">
        <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
            <classpath>
                <path refid="jacoco.class.path" />
            </classpath>
        </taskdef>
        <sequential>
            <delete dir="${build.dir}/jacoco-result" />
            <mkdir dir="${build.dir}/jacoco-result" />
            <jacoco:coverage destfile="${build.dir}/jacoco-result/${name}.exec">    
                <junit printsummary="true" haltonfailure="false" fork="yes" forkmode="once">
                    <classpath>
                        <path refid="junit.class.path" />
                        <path refid="test.class.path" />
                        <pathelement location="@{build.jar}" />
                        <pathelement location="@{build-test.jar}" />
                    </classpath>
                    <sysproperty key="ofbiz.home" value="${ofbiz.home.dir}" />
                    <formatter type="xml" />
                    <batchtest>
                        <filelist refid="test.classes" />
                    </batchtest>
                </junit>
            </jacoco:coverage>
        </sequential>
    </target>

    <target name="all" depends="jar,docs" />

    <!-- ================================================================== -->
    <!-- Apply patches if exist                                             -->
    <!-- ================================================================== -->
    <!--
        This macro applies all patches found in ./patches/@{deployment} relative to ${ofbiz.home.dir}
        and stops the build process if patches fail (to save time deleting all the rejects)
        We use patch command here instead of svn patch because it's supposed to run in a server where patch is intalled in path
    -->
    <macrodef name="apply-patches">
        <attribute name="deployment" default="dev" />
        <sequential>
            <!-- patch task can't handle a fileset => create a global patch -->
            <if>
                <available file="patches" />
                <then>
                    <concat destfile="patches/@{deployment}.patch" encoding="UTF-8" outputencoding="UTF-8">
                        <!-- exclude the patch itself in case it's still there -->
                        <fileset dir="patches" includes="@{deployment}/*.patch" />
                    </concat>
                    <patch strip="0" patchfile="patches/@{deployment}.patch" dir="${ofbiz.home.dir}" failonerror="true" />
                    <delete>
                        <fileset dir="patches" includes="@{deployment}.patch" />
                    </delete>
                </then>
            </if>
        </sequential>
    </macrodef>

    <target name="prepare-to-build-dev" description="Does everything needed to get you a ready to start building OFBiz for development. This include generic patches for OFBiz itself, not only hot-deploy components">
        <apply-patches deployment="dev" />
    </target>

    <target name="prepare-to-build-test" description="Does everything needed to get you a ready to start building OFBiz for integration testing">
        <apply-patches deployment="test" />
    </target>

    <target name="prepare-to-build-qa" description="Does everything needed to get you a ready to start building OFBiz in QA-Environment">
        <apply-patches deployment="qa" />

        <!-- need to use flatten here as qa dir might not exist and thus can't be included in "dir" -->
        <copy toDir="config/" overwrite="true" flatten="true">
            <fileset dir="patches" includes="qa/*.properties" />
        </copy>
    </target>

    <target name="prepare-to-build-production" description="Does everything needed to get you a ready to start building OFBiz in production">
        <apply-patches deployment="production" />

        <!-- need to use flatten here as production dir might not exist and thus can't be included in "dir" -->
        <copy toDir="config/" overwrite="true" flatten="true">
            <fileset dir="patches" includes="production/*.properties" />
        </copy>
        <!-- Some files might need to be deleted in production, notably some specific script files -->
        <!--exec executable="svn" dir="${ofbiz.home.dir}">
            <arg value="delete"/>
            <arg value="filename.sh"/>
        </exec-->
    </target>

    <!-- ================================================================== -->
    <!-- SCIPIO: Common component build new, original properties and tasks  -->
    <!-- ================================================================== -->

    <property name="framework.dir" value="framework" />
    <property name="applications.dir" value="applications" />
    <property name="specialpurpose.dir" value="specialpurpose" />
    <property name="addons.dir" value="addons" />
    <property name="hotdeploy.dir" value="hot-deploy" />

    <!-- Dynamic common.xml additions -->
    <fileset id="framework.commoncomponentbuilds" dir="${ofbiz.home.dir}/${framework.dir}">
        <exclude name="disabled/**" />
        <include name="*/build-component-common.xml" />
    </fileset>
    <fileset id="applications.commoncomponentbuilds" dir="${ofbiz.home.dir}/${applications.dir}">
        <exclude name="disabled/**" />
        <include name="*/build-component-common.xml" />
    </fileset>
    <fileset id="specialpurpose.commoncomponentbuilds" dir="${ofbiz.home.dir}/${specialpurpose.dir}">
        <exclude name="disabled/**" />
        <include name="*/build-component-common.xml" />
    </fileset>
    <fileset id="addons.commoncomponentbuilds" dir="${ofbiz.home.dir}/${addons.dir}">
        <exclude name="disabled/**" />
        <include name="*/build-component-common.xml" />
    </fileset>
    <fileset id="hotdeploy.commoncomponentbuilds" dir="${ofbiz.home.dir}/${hotdeploy.dir}">
        <exclude name="disabled/**" />
        <include name="*/build-component-common.xml" />
    </fileset>
    <import optional="true">
        <fileset file="${ofbiz.home.dir}/tools/misc/build-dummy.xml" />
        <!-- at least one import required -->
        <fileset refid="framework.commoncomponentbuilds" />
    </import>
    <import optional="true">
        <fileset file="${ofbiz.home.dir}/tools/misc/build-dummy.xml" />
        <!-- at least one import required -->
        <fileset refid="applications.commoncomponentbuilds" />
    </import>
    <import optional="true">
        <fileset file="${ofbiz.home.dir}/tools/misc/build-dummy.xml" />
        <!-- at least one import required -->
        <fileset refid="specialpurpose.commoncomponentbuilds" />
    </import>
    <import optional="true">
        <fileset file="${ofbiz.home.dir}/tools/misc/build-dummy.xml" />
        <!-- at least one import required -->
        <fileset refid="addons.commoncomponentbuilds" />
    </import>
    <import optional="true">
        <fileset file="${ofbiz.home.dir}/tools/misc/build-dummy.xml" />
        <!-- at least one import required -->
        <fileset refid="hotdeploy.commoncomponentbuilds" />
    </import>

    <target name="get-component-build-deps" description="Reads this component's build dependencies from component.build.dependencies filelist (if any) and prepares for automatic dependency resolution (SCIPIO)">
        <read-component-build-deps />
    </target>

    <property name="lib.update.filename.pattern.ivy" value="[artifact]-[revision].[ext]" />
    <property name="lib.update.filename.pattern.src.ivy" value="[artifact]-[revision]-sources.[ext]" />
    
    <target name="check-lib-update" description="Initial libraries and dependencies download, per-component, if enabled only">
        <if>
            <not>
                <equals arg1="${lib.update.hook.mode}" arg2="component"/>
            </not>
            <then>
                <echo level="verbose" message="Skipping component lib updates (not using per-component mode)"/>
            </then>
            <elseif>
                <equals arg1="${lib.update.bypass}" arg2="true"/>
                <then>
                    <echo level="verbose" message="Skipping lib updates (bypassed)"/>
                </then>
            </elseif>
            <elseif>
                <equals arg1="${lib.update.force}" arg2="true"/>
                <then>
                    <echo level="verbose" message="Lib updates check forced - starting..."/>
                    <antcall target="lib-update"/>
                </then>
            </elseif>
            <else>
                <echo level="verbose" message="Lib updates check starting..."/>
                <antcall target="lib-update"/>
            </else>
        </if>
    </target>
    <target name="check-init-lib-update" depends="check-lib-update" description="[deprecated] alias for check-lib-update">
    </target>
    
    <!-- NOTE: IMPORTANT: All antcall to reusable targets that might invoke ivy: functions must specify inheritRefs="true" -->
    <target name="lib-update" description="Downloads initial jars, if applicable for component">
        <if>
            <and>
                <available file="ivy.xml" type="file"/>
                <available file="lib" type="dir"/>
            </and>
            <then>
                <antcall target="lib-update-core" inheritrefs="true"/>
            </then>
            <elseif>
                <!-- 2018-03-20: migration cleanup: the ivy.xml files were removed for
                    many components, so we must clean them out - TODO: remove this in a few months -->
                <and>
                    <matches pattern="/(framework|applications|specialpurpose)/[^/]+/build.xml$" string="${ant.file}"/>
                    <not><available file="ivy.xml" type="file"/></not>
                    <available file="lib" type="dir"/>
                    <resourcecount when="greater" count="0">
                        <fileset file="lib/*.jar"/>
                    </resourcecount>
                </and>
                <then>
                    <if>
                        <and>
                            <not><equals arg1="${lib.clean}" arg2="false"/></not>
                            <not><equals arg1="${lib.clean.deployed}" arg2="false"/></not>
                        </and>
                        <then>
                            <dirname property="lib.component.current.dir" file="${ant.file}"/>
                            <basename property="lib.component.current.dirname" file="${lib.component.current.dir}"/>
                            <echo level="info" message="Lib cleanout needed for ${lib.component.current.dirname} (ivy base lib migration)"/>
                            <antcall target="do-lib-clean" inheritrefs="true"/>
                        </then>
                    </if>
                </then>
            </elseif>
        </if>
    </target>

    <target name="lib-update-core" depends="ivy-init,get-lib-resolve-confs,do-lib-resolve">
        <!-- get info about the last retrieve attempt -->
        <property file="${ofbiz.home.dir}/ivy/ivy-last.txt" prefix="lib.update.retrieve.last"/>
        
        <!-- SPECIAL: check if the last (unfinished) clean/retrieve attempt was ours. if so, must force redeploy. -->
        <condition property="last.update.retrieve.waslast" value="true" else="false">
            <and>
                <equals arg1="${ivy.organisation}" arg2="${lib.update.retrieve.last.organisation}"/>
                <equals arg1="${ivy.module}" arg2="${lib.update.retrieve.last.module}"/>
            </and>
        </condition>
        <echo level="info" message="[Deps changed? ${lib.resolve.changed}. Was last retrieve attempt? ${last.update.retrieve.waslast}.]"/>

        <var name="lib.update.changed" unset="true"/>
        <if>
            <or>
                <equals arg1="${lib.update.force}" arg2="true"/>
                <equals arg1="${lib.update.force.deploy}" arg2="true"/>
                <equals arg1="${lib.resolve.changed}" arg2="true"/>
                <equals arg1="${last.update.retrieve.waslast}" arg2="true"/><!-- force redeploy if last deploy didn't finish -->
            </or>
            <then>
                <!-- flag this module as the last clean/retrieve attempt -->
                <echo message="status=RUNNING${line.separator}organisation=${ivy.organisation}${line.separator}module=${ivy.module}${line.separator}" file="${ofbiz.home.dir}/ivy/ivy-last.txt"/>

                <dirname property="lib.component.current.dir" file="${ant.file}"/>
                <basename property="lib.component.current.dirname" file="${lib.component.current.dir}"/>
                <echo level="info" message="Lib deploy needed for ${lib.component.current.dirname} component: deploying files to lib folder..."/>
                <if>
                    <and>
                        <not><equals arg1="${lib.clean}" arg2="false"/></not>
                        <not><equals arg1="${lib.clean.deployed}" arg2="false"/></not>
                    </and>
                    <then>
                        <antcall target="do-lib-clean" inheritrefs="true"/>
                    </then>
                </if>
                <property name="lib.update.needed" value="true"/>
                <antcall target="do-lib-update" inheritrefs="true"/>
                <antcall target="do-lib-update-always" inheritrefs="true"/>

                <!-- if we're here, then we succeeded; clear the last flag -->
                <delete file="${ofbiz.home.dir}/ivy/ivy-last.txt"/>
            </then>
            <else>
                <antcall target="do-lib-update-always" inheritrefs="true"/>
            </else>
        </if>
    </target>
    
    <target name="get-lib-resolve-confs">
        <!-- if an explicit lib.resolve.build.confs is set but no lib.resolve.confs, set it to it; 
            otherwise use "*" for backward compat -->
        <if>
            <and>
                <not><isset property="lib.resolve.confs"/></not>
                <isset property="lib.resolve.build.confs"/>
            </and>
            <then>
                <!-- lib.resolve.build.confs: add the support -jdk8/-jdk11 switches for all confs supporting them (automated) -->
                <get-ivy-versioned-confs conf="${lib.resolve.build.confs}" ivyfile="${basedir}/ivy.xml" outputproperty="lib.resolve.build.confs"/>
                <echo message="lib.resolve.build.confs versioned: ${lib.resolve.build.confs}"/>

                <property name="lib.resolve.confs" value="${lib.resolve.build.confs}"/>
            </then>
            <else>
                <if>
                    <and>
                        <isset property="lib.resolve.confs"/>
                        <not><equals arg1="${lib.resolve.confs}" arg2="*"/></not>
                    </and>
                    <then>
                        <!-- lib.resolve.confs: add the support -jdk8/-jdk11 switches for all confs supporting them (automated) -->
                        <get-ivy-versioned-confs conf="${lib.resolve.confs}" ivyfile="${basedir}/ivy.xml" outputproperty="lib.resolve.confs"/>
                        <echo message="lib.resolve.confs versioned: ${lib.resolve.confs}"/>
                    </then>
                    <else>
                        <property name="lib.resolve.confs" value="*"/>
                    </else>
                </if>
            </else>
        </if>
        
        <!-- default build conf is called "application", named for legacy reasons; however,
            it's now recommended to use the name "build" instead (2018-03) -->
        <property name="lib.resolve.build.confs" value="application"/>
        
        <!-- if lib.resolve.src.confs is not set, assume based on existence of libsrc folder -->
        <if>
            <and>
                <not><isset property="lib.resolve.src.confs"/></not>
                <available file="libsrc" type="dir"/>
            </and>
            <then>
                <property name="lib.resolve.src.confs" value="sources"/>
            </then>
        </if>

        <if>
            <and>
                <equals arg1="${lib.update.sources}" arg2="true"/>
                <isset property="lib.resolve.src.confs"/>
                <not><equals arg1="${lib.resolve.src.confs}" arg2="none"/></not>
            </and>
            <then>
                <!-- lib.resolve.src.confs: add the support -jdk8/-jdk11 switches for all confs supporting them (automated) -->
                <get-ivy-versioned-confs conf="${lib.resolve.src.confs}" ivyfile="${basedir}/ivy.xml" outputproperty="lib.resolve.src.confs"/>
                <echo message="lib.resolve.src.confs versioned: ${lib.resolve.src.confs}"/>
            </then>
        </if>

        <!-- determine effective confs to use in this call (either include sources or don't) -->
        <if>
            <and>
                <equals arg1="${lib.update.sources}" arg2="true"/>
                <isset property="lib.resolve.src.confs"/>
                <not><equals arg1="${lib.resolve.src.confs}" arg2="none"/></not>
                <not><equals arg1="${lib.resolve.confs}" arg2="*"/></not>
            </and>
            <then>
                <property name="lib.resolve.confs.eff" value="${lib.resolve.confs},${lib.resolve.src.confs}"/>
            </then>
            <else>
                <property name="lib.resolve.confs.eff" value="${lib.resolve.confs}"/>
            </else>
        </if>
        
        <!-- NOTE: here we manually do the ivy:resolve call so we can detect if anything was
            changed, separate from the ivy:retrieve call, because if nothing changed we want
            to skip our manual clean as well as the retrieve -->
        <!--
        <echo level="verbose" message="lib.update.force: ${lib.update.force}"/>
        <echo level="verbose" message="lib.update.cache: ${lib.update.cache}"/>
        -->
        <condition property="lib.update.ivy.refresh" value="true" else="false">
            <or>
                <!-- by themselves, both 
                      -Dlib.update.force=true and 
                      -Dlib.update.cache=false
                    will force ivy to refresh, but is also possible to pass
                      -Dlib.update.force=true -Dlib.update.cache=true
                    which will force replacing the filesystem libs without forcing ivy refresh -->
                <and>
                    <equals arg1="${lib.update.force}" arg2="true"/>
                    <not><equals arg1="${lib.update.cache}" arg2="true"/></not>
                </and>
                <equals arg1="${lib.update.cache}" arg2="false"/>
            </or>
        </condition>
    </target>
    
    <!-- WARN: this can ONLY be called using depends="do-lib-resolve"! antcall will wreck it! -->
    <target name="do-lib-resolve" depends="get-lib-resolve-confs" description="Resolves lib dependencies">
        <echo message="lib.resolve.confs.eff: ${lib.resolve.confs.eff}"/>
        <ivy:resolve refresh="${lib.update.ivy.refresh}" conf="${lib.resolve.confs.eff}"/>
        <property name="lib.resolve.changed" value="${ivy.deps.changed}"/>
    </target>
    
    <!-- NOTE: xxx-lib-update targets must with called with: antcall inheritrefs="true" or depends="" -->
    <target name="do-lib-update" description="Deploys all jars">
        <ivy:retrieve pattern="lib/${lib.update.filename.pattern.ivy}" conf="${lib.resolve.build.confs}"/>
        <if>
            <and>
                <equals arg1="${lib.update.sources}" arg2="true"/>
                <isset property="lib.resolve.src.confs"/>
                <not><equals arg1="${lib.resolve.src.confs}" arg2="none"/></not>
            </and>
            <then>
                <ivy:retrieve pattern="libsrc/${lib.update.filename.pattern.src.ivy}" conf="${lib.resolve.src.confs}"/>
            </then>
        </if>
    </target>
    <target name="do-lib-update-always" description="Lib update callback run even if there was no need to update libs">
    </target>
    <target name="common-lib-update" description="Deploys all jars (default/common implementation)">
        <ivy:retrieve pattern="lib/${lib.update.filename.pattern.ivy}" conf="${lib.resolve.build.confs}"/>
        <if>
            <and>
                <equals arg1="${lib.update.sources}" arg2="true"/>
                <isset property="lib.resolve.src.confs"/>
                <not><equals arg1="${lib.resolve.src.confs}" arg2="none"/></not>
            </and>
            <then>
                <ivy:retrieve pattern="libsrc/${lib.update.filename.pattern.src.ivy}" conf="${lib.resolve.src.confs}"/>
            </then>
        </if>
    </target>
    <target name="root-lib-update" description="Deploys root lib folder jars">
        <ivy:retrieve pattern="lib/${lib.update.filename.pattern.ivy}" conf="${lib.resolve.build.confs}"/>
    </target>

    <!-- SCIPIO: 2018-08-27: For lib-update (or any non "explicit clean" target), always trigger clean sources
        if lib.update.sources is set; otherwise, the libsrc folder accumulates past jars.
        In previous change, this was set to "true" always, but it adds a small IO penalty to clients who don't need the sources,
        which is minor but not desirable for daily builds; so, only explicit cleans will get this overhead (see below).
        NOTE: It's highly recommended for devs to set [build.]lib.update.sources=true in build[.local].properties instead of command line,
            especially because of this conditional, to help keep lib and libsrc jars in sync. -->
    <property name="lib.clean.sources" value="${lib.update.sources}" if:set="lib.update.sources"/>

    <target name="lib-clean" description="Cleans downloadable jars, if applicable for component">
        <!-- SCIPIO: 2018-08-27: For explicit clean calls, always clean the libsrc jar sources out whenever cleaning out the binary jars.
            It makes little sense to keep the sources if the binaries are being deleted, and this ensures
            predictable behavior. There is only small IO overhead for clients not using sources, but performance not important to clean
            as it is for build/update targets. -->
        <property name="lib.clean.sources" value="true"/>
        <if>
            <and>
                <available file="ivy.xml" type="file"/>
                <available file="lib" type="dir"/>
            </and>
            <then>
                <if>
                    <not><equals arg1="${lib.clean.deployed}" arg2="false"/></not>
                    <then>
                        <antcall target="do-lib-clean" inheritrefs="true"/>
                    </then>
                </if>
            </then>
            <elseif>
                <!-- 2018-03-20: migration cleanup: the ivy.xml files were removed for
                    many components, so we must clean them out - TODO: remove this in a few months -->
                <and>
                    <matches pattern="/(framework|applications|specialpurpose)/[^/]+/build.xml$" string="${ant.file}"/>
                    <not><available file="ivy.xml" type="file"/></not>
                    <available file="lib" type="dir"/>
                    <resourcecount when="greater" count="0">
                        <fileset file="lib/*.jar"/>
                    </resourcecount>
                </and>
                <then>
                    <if>
                        <and>
                            <not><equals arg1="${lib.clean.deployed}" arg2="false"/></not>
                        </and>
                        <then>
                            <dirname property="lib.component.current.dir" file="${ant.file}"/>
                            <basename property="lib.component.current.dirname" file="${lib.component.current.dir}"/>
                            <echo level="info" message="Lib cleanout needed for ${lib.component.current.dirname} (ivy base lib migration)"/>
                            <antcall target="do-lib-clean" inheritrefs="true"/>
                        </then>
                    </if>
                </then>
            </elseif>
        </if>
    </target>
    <target name="do-lib-clean" description="Cleans out (removes) all ivy-handled jars">
        <antcall target="common-lib-clean" inheritrefs="true"/>
    </target>
    <target name="common-lib-clean" description="Cleans out (removes) all ivy-handled jars">
        <!-- NOTE: remove-lib-files is used as we cannot use sync="true" on <ivy:retrieve/>,
            because it does not support file exceptions from deletion (lib.update.manual.files) -->
        <remove-lib-files dir="lib" excludes-refid="lib.update.manual.files"/>
        <if>
            <and>
                <equals arg1="${lib.clean.sources}" arg2="true"/>
                <available file="libsrc" type="dir"/>
            </and>
            <then>
                <remove-lib-files dir="libsrc" excludes-refid="lib.update.manual.src.files"/>
            </then>
        </if>
    </target>
    
    <target name="lib-dep-tree" description="Shows library dependency tree">
        <if>
            <available file="ivy.xml" type="file"/>
            <then>
                <antcall target="lib-dep-tree-core" inheritrefs="true"/>
            </then>
        </if>
    </target>
    <target name="lib-dep-tree-core" depends="ivy-init,get-lib-resolve-confs">
        <trycatch><!-- 2018-05-10: needed because ivy 2.4 gives NullPointerException for empty ivy.xml files -->
            <try>
                <ivy:dependencytree conf="${lib.resolve.confs}"/>
            </try>
            <catch>
                <echo level="warning" 
                    message="ERROR: Ivy threw exception while generating dependency tree - known bug in Ivy 2.4 when ivy.xml empty"/>
            </catch>
        </trycatch>
    </target>
    
    <target name="lib-dep-report" description="Generate library dependency HTML report">
        <if>
            <available file="ivy.xml" type="file"/>
            <then>
                <antcall target="lib-dep-report-core" inheritrefs="true"/>
            </then>
        </if>
    </target>
    <target name="lib-dep-report-core" depends="ivy-init,do-lib-resolve">
        <basename file="./" property="component.dir"/>
        <ivy:report conf="${lib.resolve.confs}" todir="${ofbiz.home.dir}/runtime/analysis/lib-dep-report/${component.dir}"/>
    </target>
    
    <target name="lib-dep-checkupdates" description="Check for library dependency updates">
        <if>
            <available file="ivy.xml" type="file"/>
            <then>
                <antcall target="lib-dep-checkupdates-core" inheritrefs="true"/>
            </then>
        </if>
    </target>
    <target name="lib-dep-checkupdates-core" depends="ivy-init,get-lib-resolve-confs">
        <property name="lib.dep.checkupdates.transitive" value="false"/>
        <ivy:checkdepsupdate conf="${lib.resolve.confs}" showTransitive="${lib.dep.checkupdates.transitive}"/>
    </target>

</project>