<!--
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
-->

<project name="lz4" default="dist" basedir="."
    xmlns:cpptasks="antlib:net.sf.antcontrib.cpptasks"
    xmlns:ivy="antlib:org.apache.ivy.ant"
    xmlns:junit4="antlib:com.carrotsearch.junit4"
    xmlns:mvn="antlib:org.apache.maven.artifact.ant">

  <property name="src" location="src"/>
  <property name="build" location="build"/>
  <property name="dist"  location="dist"/>
  <property name="lib" location="lib" />

  <property name="javac.source" value="1.7" />
  <property name="javac.target" value="1.7" />

  <property name="ivy.jar.version" value="2.5.0"/>
  <property name="ivy.jar.name" value="ivy-${ivy.jar.version}.jar"/>
  <condition property="ivy.xml.name" value="ivy-pure-java.xml" else="ivy.xml">
    <istrue value="${lz4-pure-java}"/>
  </condition>
  <condition property="pom.template.name" value="pom-pure-java.template" else="pom.template">
    <istrue value="${lz4-pure-java}"/>
  </condition>

  <condition property="skip.jni" value="true">
    <istrue value="${lz4-pure-java}"/>
  </condition>

  <condition property="platform" value="linux">
   <os name="Linux"/>
  </condition>
  <condition property="platform" value="win32">
   <os family="windows"/>
  </condition>
  <condition property="platform" value="solaris">
   <os name="SunOS"/>
  </condition>
  <condition property="platform" value="darwin">
   <os family="mac"/>
  </condition>

  <condition property="isMacOS">
    <os family="mac"/>
  </condition>

  <condition property="java10+">
    <javaversion atleast="10"/>
  </condition>

  <target name="clean" description="clean working copy">
    <delete dir="${build}" />
    <delete dir="${dist}" />
    <delete dir="${lib}" />
  </target>

  <target name="ivy-bootstrap" description="install ivy" unless="ivy.available">
    <condition property="ivy.available">
      <typefound uri="antlib:org.apache.ivy.ant" name="configure" />
    </condition>
    <antcall target="-ivy-install" />
  </target>

  <target name="-ivy-install" unless="ivy.available">
    <mkdir dir="${user.home}/.ant/lib" />
    <get src="https://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.jar.version}/${ivy.jar.name}" dest="${user.home}/.ant/lib/${ivy.jar.name}"/>
  </target>

  <target name="install-cpptasks" unless="cpptasks.available">
    <ivy:cachepath organisation="ant-contrib" module="cpptasks" revision="1.0b5"
      inline="true" conf="default" transitive="true" pathid="cpptasks.classpath"/>
    <taskdef uri="antlib:net.sf.antcontrib.cpptasks" resource="net/sf/antcontrib/cpptasks/antlib.xml" classpathref="cpptasks.classpath"/>
    <property name="cpptasks.available" value="true"/>
  </target>

  <target name="install-maven-ant-tasks" unless="maven-ant-tasks.available">
    <ivy:cachepath organisation="org.apache.maven" module="maven-ant-tasks" revision="2.1.3"
      inline="true" conf="default" transitive="true" pathid="maven-ant-tasks.classpath"/>
    <taskdef uri="antlib:org.apache.maven.artifact.ant" resource="org/apache/maven/artifact/ant/antlib.xml" classpathref="maven-ant-tasks.classpath"/>
    <property name="maven-ant-tasks.available" value="true"/>
  </target>

  <target name="install-forbidden-apis" unless="forbidden-apis.available">
    <ivy:cachepath organisation="de.thetaphi" module="forbiddenapis" revision="1.3"
      inline="true" conf="default" transitive="true" pathid="forbidden-apis.classpath"/>
    <taskdef name="forbidden-apis" classname="de.thetaphi.forbiddenapis.AntTask" classpathref="forbidden-apis.classpath"/>
    <property name="forbidden-apis.available" value="true"/>
  </target>

  <target name="install-bnd" unless="bnd.available">
    <!-- using bnd 1.50.0 because more recent versions have broken JAR wrapping -->
    <ivy:cachepath organisation="biz.aQute" module="bnd" revision="1.50.0"
      inline="true" conf="default" transitive="true" pathid="bnd.classpath"/>
    <taskdef resource="aQute/bnd/ant/taskdef.properties" classpathref="bnd.classpath"/>
    <property name="bnd.available" value="true"/> 
  </target>

  <target name="init">
    <tstamp />
    <ivy:resolve file="${ivy.xml.name}" conf="test" />
    <ivy:retrieve />
  </target>

  <target name="install-junit4" depends="init" unless="junit4.available">
    <taskdef uri="antlib:com.carrotsearch.junit4">
      <classpath>
        <fileset dir="${lib}" includes="*.jar" />
      </classpath>
    </taskdef>
    <property name="junit4.available" value="true" />
  </target>

  <target name="generate-sources" depends="init">
    <ivy:cachepath organisation="org.mvel" module="mvel2" revision="2.3.2.Final"
      inline="true" conf="default" transitive="true" pathid="mvel.classpath"/>
    <mkdir dir="${build}/java" />
    <java
      fork="true"
      failonerror="true"
      classpathref="mvel.classpath"
      classname="org.mvel2.sh.Main"
      dir="${src}/build/source_templates">
      <sysproperty key="out.dir" value="${build}/java"/>
      <arg value="${src}/build/gen_sources.mvel" />
    </java>
  </target>

  <target name="compile-java" depends="init, generate-sources">
    <mkdir dir="${build}/classes" />
    <javac
      includeAntRuntime="false"
      srcdir="${src}/java"
      source="${javac.source}"
      target="${javac.target}"
      encoding="UTF-8"
      debug="true"
      destdir="${build}/classes"
      nativeHeaderDir="${build}/jni-headers"/>
    <mkdir dir="${build}/unsafe-classes" />
    <javac
      includeAntRuntime="false"
      srcdir="${src}/java-unsafe"
      source="${javac.source}"
      target="${javac.target}"
      encoding="UTF-8"
      debug="true"
      classpath="${build}/classes"
      destdir="${build}/unsafe-classes"/>
    <mkdir dir="${build}/generated-classes" />
    <javac
      includeAntRuntime="false"
      srcdir="${build}/java"
      source="${javac.source}"
      target="${javac.target}"
      encoding="UTF-8"
      debug="true"
      destdir="${build}/generated-classes">
      <classpath>
        <pathelement location="${build}/classes/" />
        <pathelement location="${build}/unsafe-classes" />
      </classpath>
    </javac>
  </target>

  <target name="check-skip-jni-or-java10+">
    <condition property="skip.jni.or.java10+">
      <or>
        <istrue value="${skip.jni}"/>
        <istrue value="${java10+}"/>
      </or>
    </condition>
  </target>

  <target name="generate-headers" depends="compile-java,check-skip-jni-or-java10+" unless="${skip.jni.or.java10+}">
    <mkdir dir="${build}/jni-headers" />
    <javah
      destDir="${build}/jni-headers">
      <classpath>
        <pathelement location="${build}/classes/" />
      </classpath>
      <class name="net.jpountz.lz4.LZ4JNI" />
      <class name="net.jpountz.xxhash.XXHashJNI" />
    </javah>
  </target>

  <target name="compile-jni" depends="install-cpptasks,generate-headers" unless="${skip.jni}">
    <mkdir dir="${build}/objects" />
    <mkdir dir="${build}/jni/net/jpountz/util/${platform}/${os.arch}" />
    <cpptasks:cc
      debug="false"
      optimize="extreme"
      objdir="${build}/objects"
      outfile="${build}/jni/net/jpountz/util/${platform}/${os.arch}/lz4-java"
      outtype="shared">
      <includepath path="${src}/lz4/lib" />
      <includepath path="${java.home}/../include" />
      <includepath path="${java.home}/../include/${platform}/" />
      <!-- In Java 9, java.home points not to jre/ but to the top directory -->
      <includepath path="${java.home}/include" />
      <includepath path="${java.home}/include/${platform}/" />
      <includepath path="${build}/jni-headers" />
      <fileset dir="${src}/lz4/lib" includes="lz4.c, lz4hc.c, xxhash.c" />
      <fileset dir="${src}/jni" includes="*.c" />
      <linker />
      <compilerarg value="-mmacosx-version-min=10.9" if="isMacOS"/>
    </cpptasks:cc>
  </target>

  <target name="compile" depends="compile-java, compile-jni" />

  <target name="compile-tests" depends="compile">
    <mkdir dir="${build}/test-classes" />
    <javac
      includeAntRuntime="false"
      srcdir="${src}/test"
      encoding="UTF-8"
      debug="true"
      destdir="${build}/test-classes">
      <classpath refid="${prop.compile.tests.classpath}" />
    </javac>
  </target>

  <path id="compile.tests.classpath">
    <pathelement path="${build}/classes" />
    <pathelement path="${build}/unsafe-classes" />
    <pathelement path="${build}/generated-classes" />
    <fileset dir="lib" includes="*.jar" />
  </path>

  <path id="compile.tests.classpath.with.jar">
    <pathelement path="${lz4-java.jar}" />
    <fileset dir="lib" includes="*.jar" />
  </path>

  <path id="test.classpath">
    <pathelement path="${build}/jni" />
    <pathelement path="${src}/resources" />
    <pathelement path="${src}/test-resources" />
    <pathelement path="${build}/classes" />
    <pathelement path="${build}/unsafe-classes" />
    <pathelement path="${build}/generated-classes" />
    <pathelement path="${build}/test-classes" />
    <fileset dir="${lib}" includes="*.jar" />
  </path>

  <path id="test.classpath.with.jar">
    <pathelement path="${lz4-java.jar}" />
    <pathelement path="${src}/test-resources" />
    <pathelement path="${build}/test-classes" />
    <fileset dir="${lib}" includes="*.jar" />
  </path>

  <target name="test" description="run tests">
    <property name="prop.compile.tests.classpath" value="compile.tests.classpath" />
    <property name="prop.test.classpath" value="test.classpath" />
    <antcall target="-test" />
  </target>

  <target name="test-jar" description="run tests with jar specified by lz4-java.jar property">
    <property name="prop.compile.tests.classpath" value="compile.tests.classpath.with.jar" />
    <property name="prop.test.classpath" value="test.classpath.with.jar" />
    <antcall target="-test" />
  </target>

  <target name="-test" depends="compile-tests, install-junit4">
    <mkdir dir="${build}/tests" />
    <junit4:junit4
      dir="${java.io.tmpdir}"
      maxmemory="300m"
      parallelism="auto">
      <assertions>
        <enable package="net.jpountz.lz4"/>
      </assertions>
      <classpath refid="${prop.test.classpath}" />
      <fileset dir="${build}/test-classes/">
        <include name="**/*Test.class" />
        <exclude name="**/*$*" />
        <exclude name="**/Abstract*" />
      </fileset>
      <listeners>
        <junit4:report-text
        showThrowable="true"
        showStackTraces="true"
        showOutput="never"

        showStatusOk="true"
        showStatusError="true"
        showStatusFailure="true"
        showStatusIgnored="true"

        showSuiteSummary="false" />
        <!-- For enkins -->
        <junit4:report-ant-xml dir="${build}/tests" />
      </listeners>
    </junit4:junit4>
  </target>

  <target name="test-skip-jni" description="run tests without building JNI">
    <property name="skip.jni" value="true" />
    <antcall target="test" />
  </target>

  <target name="sources" description="package sources">
    <mkdir dir="${dist}" />
    <jar
      destfile="${dist}/${ivy.module}-${ivy.revision}-sources.jar">
      <fileset dir="${src}/java" />
      <fileset dir="${src}/java-unsafe" />
    </jar>
  </target>

  <target name="docs" description="generate javadocs" depends="init">
    <mkdir dir="${build}/docs" />
    <javadoc
        overview="${src}/java/overview.html"
        packagenames="net.jpountz.lz4,net.jpountz.xxhash"
        windowtitle="lz4 / xxhash - Java API ${ivy.revision}"
        destDir="${build}/docs">
      <link href="http://download.oracle.com/javase/6/docs/api/" />
      <sourcepath>
        <pathelement location="${src}/java"/>
      </sourcepath>
    </javadoc>
    <mkdir dir="${dist}" />
    <jar
      destfile="${dist}/${ivy.module}-${ivy.revision}-javadoc.jar">
      <fileset dir="${build}/docs" />
    </jar>
  </target>

  <target name="jar" description="generate JAR" depends="compile, -jar, -jar-pure-java">
    <!-- Either one of -jar or -jar-pure-java is actually called,
	 depending on the value of the lz4-pure-java property. -->
  </target>

  <target name="-jar" unless="${lz4-pure-java}">
    <mkdir dir="${dist}" />
    <jar
      destfile="${dist}/${ivy.module}.jar">
      <fileset dir="${src}/resources" erroronmissingdir="false" />
      <fileset dir="${build}/classes" />
      <fileset dir="${build}/unsafe-classes" />
      <fileset dir="${build}/generated-classes" />
      <fileset dir="${build}/jni" erroronmissingdir="false" />
      <manifest>
	<attribute name="Automatic-Module-Name" value="org.lz4.java"/>
      </manifest>
    </jar>
  </target>

  <target name="-jar-pure-java" if="${lz4-pure-java}">
    <mkdir dir="${dist}" />
    <jar
      destfile="${dist}/${ivy.module}.jar">
      <fileset dir="${build}/classes" />
      <fileset dir="${build}/unsafe-classes" />
      <fileset dir="${build}/generated-classes" />
      <manifest>
	<attribute name="Automatic-Module-Name" value="org.lz4.pure.java"/>
      </manifest>
    </jar>
  </target>

  <target name="bundle" description="makes the JAR a valid OSGi bundle" depends="install-bnd, jar">
    <taskdef resource="aQute/bnd/ant/taskdef.properties" classpathref="bnd.classpath"/>
    <property name="packages.version" value="${ivy.revision}"/>
    <!-- We need to remove potential -SNAPSHOT qualifiers as package versions... -->
    <script language="javascript">
            <![CDATA[
                // lz4 is the ant project name
                version = lz4.getProperty("packages.version");
                lz4.setProperty("packages.version", version.replace("-SNAPSHOT", ""));
            ]]>
    </script>
    <!-- wrap the JAR as a bundle and set the proper name -->
    <bndwrap definitions="${basedir}" output="${dist}/${ivy.module}-${ivy.revision}.jar" trace="true">
      <fileset dir="${dist}/" includes="${ivy.module}.jar"/>
    </bndwrap>
    <!-- remove plain JAR -->
    <delete file="${dist}/${ivy.module}.jar"/>
  </target>

  <target name="makepom" description="generate a pom file">
    <ivy:makepom
        ivyfile="${basedir}/${ivy.xml.name}"
        pomfile="${dist}/${ivy.module}-${ivy.revision}.pom"
        templatefile="${src}/build/${pom.template.name}">
      <mapping conf="default" scope="compile" />
      <mapping conf="test" scope="test" />
    </ivy:makepom>
  </target>

  <target name="dist" description="package" depends="bundle,docs,sources,makepom" />

  <target name="dist-skip-jni" description="package without building native libraries">
    <property name="skip.jni" value="true" />
    <antcall target="dist" />
  </target>

  <target name="forbidden-apis" description="check API usage" depends="install-forbidden-apis,compile">
    <forbidden-apis internalRuntimeForbidden="true" classpathref="forbidden-apis.classpath">
      <bundledSignatures name="jdk-unsafe-${javac.target}"/>
      <bundledSignatures name="jdk-deprecated-${javac.target}"/>
      <fileset dir="${build}/classes" includes="**/*.class" />
    </forbidden-apis>
    <forbidden-apis classpathref="forbidden-apis.classpath">
      <bundledSignatures name="jdk-unsafe-${javac.target}"/>
      <bundledSignatures name="jdk-deprecated-${javac.target}"/>
      <fileset dir="${build}/classes" includes="**/*.class" />
      <fileset dir="${build}/unsafe-classes" includes="**/*.class" />
    </forbidden-apis>
  </target>

  <macrodef name="deploy">
    <attribute name="repositoryid" />
    <attribute name="repositoryurl" />
    <sequential>
      <mvn:mvn>
        <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.4:sign-and-deploy-file" />
        <arg value="-Durl=@{repositoryurl}" />
        <arg value="-DrepositoryId=@{repositoryid}" />
        <arg value="-DpomFile=${dist}/${ivy.module}-${ivy.revision}.pom" />
        <arg value="-Dfile=${dist}/${ivy.module}-${ivy.revision}.jar" />
        <arg value="-Dfiles=${dist}/${ivy.module}-${ivy.revision}-sources.jar,${dist}/${ivy.module}-${ivy.revision}-javadoc.jar" />
        <arg value="-Dclassifiers=sources,javadoc" />
        <arg value="-Dtypes=jar,jar" />
        <arg value="-Pgpg" />
      </mvn:mvn>
    </sequential>
  </macrodef>

  <target name="deploy" description="deploy snapshot to snapshot repo" depends="install-maven-ant-tasks">
    <property name="skip.jni" value="true" />
    <antcall target="-deploy" />
  </target>

  <target name="-deploy" depends="clean,dist">
    <deploy repositoryid="sonatype-nexus-snapshots" repositoryurl="https://oss.sonatype.org/content/repositories/snapshots" />
  </target>

  <!-- before this, update project version from SNAPSHOT to RELEASE -->
  <target name="stage" description="deploy to release repo" depends="install-maven-ant-tasks,test-skip-jni,forbidden-apis">
    <property name="skip.jni" value="true" />
    <antcall target="-stage" />
  </target>

  <target name="stage-skip-test" description="deploy to release repo, skipping tests" depends="install-maven-ant-tasks,forbidden-apis">
    <property name="skip.jni" value="true" />
    <antcall target="-stage" />
  </target>

  <target name="-stage" depends="clean,dist">
    <deploy repositoryid="sonatype-nexus-staging" repositoryurl="https://oss.sonatype.org/service/local/staging/deploy/maven2" />
  </target>
</project>
