Nant SVN changes between two revisions checkout

I went looking for a nant script to checkout changed files between two revisions from SVN. I found some Ant / Java based solutions. As we are using nant I figured I would give it a shot writing it myself. It is easy to get a list of files from SVN using diff. However that doesn’t do you any good if you need to get them from SVN by hand one by one. The trick is to use the list you get from SVN diff and then loop each file and bring it down to the local machine. The biggest gotcha was of course space in file or directory names. If you notice in the script that’s taken care of by inserting %20 in the URL location and local file names are quoted with double quote when doing the SVN export. List of deleted files are written to deletedfiles.txt in the checkout directory, Enjoy !

<?xml version=“1.0”?>
<!–
  Exports changes between revision from the given repository URL to checkout Directory
–>
<project name=“SVN_changes”
   default=“getChanges”
   basedir=“.”>

  <!–
   Register the sys.* properties; most specifically, sys.env.* for all environment vars
  –>
  <sysinfo/>

  <!– Properties / defaults –>
  <property name=“checkoutDir” value=“svnchanges”/>
  <property name=“changelog” value=“${checkoutDir}\changelog.txt”/>
  <property name=“delLog” value=“${checkoutDir}\deletedfiles.txt”/>
  <property name=“delFile” value=“”/>
  <property name=“deleteIndicator” value=“D      “/>

  <!– url to svn repository –>
  <property name=“repoURL” value=“http://10.10.10.10/svn/myproject/trunk”/>
  <property name=“repoUser” value=“testUser” dynamic=“true” />
  <property name=“repoPassword” value=“testPassword” dynamic=“true” />
  <property name=“startingRevision” value=“29455” />
  <property name=“endingRevision” value=“30692” />

  <target name=“getChanges” description=“Get changes from Subversion given two revisions “  >

    <echo message=“Exporting files between revisions ${startingRevision} and ${endingRevision}” />
    <echo message=“from ${repoURL}” />
    <echo message=“to ${checkoutDir}/” />
    <echo message=“——-“ />
    <echo message=“stand by….. “ />
    <echo message=“——-“ />

    <!– Start with a fresh local checkout directory –>
    <mkdir dir=“${checkoutDir}” />

    <!– creates log file comparison from start to end revision –>
    <exec program=“svn”
      commandline=“diff -r ${startingRevision}:${endingRevision} –summarize ${repoURL}”
      output=“${changelog}” />

    <!– Loop the files in the changelog and process –>
    <foreach item=“Line” in=“${changelog}” delim=“,” property=“svnfile”>

      <!– Extract the file name –>
      <property name=“startpos” value=“${string::index-of(svnfile, repoURL) +  string::get-length(repoURL) }” />
      <property name=“length” value=“${string::get-length(svnfile) – int::parse(startpos)}” />
      <property name=“tmpFile” value=“${string::substring( svnfile, startpos, length)}” />
      <!– Space in URL covered –>
      <property name=“repoFile” value=“${string::replace( tmpFile, ‘ ‘, ‘%20’)}” />
      <!– Extract the dir –>
      <property name=“endpos” value=“${string::last-index-of( tmpFile, ‘/’)}” />
      <property name=“localDir” value=“${string::substring( tmpFile, 0, int::parse(endpos))}” />

      <!– Sep –>
      <echo message=“—“/>
     
      <!– Advertise deleted files between revisions –>
      <if test=“${ string::contains(svnfile, deleteIndicator)}”>
          <echo message=“Deleted file=${tmpFile}”/>
          <property name=“delFile” value=“${tmpFile}”/>
          <call target=“WriteToTextFile” />
      </if>

      <!– Files to bring down from repository  –>
      <if test=“${ not string::contains(svnfile, deleteIndicator)}”>
          <!–
            Create the dir before checkout, this might happen multible times
            for files in the same dir, don‘t fail it.
          –>
          <mkdir dir="${checkoutDir}${localDir}" failonerror="false"/>
       
          <!– Check out the file –>
          <echo message="svn export ${repoURL}${repoFile} &quot;${checkoutDir}${tmpFile}&quot; -r ${endingRevision} –force " />
          <exec program="svn"
                commandline="export ${repoURL}${repoFile} &quot;${checkoutDir}${tmpFile}&quot; -r ${endingRevision} –force"
                            failonerror="true"
          />
      </if>
    </foreach>

    <!– Show user that it’s all done –>
    <echo message=”   “ />
    <echo message=“——-“ />
    <echo message=“Changed and new files have been exported to the ${checkoutDir} directory” />
    <echo message=“List of deleted files can be found in the ${delLog} file” />
    <echo message=“——-“ />
    <echo message=“Done !” />
  </target>

  <!– Appends deleted files to text file –>
  <target name=“WriteToTextFile” >
    <script language=“C#” mainclass=“writeToDelLog”>
      <references>
        <include name=“System.Management.dll” />
      </references>
      <div class=“codesnip-container” ><![CDATA[
            class writeToDelLog
            {       
                public static void ScriptMain(Project project)
                {       
                                      PropertyDictionary pd = project.Properties;       
                    string sDeletedFile = pd[“delLog”];
                    string sDeletedEntry = pd[“delFile”];
                   
                    FileStream stream = new FileStream(sDeletedFile, FileMode.Append );
                    StreamWriter writer = new StreamWriter(stream);

                    try
                    {
                      writer.WriteLine(sDeletedEntry);
                    }
                    catch( Exception ex )
                    {
                      Console.WriteLine( “NOT able to write to file, error=” + ex );
                    }
                    finally
                    {
                      if( writer != null ) writer.Close();
                      if( stream != null ) stream.Close();
                    }
                           
                }
            }
        ]]></div>
    </script>
  </target>

</project>

Leave a Reply