<?xml version="1.0" encoding="UTF-8"?>

<project basedir="." default="jar" name="freemarker"
  xmlns:ivy="antlib:org.apache.ivy.ant"
  xmlns:javacc="http://javacc.dev.java.net/"
  xmlns:docgen="http://freemarker.org/docgen"
  xmlns:bnd="http://www.aqute.biz/bnd"
  xmlns:u="http://freemarker.org/util"
>

  <!-- ================================================================== -->
  <!-- Properties                                                         -->
  <!-- ================================================================== -->

  <!-- Ivy project coordinates: -->
  <property name="moduleOrg" value="org.freemarker" />
  <property name="moduleName" value="freemarker" />
  <property name="moduleBranch" value="2.3" />

  <!-- Will be overidden on the Continous Integration server: -->
  <property name="server.ivy.repo.root" value="${basedir}/build/dummy-server-ivy-repo" />
  
  <property file="build.properties"/>
  <condition property="has.explicit.boot.classpath.j2se1.4">
    <isset property="boot.classpath.j2se1.4"/>
  </condition>
  <condition property="has.explicit.boot.classpath.j2se1.5">
    <isset property="boot.classpath.j2se1.5"/>
  </condition>
  <condition property="has.all.explicit.boot.classpaths">
    <and>
      <isset property="has.explicit.boot.classpath.j2se1.4"/>
      <isset property="has.explicit.boot.classpath.j2se1.5"/>
    </and>
  </condition>
  <available property="atLeastJDK8" classname="java.util.function.Predicate"/>

  <!-- When boot.classpath.j2se* is missing, these will be the defaults: -->
  <!-- Note: Target "dist" doesn't allow using these. -->
  <property name="boot.classpath.j2se1.4" value="${sun.boot.class.path}" />
  <property name="boot.classpath.j2se1.5" value="${sun.boot.class.path}" />
  
  <!-- For checking the correctness of the boot.classpath.j2se* -->
  <available classpath="${boot.classpath.j2se1.4}"
    classname="java.lang.Object" ignoresystemclasses="true" 
    property="boot.classpath.j2se1.4.correct"
  />
  <available classpath="${boot.classpath.j2se1.5}"
    classname="java.lang.Object" ignoresystemclasses="true" 
    property="boot.classpath.j2se1.5.correct"
  />
  
  <condition property="example.freemarker.jar.location"
    value="freemarker.jar" else="build/freemarker.jar">
    <and>
      <available  file="freemarker.jar" />
      <not>
        <available  file="build/freemarker.jar" />
      </not>
    </and>
  </condition>
  
  <available file="lib/struts" property="struts.available" />
  
  <!-- Set up version/timestamp filters and the version property: -->
  <tstamp>
    <format property="timestampNice" pattern="yyyy-MM-dd'T'HH:mm:ss'Z'"
        timezone="UTC" />
    <format property="timestampInVersion" pattern="yyyyMMdd'T'HHmmss'Z'"
        timezone="UTC" />
  </tstamp>
  <filter token="timestampInVersion" value="${timestampInVersion}" />
  <filter token="timestampNice" value="${timestampNice}" />
  <mkdir dir="build"/>
  <!-- Copying is needed to substitute the timestamps. -->
  <copy
      file="src/main/resources/freemarker/version.properties"
      tofile="build/version.properties.tmp"
      filtering="true"
      overwrite="true"
  />
  <property file="build/version.properties.tmp" />
  <delete file="build/version.properties.tmp" />
  <filter token="version" value="${version}" />
  
  <property name="dist.dir" value="build/dist/freemarker-${version}" />
  
  
  <!-- ================================================================== -->
  <!-- Initialization                                                     -->
  <!-- ================================================================== -->

  
  <target name="clean" description="get rid of all generated files">
    <delete dir="build" />
  </target>

  <target name="clean-classes" description="get rid of compiled classes">
    <delete dir="build/classes" />
    <delete dir="build/test-classes" />
    <delete dir="build/coverage/classes" />
  </target>

  <condition property="deps.available">
    <available file=".ivy" />
  </condition>
  
  <target name="init" depends="_autoget-deps"
    description="Fetch dependencies if any are missing and create the build directory if necessary"
  >
    <mkdir dir="build"/>
  </target>

  
  <!-- ================================================================= -->
  <!-- Compilation                                                       -->
  <!-- ================================================================= -->

  
  <target name="javacc" depends="init" unless="parser.uptodate"
    description="Build the parser from its grammar file"
  >
    <ivy:cachepath conf="parser" pathid="ivy.dep" />
    <taskdef name="generate" classname="org.apache.tools.ant.taskdefs.optional.javacc.JavaCC"
      uri="http://javacc.dev.java.net/"
      classpathref="ivy.dep"
    />
    
    <property name="_javaccOutputDir"
      value="build/generated-sources/java/freemarker/core/"
    />

    <mkdir dir="${_javaccOutputDir}" />
    <ivy:retrieve conf="parser" pattern="build/javacc-home.tmp/[artifact].[ext]" />
    <javacc:generate
      target="src/main/javacc/FTL.jj"
      outputdirectory="${_javaccOutputDir}"
      javacchome="build/javacc-home.tmp"
    />
    <delete dir="build/javacc-home.tmp" />
    
    <replace
      file="${_javaccOutputDir}/FMParser.java"
      token="private final LookaheadSuccess"
      value="private static final LookaheadSuccess"
    />
    <replace
      file="${_javaccOutputDir}/FMParserConstants.java"
      token="public interface FMParserConstants"
      value="interface FMParserConstants"
    />
    <replace
      file="${_javaccOutputDir}/FMParserTokenManager.java"
      token="public class FMParserTokenManager"
      value="class FMParserTokenManager"
    />
    <replace
      file="${_javaccOutputDir}/Token.java"
      token="public class Token"
      value="class Token implements java.io.Serializable"
    />
    <replace
      file="${_javaccOutputDir}/SimpleCharStream.java"
      token="public final class SimpleCharStream"
      value="final class SimpleCharStream"
    />
    <replace
      file="${_javaccOutputDir}/FMParser.java"
      token="enum"
      value="ENUM"
    />
    
    <!-- As we have a modified version in src/main/java: -->
    <move 
      file="${_javaccOutputDir}/ParseException.java"
      tofile="${_javaccOutputDir}/ParseException.java.ignore"
    />
    <move 
      file="${_javaccOutputDir}/TokenMgrError.java"
      tofile="${_javaccOutputDir}/TokenMgrError.java.ignore"
    />
  </target>
   
  <target name="compile" depends="javacc">
    <fail unless="boot.classpath.j2se1.4.correct"><!--
      -->The "boot.classpath.j2se1.4" property value (${boot.classpath.j2se1.4}) <!--
      -->seems to be an incorrect boot classpath. Please fix it in <!--
      -->the &lt;projectDir>/build.properties file, or wherever you <!--
      -->set it.<!--
    --></fail>
    <fail unless="boot.classpath.j2se1.5.correct"><!--
      -->The "boot.classpath.j2se1.5" property value (${boot.classpath.j2se1.5}) <!--
      -->seems to be an incorrect boot classpath. Please fix it in <!--
      -->the &lt;projectDir>/build.properties file, or wherever you <!--
      -->set it.<!--
    --></fail>
    <echo level="info">Using boot classpaths: 1.4: ${boot.classpath.j2se1.4}; 1.5: ${boot.classpath.j2se1.5}</echo>

    <mkdir dir="build/classes" />
    
    <!-- Note: the "build.base" conf doesn't include optional FreeMarker dependencies. -->
    <ivy:cachepath conf="build.base" pathid="ivy.dep" />
    <javac destdir="build/classes" deprecation="off" 
      debug="on" optimize="off" target="1.4" source="1.4" encoding="utf-8"
      includeantruntime="false"
      classpathref="ivy.dep"
      bootclasspath="${boot.classpath.j2se1.4}"
      excludes="
        freemarker/ext/beans/_EnumModels.java,
        freemarker/ext/dom/SunInternalXalanXPathSupport.java,
        
        freemarker/ext/jsp/**,
        freemarker/ext/servlet/**,
        freemarker/cache/WebappTemplateLoader.java,
      
        freemarker/ext/jython/**,
        freemarker/template/utility/JythonRuntime.java,
        freemarker/ext/ant/**"
    >
      <src>
        <pathelement location="src/main/java" />
        <pathelement location="build/generated-sources" />
      </src>
    </javac>

    <rmic
      base="build/classes" includes="freemarker/debug/impl/Rmi*Impl.class"
      classpathref="ivy.dep"
      verify="yes" stubversion="1.2"
    />

    <ivy:cachepath conf="build.j2se1.5" pathid="ivy.dep.j2se1.5" />
    <javac srcdir="src/main/java" destdir="build/classes" deprecation="off" 
      debug="on" optimize="off" target="1.5" source="1.5" encoding="utf-8"
      includeantruntime="false"
      classpathref="ivy.dep.j2se1.5"
      bootclasspath="${boot.classpath.j2se1.5}"
      includes="
        freemarker/ext/beans/_EnumModels.java,
        freemarker/ext/dom/SunInternalXalanXPathSupport.java"
    />

    <ivy:cachepath conf="build.jsp2.0" pathid="ivy.dep.jsp1.2" />
    <javac srcdir="src/main/java" destdir="build/classes" deprecation="off" 
      debug="on" optimize="off" target="1.4" source="1.4" encoding="utf-8"
      includeantruntime="false"
      classpathref="ivy.dep.jsp1.2"
      bootclasspath="${boot.classpath.j2se1.4}"
      includes="
        freemarker/ext/jsp/**,
        freemarker/ext/servlet/**,
        freemarker/cache/WebappTemplateLoader.java"
      excludes="
        freemarker/ext/jsp/TaglibFactory.java,
        freemarker/ext/jsp/_FreeMarkerPageContext1.java,
        freemarker/ext/jsp/_FreeMarkerPageContext21.java,
        freemarker/ext/jsp/FreeMarkerJspFactory21.java,
        freemarker/ext/jsp/FreeMarkerJspApplicationContext.java"
    />
    
    <ivy:cachepath conf="build.jsp1.2" pathid="ivy.dep.jsp1.2" />
    <javac srcdir="src/main/java" destdir="build/classes" deprecation="off" 
      debug="on" optimize="off" target="1.4" source="1.4" encoding="utf-8"
      includeantruntime="false"
      classpathref="ivy.dep.jsp1.2"
      bootclasspath="${boot.classpath.j2se1.4}"
      includes="
        freemarker/ext/jsp/TaglibFactory.java,
        freemarker/ext/jsp/_FreeMarkerPageContext1.java"
    />
    
    <!-- There's no build.jsp2.0, as those classes are part of the common build subset. -->
    
    <ivy:cachepath conf="build.jsp2.1" pathid="ivy.dep.jsp2.1" />
    <javac srcdir="src/main/java" destdir="build/classes" deprecation="off" 
      debug="on" optimize="off" target="1.4" source="1.4" encoding="utf-8"
      includeantruntime="false"
      classpathref="ivy.dep.jsp2.1"
      bootclasspath="${boot.classpath.j2se1.4}"
      includes="
        freemarker/ext/jsp/_FreeMarkerPageContext21.java,
        freemarker/ext/jsp/FreeMarkerJspFactory21.java,
        freemarker/ext/jsp/FreeMarkerJspApplicationContext.java"
    />

    <ivy:cachepath conf="build.jython2.0" pathid="ivy.dep.jython2.0" />
    <javac srcdir="src/main/java" destdir="build/classes" deprecation="off" 
      debug="on" optimize="off" target="1.4" source="1.4" encoding="utf-8"
      includeantruntime="false"
      classpathref="ivy.dep.jython2.0"
      bootclasspath="${boot.classpath.j2se1.4}"
      includes="
        freemarker/ext/ant/**,
        freemarker/template/utility/JythonRuntime.java,
        freemarker/ext/jython/**"
      excludes="
        freemarker/ext/jython/_Jython22VersionAdapter.java,
        freemarker/ext/jython/_Jython25VersionAdapter.java"
    />
    
    <ivy:cachepath conf="build.jython2.2" pathid="ivy.dep.jython2.2" />
    <javac srcdir="src/main/java" destdir="build/classes" deprecation="off" 
      debug="on" optimize="off" target="1.4" source="1.4" encoding="utf-8"
      includeantruntime="false"
      classpathref="ivy.dep.jython2.2"
      bootclasspath="${boot.classpath.j2se1.4}"
      includes="
        freemarker/ext/jython/_Jython22VersionAdapter.java"
    />
    
    <ivy:cachepath conf="build.jython2.5" pathid="ivy.dep.jython2.5" />
    <javac srcdir="src/main/java" destdir="build/classes" deprecation="off" 
      debug="on" optimize="off" target="1.4" source="1.4" encoding="utf-8"
      includeantruntime="false"
      classpathref="ivy.dep.jython2.5"
      bootclasspath="${boot.classpath.j2se1.5}"
      includes="
        freemarker/ext/jython/_Jython25VersionAdapter.java"
    />
    
    <rmic base="build/classes" classpathref="ivy.dep"
      includes="src/main/java/freemarker/debug/impl/Rmi*Impl.class"
      verify="yes" stubversion="1.2"
    />
    
    <!-- We don't have this file in 2.4.X... yet?
    <copy
      file="build/classes/freemarker/core/SecureRendererImpl.class"
      tofile="build/classes/freemarker/core/SecureRendererImpl.clazz"
    />
    -->
    
    <copy toDir="build/classes">
      <fileset dir="src/main/resources"
        excludes="
          freemarker/version.properties"
      />
    </copy>
    <copy toDir="build/classes" filtering="true" overwrite="true">
      <fileset dir="src/main/resources"
        includes="
          freemarker/version.properties"
      />
    </copy>
    <copy toDir="build/classes/META-INF">
      <fileset dir="."
        includes="
          LICENSE.txt,
          NOTICE.txt"
      />
    </copy>
  </target>

  <target name="compileTest" depends="compile">
    <mkdir dir="build/test-classes" />
  
    <ivy:cachepath conf="build.test" pathid="ivy.dep.build.test" />
    <javac srcdir="src/test/java" destdir="build/test-classes" deprecation="off" 
      debug="on" optimize="off" target="1.5" source="1.5" encoding="utf-8"
      includeantruntime="false"
      classpath="build/classes"
      classpathref="ivy.dep.build.test"
      bootclasspath="${boot.classpath.j2se1.5}"
    />
    <copy toDir="build/test-classes">
      <fileset dir="src/test/resources"
        excludes=""
      />
    </copy>
  </target>
   
   <target name="jar" depends="compile">
    <ivy:cachepath pathid="ivy.dep" conf="bnd" />
    <taskdef resource="aQute/bnd/ant/taskdef.properties"
      uri="http://www.aqute.biz/bnd"
      classpathref="ivy.dep"
    />
  
    <!-- Hack: This file should be excluded, but I can't explain that to bnd. -->
    <!-- We don't have this file in 2.4.X... yet?
    <move
        file="build/classes/freemarker/core/SecureRendererImpl.class"
        tofile="build/SecureRendererImpl.class.tmp"
        preservelastmodified="true" overwrite="true"
    />
    -->
    <bnd:bnd
        files="osgi.bnd" eclipse="false"
        output="build/freemarker.jar"
    />
    <!-- Revert previous hack... -->
    <!-- We don't have this file in 2.4.X... yet?
    <move
        file="build/SecureRendererImpl.class.tmp"
        tofile="build/classes/freemarker/core/SecureRendererImpl.class"
        preservelastmodified="true" overwrite="true"
    />
    -->
  </target>

  <!-- ================================================================= -->
  <!-- Testing                                                           -->
  <!-- ================================================================= -->

  <target name="test" depends="compileTest" description="Run test cases">
    <mkdir dir="build/junit-reports" />
    <ivy:cachepath conf="run.test" pathid="ivy.dep.run.test" />
    <junit haltonfailure="on" fork="true" forkmode="once">
      <classpath>
        <pathelement path="build/test-classes" />
        <pathelement path="build/classes" />
        <path refid="ivy.dep.run.test" />
      </classpath>
      <formatter type="plain" />
      <formatter type="xml" />
      <batchtest todir="build/junit-reports">
        <fileset dir="src/test/java">
          <include name="**/*Test.java" />
          <include name="**/*TestSuite.java" />
          <exclude name="**/Abstract*.java" />
        </fileset>
      </batchtest>
    </junit>
  </target>
  
  <!-- ================================================================= -->
  <!-- Generate docs                                                     -->
  <!-- ================================================================= -->

  <target depends="javacc" name="_rawJavadoc">
    <!-- depends="javacc" is needed as its output is referred in the docs. -->
    <mkdir dir="build/api" />
    <delete includeEmptyDirs="yes">
      <fileset dir="build/api" includes="**/*" />
    </delete>
    <!-- javadoc with <fileset> has bugs, so we create a filtered copy: -->
    <copy todir="build/javadoc-sources">
      <fileset dir="src/main/java">
        <exclude name="**/_*.java" />
        <exclude name="**/SunInternalXalanXPathSupport.java" />
        <!-- Remove classes that are, I suppose, only accidentally public: -->
        <exclude name="**/core/LocalContext.java" />
        <exclude name="**/core/CollectionAndSequence.java" />
        <exclude name="**/core/Comment.java" />
        <exclude name="**/core/DebugBreak.java" />
        <exclude name="**/core/Expression.java" />
        <exclude name="**/core/LibraryLoad.java" />
        <exclude name="**/core/Macro.java" />
        <exclude name="**/core/ReturnInstruction.java" />
        <exclude name="**/core/StringArraySequence.java" />
        <exclude name="**/core/TemplateElement.java" />
        <exclude name="**/core/TemplateObject.java" />
        <exclude name="**/core/TextBlock.java" />
        <exclude name="**/core/ReturnInstruction.java" />
        <exclude name="**/core/TokenMgrError.java" />
        <exclude name="**/template/EmptyMap.java" />
        <exclude name="**/log/SLF4JLoggerFactory.java" />
        <exclude name="**/log/CommonsLoggingLoggerFactory.java" />
      </fileset>
    </copy>
    
    <!-- conf="IDE": as that has to contain all depedencies -->
    <ivy:cachepath conf="IDE" pathid="ivy.dep" />
    <javadoc
      sourcepath="build/javadoc-sources"
      destdir="build/api"
      doctitle="FreeMarker ${version}"
      packagenames="
        freemarker.debug, freemarker.template.*,
        freemarker.core.*, freemarker.ext.*,
        freemarker.cache.*, freemarker.log.*"
      use="true"
      version="true"
      author="true"
      windowtitle="FreeMarker ${version} API"
      classpath="build/classes"
      classpathref="ivy.dep"
      failonerror="true"
      charset="UTF-8"
      docencoding="UTF-8"
      locale="en_US"
    >
      <link href="http://docs.oracle.com/javase/8/docs/api/"/>
    </javadoc>
    <delete dir="build/javadoc-sources" />
  </target>

  <target name="javadoc" depends="_rawJavadoc, _fixJDK8JavadocCSS" description="Build the JavaDocs" />
  
  <target name="_fixJDK8JavadocCSS" depends="_rawJavadoc" if="atLeastJDK8">
    <property name="file" value="build/api/stylesheet.css" />
        
    <available file="${file}" property="stylesheet.available"/>
    <fail unless="stylesheet.available">CSS file not found: ${file}</fail>
    <echo>Fixing JDK 8 CSS in ${file}</echo>
    
    <!-- Tell that it's modified: -->
    <replaceregexp
        file="${file}" flags="gs" encoding="utf-8"
        match="/\* (Javadoc style sheet) \*/" replace="/\* \1 - JDK 8 usability fix regexp substitutions applied \*/"
    />

    <!-- Remove broken link: -->
    <replaceregexp
        file="${file}" flags="gs" encoding="utf-8"
        match="@import url\('resources/fonts/dejavu.css'\);\s*" replace=""
    />
    
    <!-- Font family fixes: -->
    <replaceregexp
        file="${file}" flags="gsi" encoding="utf-8"
        match="['&quot;]DejaVu Sans['&quot;]" replace="Arial"
    />
    <replaceregexp
        file="${file}" flags="gsi" encoding="utf-8"
        match="['&quot;]DejaVu Sans Mono['&quot;]" replace="'Courier New'"
    />
    <replaceregexp
        file="${file}" flags="gsi" encoding="utf-8"
        match="['&quot;]DejaVu Serif['&quot;]" replace="Arial"
    />
    <replaceregexp
        file="${file}" flags="gsi" encoding="utf-8"
        match="(?&lt;=[\s,:])serif\b" replace="sans-serif"
    />
    <replaceregexp
        file="${file}" flags="gsi" encoding="utf-8"
        match="(?&lt;=[\s,:])Georgia,\s*" replace=""
    />
    <replaceregexp
        file="${file}" flags="gsi" encoding="utf-8"
        match="['&quot;]Times New Roman['&quot;],\s*" replace=""
    />
    <replaceregexp
        file="${file}" flags="gsi" encoding="utf-8"
        match="(?&lt;=[\s,:])Times,\s*" replace=""
    />
    <replaceregexp
        file="${file}" flags="gsi" encoding="utf-8"
        match="(?&lt;=[\s,:])Arial\s*,\s*Arial\b" replace="Arial"
    />
    
    <!-- "Parameters:", "Returns:", "Throws:", "Since:", "See also:" etc. fixes: -->
    <property name="ddSelectorStart" value="(?:\.contentContainer\s+\.(?:details|description)|\.serializedFormContainer)\s+dl\s+dd\b.*?\{[^\}]*\b" />
    <property name="ddPropertyEnd" value="\b.+?;" />
    <!-- - Put back description (dd) indentation: -->
    <replaceregexp
        file="${file}" flags="gs" encoding="utf-8"
        match="(${ddSelectorStart})margin${ddPropertyEnd}" replace="\1margin: 5px 0 10px 20px;"
    />
    <!-- - No monospace font for the description (dd) part: -->
    <replaceregexp
        file="${file}" flags="gs" encoding="utf-8"
        match="(${ddSelectorStart})font-family${ddPropertyEnd}" replace="\1"
    />
  </target>
  
  <!-- ====================== -->
  <!-- Manual                 -->
  <!-- ====================== -->
  
  <macrodef name="manual" uri="http://freemarker.org/util">
    <attribute name="offline" />
    <sequential>
      <ivy:cachepath conf="manual" pathid="ivy.dep" />
      <taskdef resource="org/freemarker/docgen/antlib.properties"
        uri="http://freemarker.org/docgen"
        classpathref="ivy.dep"
      />
      
      <docgen:transform
        srcdir="src/manual" destdir="build/manual"
        offline="@{offline}"
      />
    </sequential>
  </macrodef>
  
  <target name="manualOffline" depends="init" description="Build the Manual for offline use" >
    <u:manual offline="true" />
  </target>

  <target name="manualFreemarkerOrg" depends="init" description="Build the Manual to be upload to freemarker.org" >
    <u:manual offline="false" />
  </target>

  <!-- ====================== -->
  <!-- Examples               -->
  <!-- ====================== -->

  <macrodef name="buildExampleWebapp" uri="http://freemarker.org/util">
    <attribute name="exampleName" />
    <sequential>
      <mkdir dir="build/examples/@{exampleName}/WEB-INF/classes" />
      <ivy:cachepath conf="example.@{exampleName}" pathid="ivy.dep" />
      <javac
        srcdir="src/examples/@{exampleName}/WEB-INF/classes"
        destdir="build/examples/@{exampleName}/WEB-INF/classes"
        deprecation="off" debug="on" optimize="off" target="1.4" source="1.4"
        encoding="utf-8"
        includeantruntime="false"
        classpathref="ivy.dep"
        bootclasspath="${boot.classpath.j2se1.4}"
      >
        <classpath>
          <pathelement path="${ivy.dep}" />
          <pathelement location="${example.freemarker.jar.location}" />
          <fileset dir="lib/struts" erroronmissingdir="false">
            <include name="*.jar" />
          </fileset>
        </classpath>
      </javac>
      <copy toDir="build/examples/@{exampleName}">
        <fileset dir="src/examples/@{exampleName}" excludes="**/*.java" />
      </copy>
      <copy file="${example.freemarker.jar.location}"
        todir="build/examples/@{exampleName}/WEB-INF/lib" />
      <echo message="*** Example built: build/examples/@{exampleName} ***" />
    </sequential>
  </macrodef>
  
  <target name="example-webapp1" depends="jar" description="Build example webapp 1">
    <u:buildExampleWebapp examplename="webapp1" />
  </target>

  <target name="example-webapp2" depends="jar" description="Build example webapp 2">
    <u:buildExampleWebapp examplename="webapp2" />
  </target>

  <target name="example-struts-webapp" depends="jar" description="Build example Struts 1 webapp">
    <fail unless="struts.available"><!--
      -->You have to copy the Struts 1.1 jar-s to <!--
      -->&lt;freemarker_project>/lib/struts to build this example!<!--
    --></fail>
    <copy todir="build/examples/struts-webapp/WEB-INF/lib">
      <fileset dir="lib/struts" />
    </copy>
    <u:buildExampleWebapp examplename="struts-webapp" />
  </target>
  
  <target name="example-ant" depends="jar" description="Build Ant example">
    <mkdir dir="build/examples/ant" />
    <copy toDir="build/examples/ant">
      <fileset dir="src/examples/ant" />
    </copy>
    <copy file="${example.freemarker.jar.location}"
      todir="build/examples/ant/lib" />
    <echo message="*** Example built: build/examples/ant ***" />
  </target>

  <!-- ====================== -->
  <!-- Distributuion building -->
  <!-- ====================== -->

  <target name="dist"
    description="Build the FreeMarker distribution files"
  >
    <fail
      unless="has.all.explicit.boot.classpaths"
      message="All boot.classpath properties must be set in build.properties for dist!"
    />
    <fail unless="atLeastJDK8" message="The release should be built with JDK 8+ (you may need to set JAVA_HOME)" />
    <antcall target="clean" />  <!-- To improve the reliability -->
    <antcall target="_dist" />
  </target>

  <target name="_dist"
    depends="jar, javadoc, manualOffline"
  >
    <!-- Copy jars and sources and such into the distro -->
    <delete dir="${dist.dir}" />
    <mkdir dir="${dist.dir}" />
    
    <!-- Copy txt-s -->
    <copy todir="${dist.dir}" includeEmptyDirs="no">
      <fileset dir="." defaultexcludes="no">
        <include name="*.txt" />
        <!-- Because of the documentation fonts, the distribution has an extended version of these: -->
        <exclude name="LICENSE.txt" />
        <exclude name="NOTICE.txt" />
      </fileset>
    </copy>
    <replace
      file="${dist.dir}/README.txt"
      token="{version}"
      value="${version}"
    />

    <!-- Copy binary -->
    <copy file="build/freemarker.jar" tofile="${dist.dir}/freemarker.jar" />

    <!-- Copy documentation -->
    <mkdir dir="${dist.dir}/documentation" />
    <copy todir="${dist.dir}/">
      <fileset dir="src/dist/" />
    </copy>
    <copy todir="${dist.dir}/documentation/_html" includeEmptyDirs="no">
      <fileset dir="build/manual" />
    </copy>
    <copy todir="${dist.dir}/documentation/_html/api" includeEmptyDirs="no">
      <fileset dir="build/api" />
    </copy>
    
    <copy todir="${dist.dir}/source" includeEmptyDirs="no">
      <fileset dir="." defaultexcludes="no">
        <exclude name="**/*.bak" />
        <exclude name="**/*.~*" />
        <include name="src/**" />
        <include name="examples/**" />
        <include name=".settings/**" />
        <include name="*.xml" />
        <include name="*.sample" />
        <include name="*.txt" />
        <include name="osgi.bnd" />
        <include name=".classpath" />
        <include name=".project" />
        <include name=".git*" />
      </fileset>
    </copy>
    
    <!-- Package the distro -->
    <property name="freemarker.tar" value="build/freemarker-${version}.tar" />
    <property name="freemarker.gzip" value="${freemarker.tar}.gz" />
    <delete file="${freemarker.tar}" />
    <tar tarfile="${freemarker.tar}" basedir="${dist.dir}" />
    <delete file="${freemarker.gzip}" />
    <gzip zipfile="${freemarker.gzip}" src="${freemarker.tar}" />
    <delete file="${freemarker.tar}" />
  </target>

  <target name="maven-pom">
    <echo file="build/pom.xml"><![CDATA[<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  
  <parent>
    <groupId>org.sonatype.oss</groupId>
    <artifactId>oss-parent</artifactId>
    <version>9</version>
  </parent>
  
  <groupId>org.freemarker</groupId>
  <artifactId>freemarker</artifactId>
  <version>${mavenVersion}</version>
  
  <packaging>jar</packaging>
  
  <name>FreeMarker</name>
  <description>
    FreeMarker is a "template engine"; a generic tool to generate text output based on templates.
  </description>
  <url>http://freemarker.org/</url>
  <licenses>
    <license>
      <name>Apache License, Version 2.0</name>
      <url>http://freemarker.org/LICENSE.txt</url>
    </license>
  </licenses>
  <scm>
    <connection>scm:git:git@github.com:freemarker/freemarker.git</connection>
    <developerConnection>scm:git:git@github.com:freemarker/freemarker.git</developerConnection>
    <url>git@github.com:freemarker/freemarker.git</url>
  </scm>
  <developers>
    <developer>
      <name>Attila Szegedi</name>
    </developer>
    <developer>
      <name>Daniel Dekany</name>
      <email>ddekany@freemail.hu</email>
    </developer>
    <developer>
      <name>Jonathan Revusky</name>
    </developer>
  </developers>  
  
  <dependencies>
    <!-- no required dependencies -->
  </dependencies>
</project>
]]></echo>
  </target>
  
  <!--
    Uploads the freemarker.jar that is in the current DISTRIBUTION DIRECTORY
    to a Maven repository (snapshot or central).
    Use this after "dist" (without interleaving "clean").
  -->
  <target name="maven-dist" depends="maven-pom"
      description="Releases the already built distro to a Maven repository">
    <jar destfile="build/maven-source-attachment.jar">
      <fileset dir="${dist.dir}/source/src/main/java" />
      <fileset dir="${dist.dir}/source/src/main/resources" />
    </jar>

    <jar destfile="build/maven-javadoc-attachment.jar">
      <fileset dir="${dist.dir}/documentation/_html/api" />
    </jar>

    <property name="maven-server-id" value="ossrh" />
    <property name="maven-repository-url" value="https://oss.sonatype.org/service/local/staging/deploy/maven2/" />
    <!--
    Don't deploy to public snapshot repositories here!
    It isn't backward compatible as version ranges will pick them up.
    -->
    
    <input
       validargs="y,n"
       addproperty="mavenUpload.answer"
    >
