<?xml version="1.0"?>
<project name="TortoiseSVN" default="help">

  <property name="signtool" value="signtool.exe" />
  <!-- default configuration is release -->
  <property name="configuration" value="release" />
  <!-- default builds are dev builds -->
  <property name="devrelease" value="-dev" unless="${property::exists('devrelease')}" />
  <!-- default build for win32 platform -->
  <property name="platform" value="win32" />
  <!-- default: don't add a platform specific extension
       to the bin folders 'release' / 'debug'   -->
  <property name="bindirextension" value="" />
  <!-- default: we don't cross-compile -->
  <property name="crosscompile" value="" />
  <!-- default: we don't clean first -->
  <property name="cleanup" value="" />
  <!-- default: we build with openssl support -->
  <property name="skipssl" value="" />
  <!-- default: we build in a user session -->
  <property name="schedule" value="no" />
  <!-- the ${subsystem} to use -->
  <property name="subsystem" value="/SUBSYSTEM:WINDOWS" />
  <property name="subsystemcl" value="/SUBSYSTEM:CONSOLE" />
  <!-- default to asm-optimized OpenSSL build -->
  <property name="no-asm" value="no" />
  
  <!-- make sure the user config file exists -->
  <property name="userconfigfile"
            value="default.build.user" />
  <property name="userconfigtemplate"
            value="${userconfigfile}.tmpl" />
  <if test="${not file::exists(userconfigfile)}">
    <echo level="Warning">
      The file ${userconfigfile} is missing. We will auto-create it
      from the ${userconfigtemplate} file. Please consider adapting
      it to your needs.
    </echo>
    <copy file="${userconfigtemplate}"
          tofile="${userconfigfile}" />
  </if>

  <include buildfile="default.build.user" />

  <!-- the signinfo.txt file has to contain one line with parameters for signtool.exe,
       for example:
       /t "url/to/timestamp/server" /q
  -->
  <loadfile file="signinfo.txt" property="signinfo" failonerror="false" if="${file::exists('signinfo.txt')}" />

  <!-- ====================================================================== -->
  <!-- Configuration targets                                                  -->
  <!-- ====================================================================== -->
  <target name="debug">
    <description>
      Sets the environment up to build the debug versions.
    </description>
    <property name="configuration" value="debug" />
  </target>

  <target name="release">
    <description>
      Sets the environment up to build an official release version,
      without the '-dev' markers.
    </description>
    <property name="devrelease" value="" />
  </target>

  <target name="x64">
    <description>
      Compiles everything for the win64 platform.
    </description>
    <property name="platform" value="x64" />
    <property name="bindirextension" value="64" />
    <property name="subsystem" value="/SUBSYSTEM:WINDOWS" />
    <property name="subsystemcl" value="/SUBSYSTEM:CONSOLE" />
  </target>
  <target name="ARM64">
    <description>
      Compiles everything for the ARM64 platform.
    </description>
    <property name="platform" value="ARM64" />
    <property name="bindirextension" value="ARM64" />
    <property name="subsystem" value="/SUBSYSTEM:WINDOWS" />
    <property name="subsystemcl" value="/SUBSYSTEM:CONSOLE" />
  </target>

  <target name="cross">
    <description>
      Cross-compiles for a different platform.
    </description>
    <property name="crosscompile" value="yes" if="${platform == 'ARM64'}" />
    <echo message="ignore cross-compiling (only supported for ARM64)" level="Warning" if="${platform != 'ARM64'}" />
  </target>

  <target name="skipssl">
    <description>
      skips the building of openssl
    </description>
    <property name="skipssl" value="yes" />
  </target>

  <target name="no-asm">
    <description>
      compile openssl without assembler code (see ext/openssl/INSTALL.md#no-asm).
    </description>
    <property name="no-asm" value="yes" />
  </target>

  <target name="schedule">
    <description>
      run this task if the whole build is done via task scheduler
    </description>
    <property name="schedule" value="yes" />
    <echo message="trying to fix nightly builds..." level="Warning" />
    <exec program="svn.exe" verbose="true">
      <arg value="resolve" />
      <arg value="-R" />
      <arg value="--accept" />
      <arg value="r" />
      <arg value="." />
    </exec>
    <exec program="svn.exe" verbose="true">
      <arg value="revert" />
      <arg value="-R" />
      <arg value="." />
    </exec>
    <exec program="svn.exe" verbose="true">
      <arg value="up" />
      <arg value="." />
    </exec>
  </target>
  <!-- ====================================================================== -->
  <!-- Project targets                                                        -->
  <!-- ====================================================================== -->

  <target name="clean" depends="VSNET">
    <description>
      Cleans before building the target
    </description>
    <property name="cleanup" value="yes" />
  </target>

  <target name="cleanall" depends="VSNET">
    <description>
      Cleans every subproject.
    </description>
    <property name="cleanup" value="yes" />
    <nant target="clean">
      <buildfiles>
        <include name="doc\doc.build" />
        <include name="src\TortoiseSVN.build" />
        <include name="ext\build\OpenSSL.build" />
        <include name="ext\build\default.build" />
        <include name="Languages\LanguagePack.build" />
      </buildfiles>
    </nant>
  </target>

  <target name="docs" depends="VSNET,env,VersionInfo">
    <description>
      Builds the docs in all languages and all formats.
    </description>
    <nant target="all">
      <buildfiles>
        <include name="doc\doc.build" />
      </buildfiles>
    </nant>
    <if test="${devrelease != '-dev'}">
      <move todir="upload\${environment::get-variable('MajorVersion')}.${environment::get-variable('MinorVersion')}.${environment::get-variable('MicroVersion')}\Documentation">
        <fileset basedir="doc\output">
          <include name="*.pdf" />
        </fileset>
      </move>
    </if>
  </target>

  <target name="APIDocs" depends="env">
    <description>
      Builds the API docs from the comments in the sourcecode
    </description>
    <nant target="apidoc">
      <buildfiles>
        <include name="doc\doc.build" />
      </buildfiles>
    </nant>
  </target>

  <target name="VersionInfo" depends="VSNET,env">
    <description>
      Sets the version information as properties, env variables
      and sets up the different version specific files.
    </description>
    <nant target="versioninfo">
      <buildfiles>
        <include name="src\TortoiseSVN.build" />
      </buildfiles>
    </nant>
  </target>

  <target name="Overlays" depends="VSNET,env">
    <description>
      Builds the TortoiseOverlays install files
    </description>
    <nant target="all">
      <buildfiles>
        <include name="src\TortoiseOverlays\TortoiseOverlays.build" />
      </buildfiles>
    </nant>
  </target>

  <target name="Subversion" depends="VSNET,env">
    <description>
      Builds all the libraries TortoiseSVN depends on:
      Subversion, apr, OpenSSL, ...
    </description>
    <nant target="OpenSSL" if="${skipssl != 'yes'}">
      <buildfiles>
        <include name="ext\build\OpenSSL.build" />
      </buildfiles>
    </nant>
    <nant target="build">
      <buildfiles>
        <include name="ext\build\default.build" />
      </buildfiles>
    </nant>
  </target>

  <target name="SubversionOnly" depends="VSNET,env">
    <description>
      Builds only the Subversion libraries
    </description>
    <nant target="build">
      <buildfiles>
        <include name="ext\build\subversion.build" />
      </buildfiles>
    </nant>
  </target>

  <target name="TortoiseSVN" depends="VSNET,env,editorconfig">
    <description>
      Builds TortoiseSVN. The libraries must have been built
      before.
    </description>
    <nant target="TortoiseSVN">
      <buildfiles>
        <include name="src\TortoiseSVN.build" />
      </buildfiles>
    </nant>
  </target>

  <target name="editorconfig" depends="VSNET,env">
    <description>
      Builds editorconfig. The library must have been built
      before TortoiseMerge.
    </description>
    <nant target="build">
      <buildfiles>
        <include name="ext\build\editorconfig.build" />
      </buildfiles>
    </nant>
  </target>

  <target name="binaries" depends="VSNET,env,Subversion,TortoiseSVN">
    <description>
      Builds all binaries (TortoiseSVN with all the required
      libraries)
    </description>
  </target>

  <target name="setup" depends="env,binaries,docs,LanguagePacks,changelog">
    <description>
      Uses WiX to create an msi installer file.
    </description>
    <if test="${devrelease != '-dev'}">
      <call target="uploadsymbols" />
    </if>
    <nant target="setup">
      <buildfiles>
        <include name="src\TortoiseSVNSetup\setup.build" />
      </buildfiles>
    </nant>
  </target>

  <target name="LanguagePacks" depends="env,VersionInfo">
    <description>
      Builds all the language pack installers.
    </description>
    <nant target="all">
      <buildfiles>
        <include name="Languages\LanguagePack.build" />
      </buildfiles>
    </nant>
    <if test="${devrelease != '-dev'}">
      <move todir="upload\${environment::get-variable('MajorVersion')}.${environment::get-variable('MinorVersion')}.${environment::get-variable('MicroVersion')}\Language Packs">
        <fileset basedir="bin">
          <include name="LanguagePack*.msi" />
        </fileset>
      </move>
    </if>
  </target>

  <target name="msi" depends="env,VersionInfo">
    <description>
      Builds the msi installer from already built binaries.
    </description>
    <if test="${devrelease != '-dev'}">
      <call target="uploadsymbols" />
      <call target="changelog" />
    </if>
    <nant target="setup">
      <buildfiles>
        <include name="src\TortoiseSVNSetup\setup.build" />
      </buildfiles>
    </nant>
    <if test="${devrelease != '-dev'}">
      <property name="verstring" value="${environment::get-variable('MajorVersion')}.${environment::get-variable('MinorVersion')}.${environment::get-variable('MicroVersion')}.${environment::get-variable('WCREV')}" />
      <property name="svnverstring" value="${environment::get-variable('SVNMajorVersion')}.${environment::get-variable('SVNMinorVersion')}.${environment::get-variable('SVNMicroVersion')}" />
      <mkdir dir="upload\${environment::get-variable('MajorVersion')}.${environment::get-variable('MinorVersion')}.${environment::get-variable('MicroVersion')}\Application" />
      <property name="msifilename" value="TortoiseSVN-${verstring}${devrelease}-${platform}-svn-${svnverstring}" />
      <move file="bin\${msifilename}.msi" tofile="upload\${environment::get-variable('MajorVersion')}.${environment::get-variable('MinorVersion')}.${environment::get-variable('MicroVersion')}\Application\${msifilename}.msi" />
    </if>
  </target>

  <target name="tabspace" depends="env">
    <description>
      Runs the tabspace utility on our source files, including the doc xml files
    </description>
    <foreach item="Folder" property="foldername">
      <in>
        <items>
          <include name="src" />
          <include name="doc\source\en" />
          <include name="contrib\diff-scripts" />
          <include name="contrib\hook-scripts" />
        </items>
      </in>
      <do>
        <echo message="tabspace for folder ${foldername}" />
        <exec program="tabspace${bindirextension}.exe">
          <arg value="/path:${foldername}" />
          <!-- include all our own files -->
          <arg value="/ext:c;cc;cpp;cs;cxx;h;hpp;hxx;build;txt;in;wxs;wxi;def;rc2;bat;js;vbs;idl;tmpl;sh" />
          <!-- exclude generated source files -->
          <arg value="/exclude:resource.h;dlldata.c;IBugTraqProvider_h.h;IBugTraqProvider_i.c;IBugTraqProvider_p.c;SubWCRevCOM_h.h;SubWCRevCOM_i.c" />
        </exec>
      </do>
    </foreach>
  </target>

  <target name="MakeRelease" depends="VSNET,env,clean,setup">
    <description>
      executes all Nant targets required for a release.
    </description>
  </target>

  <target name="uploadsymbols" depends="env,VersionInfo">
    <description>
      Uploads all the debug symbols and binaries to the crash report
      server https://drdump.com
    </description>
    <property name="verstring" value="${environment::get-variable('MajorVersion')}.${environment::get-variable('MinorVersion')}.${environment::get-variable('MicroVersion')}.${environment::get-variable('WCREV')}" />
    <property name="platformfoldername" value=""   if="${platform == 'win32'}" />
    <property name="platformfoldername" value="64" if="${platform == 'x64'}" />
    <property name="platformfoldername" value="ARM64" if="${platform == 'ARM64'}" />

    <exec program="${environment::get-variable('DEBUGTOOLS')}\srcsrv\svnindex.cmd">
      <arg value="/debug" />
      <arg value="/symbols=bin\${configuration}${platformfoldername}\bin\" />
      <arg value="/source=.;ext\apr;ext\apr-util;ext\subversion" />
    </exec>
    <if test="${platform != 'ARM64'}">
      <trycatch>
        <try>
          <exec program="ext\CrashServer\SymUpload.exe">
            <arg value="-publish" />
            <arg value="-noprogress" />
            <arg value="71040f62-f78a-4953-b5b3-5c148349fed7" />
            <arg value="${verstring}" />
            <arg value="0" />
            <arg value="bin\${configuration}${platformfoldername}\bin\*.exe" />
          </exec>
        </try>
        <catch>
          <sleep minutes="5" />
          <trycatch>
            <try>
              <exec program="ext\CrashServer\SymUpload.exe">
                <arg value="-publish" />
                <arg value="-noprogress" />
                <arg value="71040f62-f78a-4953-b5b3-5c148349fed7" />
                <arg value="${verstring}" />
                <arg value="0" />
                <arg value="bin\${configuration}${platformfoldername}\bin\*.exe" />
              </exec>
            </try>
            <catch>
              <sleep minutes="5" />
              <trycatch>
                <try>
                  <exec program="ext\CrashServer\SymUpload.exe">
                    <arg value="-publish" />
                    <arg value="-noprogress" />
                    <arg value="71040f62-f78a-4953-b5b3-5c148349fed7" />
                    <arg value="${verstring}" />
                    <arg value="0" />
                    <arg value="bin\${configuration}${platformfoldername}\bin\*.exe" />
                  </exec>
                </try>
                <catch>
                  <sleep minutes="5" />
                  <trycatch>
                    <try>
                      <exec program="ext\CrashServer\SymUpload.exe">
                        <arg value="-publish" />
                        <arg value="-noprogress" />
                        <arg value="71040f62-f78a-4953-b5b3-5c148349fed7" />
                        <arg value="${verstring}" />
                        <arg value="0" />
                        <arg value="bin\${configuration}${platformfoldername}\bin\*.exe" />
                      </exec>
                    </try>
                    <catch>
                      <echo message="Symbol-upload failed!" level="Warning" />
                    </catch>
                  </trycatch>
                </catch>
              </trycatch>
            </catch>
          </trycatch>
        </catch>
      </trycatch>
      
      <trycatch>
        <try>
          <exec program="ext\CrashServer\SymUpload.exe">
            <arg value="-publish" />
            <arg value="-noprogress" />
            <arg value="71040f62-f78a-4953-b5b3-5c148349fed7" />
            <arg value="${verstring}" />
            <arg value="0" />
            <arg value="bin\${configuration}${platformfoldername}\bin\*.dll" />
          </exec>
        </try>
        <catch>
          <sleep minutes="5" />
          <trycatch>
            <try>
              <exec program="ext\CrashServer\SymUpload.exe">
                <arg value="-publish" />
                <arg value="-noprogress" />
                <arg value="71040f62-f78a-4953-b5b3-5c148349fed7" />
                <arg value="${verstring}" />
                <arg value="0" />
                <arg value="bin\${configuration}${platformfoldername}\bin\*.dll" />
              </exec>
            </try>
            <catch>
              <sleep minutes="5" />
              <trycatch>
                <try>
                  <exec program="ext\CrashServer\SymUpload.exe">
                    <arg value="-publish" />
                    <arg value="-noprogress" />
                    <arg value="71040f62-f78a-4953-b5b3-5c148349fed7" />
                    <arg value="${verstring}" />
                    <arg value="0" />
                    <arg value="bin\${configuration}${platformfoldername}\bin\*.dll" />
                  </exec>
                </try>
                <catch>
                  <sleep minutes="5" />
                  <trycatch>
                    <try>
                      <exec program="ext\CrashServer\SymUpload.exe">
                        <arg value="-publish" />
                        <arg value="-noprogress" />
                        <arg value="71040f62-f78a-4953-b5b3-5c148349fed7" />
                        <arg value="${verstring}" />
                        <arg value="0" />
                        <arg value="bin\${configuration}${platformfoldername}\bin\*.dll" />
                      </exec>
                    </try>
                    <catch>
                      <echo message="Symbol-upload failed!" level="Warning" />
                    </catch>
                  </trycatch>
                </catch>
              </trycatch>
            </catch>
          </trycatch>
        </catch>
      </trycatch>
    </if>
  </target>

  <target name="init" depends="VSNET,env">
    <description>
      Initializes the build, fetches the tools if not already available
    </description>
    <if test="${not file::exists(userconfigfile)}">
      <echo>
        The file ${userconfigfile} is missing. We will auto-create it
        from the ${userconfigtemplate} file. Please consider adapting
        it to your needs.
      </echo>
      <copy file="${userconfigtemplate}" tofile="${userconfigfile}" />
    </if>

    <if test="${not directory::exists('Tools') or not file::exists('Tools/ver-1.8.0')}">
      <get src="https://downloads.sourceforge.net/project/tortoisesvn/build%20tools/Tools-1.8.0.zip" dest="tools.zip" />
      <unzip zipfile="tools.zip" />
      <touch file="Tools\ver-1.8.0" />
      <delete file="tools.zip" />
    </if>
  </target>

  <target name="changelog" depends="VSNET,env,VersionInfo">
    <description>
      Creates an md file (markdown) from the changelog file
    </description>

    <!-- do regex replace to get the markdown output -->
    <script language="C#">
      <code>
        <![CDATA[
          public static void ScriptMain(Project project)
          {
            StreamReader reader = new StreamReader( @"src\Changelog.txt" );
            string content = reader.ReadToEnd();
            reader.Close();

            string header = @"![TortoiseSVN logo](https://svn.code.sf.net/p/tortoisesvn/code/trunk/doc/logo/tortoisesvn_logo_hor468x64.png)

Make sure to also check the [changelog of Subversion](https://svn.apache.org/repos/asf/subversion/trunk/CHANGES).

";
            // remove older entries
            content = Regex.Replace( content, "(Version 1\\.6\\.17.+)", "", RegexOptions.Singleline );
            // add header with logo
            content = header + content;
            // format version titles as headings
            content = Regex.Replace( content, "(Version [^\\r\\n]*)", "### $0 ###" );
            // convert my name to links
            content = Regex.Replace( content, "\\(Stefan\\)", "[(Stefan)](https://tortoisesvn.net/stefan_kueng.html)" );
            // convert the link to the release notes to markdown links
            content = Regex.Replace( content, "https://tortoisesvn.net/tsvn_(1\\.\\d+)_releasenotes.html", "[https://tortoisesvn.net/tsvn\\\\_$1\\\\_releasenotes.html](https://tortoisesvn.net/tsvn_$1_releasenotes.html)" );

            // save the file as README.md so sourceforge recognizes it
            StreamWriter writer = new StreamWriter( @"bin\README.md" );
            writer.Write( content );
            writer.Close();
          }
        ]]>
      </code>
      <references>
        <include name="System.dll" />
        <include name="System.Xml.dll" />
      </references>
      <imports>
        <import namespace="System.Text.RegularExpressions" />
        <import namespace="System.Xml" />
        <import namespace="System.Xml.XPath" />
      </imports>
    </script>
    <if test="${devrelease != '-dev'}">
      <copy file="bin\README.md" tofile="upload\${environment::get-variable('MajorVersion')}.${environment::get-variable('MinorVersion')}.${environment::get-variable('MicroVersion')}\README.md" />
    </if>
  </target>

  <target name="chocolatey" depends="env, VersionInfo">
    <loadfile file="contrib\choco\tortoisesvn.nuspec" property="nuspecfile">
      <filterchain>
        <replacetokens begintoken="$" endtoken="$">
          <token key="MajorVersion" value="${environment::get-variable('MajorVersion')}" />
          <token key="MinorVersion" value="${environment::get-variable('MinorVersion')}" />
          <token key="MicroVersion" value="${environment::get-variable('Microversion')}" />
          <token key="WCREV" value="${environment::get-variable('WCREV')}" />
          <token key="WCDATE" value="${environment::get-variable('WCDATE')}" />
          <token key="SVNMajorVersion" value="${environment::get-variable('SVNMajorVersion')}" />
          <token key="SVNMinorVersion" value="${environment::get-variable('SVNMinorVersion')}" />
          <token key="SVNMicroVersion" value="${environment::get-variable('SVNMicroversion')}" />
        </replacetokens>
      </filterchain>
    </loadfile>
    <echo file="contrib\choco\package\tortoisesvn.nuspec" message="${nuspecfile}" />

    <loadfile file="contrib\choco\chocolateyInstall.ps1" property="cinstfile">
      <filterchain>
        <replacetokens begintoken="$" endtoken="$">
          <token key="MajorVersion" value="${environment::get-variable('MajorVersion')}" />
          <token key="MinorVersion" value="${environment::get-variable('MinorVersion')}" />
          <token key="MicroVersion" value="${environment::get-variable('Microversion')}" />
          <token key="WCREV" value="${environment::get-variable('WCREV')}" />
          <token key="WCDATE" value="${environment::get-variable('WCDATE')}" />
          <token key="SVNMajorVersion" value="${environment::get-variable('SVNMajorVersion')}" />
          <token key="SVNMinorVersion" value="${environment::get-variable('SVNMinorVersion')}" />
          <token key="SVNMicroVersion" value="${environment::get-variable('SVNMicroversion')}" />
        </replacetokens>
      </filterchain>
    </loadfile>
    <echo file="contrib\choco\package\tools\chocolateyInstall.ps1" message="${cinstfile}" />
    <copy file="contrib\choco\install.ps1" tofile="contrib\choco\package\tools\install.ps1" />
    <echo>
      now start an admin console in contrib\choco\package and then run
      choco pack
      to upload the package, run
      cpush TortoiseSVN-x.x.x.nupkg
    </echo>
  </target>
  
  <target name="ipv6" />	<!-- deprecated, only here so old build scripts won't fail -->

  <!-- ====================================================================== -->
  <!-- Help target                                                            -->
  <!-- ====================================================================== -->
  <target name="help">
    <!-- note: use spaces in the help text below! Otherwise the output won't be aligned in the console. -->
    <echo message="You must specify a target to tell us what you want to build!" />
    <echo />
    <echo message="The following targets are available:" />
    <echo message="init         : initializes the build tools if required" />
    <echo message="binaries     : builds all binaries (TortoiseSVN, Subversion, Libs)" />
    <echo message="setup        : creates an msi installer for TortoiseSVN" />
    <echo />
    <echo message="cleanall     : clean every subproject" />
    <echo message="docs	        : builds the docs in all languages and all formats" />
    <echo message="APIDocs      : Builds the API docs from the sourcecode comments" />
    <echo message="Subversion   : builds the Subversion libraries, including its" />
    <echo message="               dependencies" />
    <echo message="TortoiseSVN  : builds TortoiseSVN. You must have built the" />
    <echo message="               Subversion libraries before, or this will fail" />
    <echo message="LanguagePacks: creates the Languagepack installers" />
    <echo message="msi          : creates the msi, but doesn't build the libs first" />
    <echo message="Overlays     : builds the TortoiseOverlays module" />
    <echo message="tabspace     : cleans the code and documents up replacing tabs with spaces" />
    <echo />
    <echo message="The following targets can be used to tweak the builds:" />
    <echo message="clean    : clean those targets which are built next" />
    <echo message="debug    : if this target is called before other build targets," />
    <echo message="           those targets are built with debug support" />
    <echo message="release  : call this if you want to create official releases." />
    <echo message="           It removes the '-dev' string from some builds" />
    <echo message="x64      : call this if you want to create native 64 bit builds." />
    <echo message="           (AMD64/EM64T only -- will not work on Itanium systems.)" />
    <echo message="cross    : cross-compile for the given target platform." />
    <echo message="           (currently only available with ARM64.)" />
    <echo message="no-asm   : don't use assembler optimized code in OpenSSL" />

    <echo />
    <echo message="Please specify the configuration targets BEFORE the main target." />
    <echo message="Examples:" />
    <echo />
    <echo message="nant debug clean binaries" />
    <echo message="nant release setup" />
    <echo message="nant -v x64 debug binaries" />
    <echo message="nant cross ARM64 setup" />
    <echo />
    <echo message="Remember to use the correct Visual Studio command prompt environment for your" />
    <echo message="target [x64, ARM64, default x86] each build with different Visual Studio command prompts!" />
    <echo />
  </target>
</project>