You are about uploading
${dist.dir}/freemarker.jar
and its attachments to this Maven repository:
${maven-repository-url}
with Maven artifact version number ${mavenVersion}.
Note that it's assumed that you have run `ant dist` just before this.
Proceed? </input>
    <condition property="mavenUpload.yes">
      <equals arg1="y" arg2="${mavenUpload.answer}"/>
    </condition>
    <fail unless="mavenUpload.yes" message="Task aborted by user." />
    
		<!-- Sign and deploy the main artifact -->
		<exec executable="${mvnCommand}">
			<arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
			<arg value="-Durl=${maven-repository-url}" />
			<arg value="-DrepositoryId=${maven-server-id}" />
			<arg value="-DpomFile=build/pom.xml" />
			<arg value="-Dfile=${dist.dir}/freemarker.jar" />
      <arg value="-Pgpg" />
		</exec>

		<!-- Sign and deploy the sources artifact -->
		<exec executable="${mvnCommand}">
			<arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
			<arg value="-Durl=${maven-repository-url}" />
			<arg value="-DrepositoryId=${maven-server-id}" />
			<arg value="-DpomFile=build/pom.xml" />
			<arg value="-Dfile=build/maven-source-attachment.jar" />
			<arg value="-Dclassifier=sources" />
      <arg value="-Pgpg" />
		</exec>

		<!-- Sign and deploy the javadoc artifact -->
		<exec executable="${mvnCommand}">
			<arg value="org.apache.maven.plugins:maven-gpg-plugin:1.3:sign-and-deploy-file" />
			<arg value="-Durl=${maven-repository-url}" />
			<arg value="-DrepositoryId=${maven-server-id}" />
			<arg value="-DpomFile=build/pom.xml" />
			<arg value="-Dfile=build/maven-javadoc-attachment.jar" />
			<arg value="-Dclassifier=javadoc" />
      <arg value="-Pgpg" />
		</exec>
    
    <echo>*****************************************************************</echo>
    <echo>Check the above lines for any Maven errors!</echo>
    <echo>Now you have to release the staged repo on</echo>
    <echo>https://oss.sonatype.org/.</echo>
    <echo>*****************************************************************</echo>
  </target>
  
  
  <!-- ================================================================== -->
  <!-- Eclipse                                                            -->
  <!-- ================================================================== -->

  <property name="eclipseFeatureFileName" value="org.freemarker.freemarker.feature_${versionForOSGi}.jar" />
  <property name="eclipseSourceFeatureFileName" value="org.freemarker.freemarker.source.feature_${versionForOSGi}.jar" />
  <property name="eclipsePluginFileName" value="org.freemarker.freemarker_${versionForOSGi}.jar" />
  <property name="eclipseSourcePluginFileName" value="org.freemarker.freemarker.source_${versionForOSGi}.jar" />
  
  <target name="eclipse-update-site" depends="jar">
    <delete dir="build/eclipse" />

    <!-- Create org.freemarker.freemarker feature: -->
    
    <mkdir dir="build/eclipse/freemarker/plugins" />
    <copy
        file="build/freemarker.jar"
        tofile="build/eclipse/freemarker/plugins/org.freemarker.freemarker_${versionForOSGi}.jar"
    />
    
    <mkdir dir="build/eclipse/freemarker/features/tmp" />
    <echo file="build/eclipse/freemarker/features/tmp/feature.xml"><![CDATA[<?xml version="1.0"?>
<feature
    id="org.freemarker.freemarker"
    label="FreeMarker"
    version="${versionForOSGi}">

  <description url="http://freemarker.org">
    Adds barebone FreeMarker as a plug-in (OSGi bundle) to Eclipse.
  </description>

  <license><!--
    -->Apache License, Version 2.0; see http://freemarker.org/LICENSE.txt.<!--
  --></license>

  <plugin
      id="org.freemarker.freemarker"
      download-size="0"
      install-size="0"
      version="${versionForOSGi}"
      unpack="false"
  />
</feature>
    ]]></echo>
    <jar
        basedir="build/eclipse/freemarker/features/tmp"
        destfile="build/eclipse/freemarker/features/${eclipseFeatureFileName}"
    />
    <delete dir="build/eclipse/freemarker/features/tmp" />

    <!-- Create org.freemarker.freemarker.source feature: -->
    
    <mkdir dir="build/eclipse/freemarker/plugins" />
    <jar 
        basedir="src/main/java" jarfile="build/eclipse/freemarker/plugins/org.freemarker.freemarker.source_${versionForOSGi}.jar" 
    >
      <manifest>
        <attribute name="Bundle-SymbolicName" value="${moduleOrg}.${moduleName}.source" />
        <attribute name="Bundle-Version" value="${versionForOSGi}" />
        <attribute name="Bundle-License" value="Apache License, Version 2.0" />
        <attribute name="Bundle-Vendor" value="freemarker.org" />
        <attribute name="Eclipse-SourceBundle" value='org.freemarker.freemarker;version="${versionForOSGi}";roots:="."' />
      </manifest>
    </jar>
    
    <mkdir dir="build/eclipse/freemarker/features/tmp" />
    <echo file="build/eclipse/freemarker/features/tmp/feature.xml"><![CDATA[<?xml version="1.0"?>
<feature
    id="org.freemarker.freemarker.source"
    label="FreeMarker source"
    version="${versionForOSGi}">

  <description url="http://freemarker.org">
    Adds source code attachment to the barebone FreeMarker plug-in.
  </description>

  <license><!--
    -->Apache License, Version 2.0; see http://freemarker.org/LICENSE.txt.<!--
  --></license>

  <plugin
      id="org.freemarker.freemarker.source"
      download-size="0"
      install-size="0"
      version="${versionForOSGi}"
      unpack="false"
  />
</feature>
    ]]></echo>
    <jar
        basedir="build/eclipse/freemarker/features/tmp"
        destfile="build/eclipse/freemarker/features/${eclipseSourceFeatureFileName}"
    />
    <delete dir="build/eclipse/freemarker/features/tmp" />

    <!-- Create site: -->

    <echo file="build/eclipse/freemarker/site.xml"><![CDATA[<?xml version="1.0"?>
<site>
  <feature url="features/${eclipseFeatureFileName}"
      id="org.freemarker.freemarker"
      version="${versionForOSGi}">
    <category name="core" />
    <category name="core-with-sources" />
  </feature>
  <feature url="features/${eclipseSourceFeatureFileName}"
      id="org.freemarker.freemarker.source"
      version="${versionForOSGi}">
    <category name="core-with-sources" />
  </feature>
  <category-def name="core" label="FreeMarker core">
    <description>
      Features that are used as dependencies of other products, but do nothing visible themselves.
    </description>
  </category-def>
  <category-def name="core-with-sources" label="FreeMarker core with sources">
    <description>
      Features that are used as dependencies of other products, but do nothing visible themselves.
      Includes source code attachments.
    </description>
  </category-def>
</site>
    ]]></echo>
    <echo message="**************************************************************" />
    <echo message="The new Eclipse update site is created in:" />
    <echo message="${basedir}/build/eclipse/freemarker" />
    <echo message="You can use this directory as a local update site in Eclipse," />
    <echo message="or if you are an admin who makes a release, you should replace" />
    <echo message="http://freemarker.org/eclipse/freemarker with this directory." />
    <echo message="**************************************************************" />
  </target>
  
  
  <!-- ================================================================== -->
  <!-- Dependency management (keep it exactly identical for all projects) -->
  <!-- ================================================================== -->
  
  <target name="_autoget-deps" unless="deps.available">
    <antcall target="update-deps" />
  </target>
  
  <target name="update-deps"
    description="Gets the latest version of the dependencies from the Web"
  >
    <echo>Getting dependencies...</echo>
    <echo>-------------------------------------------------------</echo>
    <ivy:settings id="remote" url="http://freemarker.org/repos/ivy/ivysettings-remote.xml" />
    <!-- Build an own repository that will serve us even offline: -->
    <ivy:retrieve settingsRef="remote" sync="true"
      ivypattern=".ivy.part/repo/[organisation]/[module]/ivy-[revision].xml"
      pattern=".ivy.part/repo/[organisation]/[module]/[artifact]-[revision].[ext]"
    />
    <echo>-------------------------------------------------------</echo>
    <echo>*** Successfully acquired dependencies from the Web ***</echo>
    <echo>Eclipse users: Now right-click on ivy.xml and Resolve! </echo>
    <echo>-------------------------------------------------------</echo>
    <!-- Only now that we got all the dependencies will we delete anything. -->
    <!-- Thus a net or repo outage doesn't left us without the dependencies. -->

    <!-- Save the resolution cache from the soon coming <delete>: -->
    <move todir=".ivy.part/update-deps-reso-cache">
      <fileset dir=".ivy/update-deps-reso-cache" />
    </move>
    <!-- Drop all the old stuff: -->
    <delete dir=".ivy" />
    <!-- And use the new stuff instead: -->
    <move todir=".ivy">
      <fileset dir=".ivy.part" />
    </move>
  </target>

  <!-- Do NOT call this from 'clean'; offline guys would stuck after that. -->
  <target name="clean-deps"
    description="Deletes all dependencies"
  >
    <delete dir=".ivy" />
  </target>

  <target name="publish-override" depends="jar"
    description="Ivy-publishes THIS project locally as an override"
  >
    <ivy:resolve />
    <ivy:publish
      pubrevision="${moduleBranch}-branch-head"
      artifactspattern="build/[artifact].[ext]"
      overwrite="true" forcedeliver="true"
      resolver="freemarker-devel-local-override"
    >
      <artifact name="freemarker" type="jar" ext="jar" />
    </ivy:publish>
    <delete file="build/ivy.xml" />  <!-- ivy:publish makes this -->
    <echo>-------------------------------------------------------</echo>
    <echo>*** Don't forget to `ant unpublish-override` later! ***</echo>
  </target>

  <target name="unpublish-override"
    description="Undoes publish-override (made in THIS project)"
  >
    <delete dir="${user.home}/.ivy2/freemarker-devel-local-override/${moduleOrg}/${moduleName}" />
    <delete dir="${user.home}/.ivy2/freemarker-devel-local-override-cache/${moduleOrg}/${moduleName}" />
  </target>  

  <target name="unpublish-override-all"
    description="Undoes publish-override-s made in ALL projects"
  >
    <delete dir="${user.home}/.ivy2/freemarker-devel-local-override" />
    <delete dir="${user.home}/.ivy2/freemarker-devel-local-override-cache" />
  </target>  

  <target name="uninstall"
    description="Deletes external files created by FreeMarker developement"
  >
    <delete dir="${user.home}/.ivy2/freemarker-devel-cache" />
    <delete dir="${user.home}/.ivy2/freemarker-devel-local-override" />
    <delete dir="${user.home}/.ivy2/freemarker-devel-local-override-cache " />
  </target>

  <target name="report-deps"
    description="Creates a HTML document that summarizes the dependencies."
  >
    <mkdir dir="build/deps-report" />
    <ivy:resolve />
    <ivy:report todir="build/deps-report" />
  </target>
  
  <target name="ide-dependencies" description="If your IDE has no Ivy support, this generates ide-lib/*.jar for it">
    <mkdir dir="ide-dependencies" />
    <delete includeEmptyDirs="true">  
      <fileset dir="ide-dependencies">  
         <include name="*/**" />  
      </fileset>  
    </delete>    
    <ivy:retrieve conf="IDE" pattern="ide-dependencies/[artifact]-[revision].[ext]" />
  </target>
  
  <!--
    This meant to be called on the Continuous Integration server, so the
    integration builds appear in the freemarker.org public Ivy repository.
    The artifacts must be already built.
  -->
  <target name="server-publish-last-build"
    description="(For the Continuous Integration server only)"
  >
    <delete dir="build/dummy-server-ivy-repo" />
    <ivy:resolve />
    <ivy:publish
      pubrevision="${moduleBranch}-branch-head"
      artifactspattern="build/[artifact].[ext]"
      overwrite="true" forcedeliver="true"
      resolver="server-publishing-target"
    >
      <artifact name="freemarker" type="jar" ext="jar" />
    </ivy:publish>
    <delete file="build/ivy.xml" />  <!-- ivy:publish makes this -->
  </target>

  <target name="archive" depends=""
    description='Archives project with Git repo into the "archive" directory.'
  >
    <mkdir dir="archive" />
    <tstamp>
      <format property="tstamp" pattern="yyyyMMdd-HHmm" />
    </tstamp>
    <delete file="archive/freemarker-git-${tstamp}.tar" />
    <delete file="archive/freemarker-git-${tstamp}.tar.bz2" />
    <tar tarfile="archive/freemarker-git-${tstamp}.tar"
      basedir="."
      longfile="gnu"
      excludes="build/** .build/** .bin/** .ivy/**  archive/**"
    />
    <bzip2 src="archive/freemarker-git-${tstamp}.tar"
        zipfile="archive/freemarker-git-${tstamp}.tar.bz2" />
    <delete file="archive/freemarker-git-${tstamp}.tar" />
  </target>
    
</project>
