RSS Feed of SVN Changelog

  • joebert
  • Genius
  • Genius
  • User avatar
  • Posts: 13511
  • Loc: Florida

Post 3+ Months Ago

I'm going to start making my SVN log available to the public and I'm looking for ideas.

The SVN server is here at home, and the public website is hosted at a remote location. What I'm thinking about doing is setting up a cron job / script that starts by exporting the SVN log.

Code: [ Select ]
$ svn log > changelog.log

I want to make the entire log available for those who want it, but not as an RSS feed. So after exporting the log, I'm thinking I'll gzip it right away. I don't want to direct the output from the log dump directly through tar because I want to open the dump and work with it.

Code: [ Select ]
$ tar --gzip -cf changelog.tar.gz changelog.log

Next I'm thinking I'll parse changelog.log until I have the last 10 revisions stored in an array. Once I have that, I can generate an RSS feed and save that as changelog.xml and once I have changelog.tar.gz and changelog.xml I can SCP them to the public server before deleting changelog.log

Before I write something to do this parsing, I figured it's worth seeing if anyone has something like this already, or perhaps a better idea. :)
  • joebert
  • Genius
  • Genius
  • User avatar
  • Posts: 13511
  • Loc: Florida

Post 3+ Months Ago

I came across this blog post, from September of 2006 and it looks like it's fairly easy to export the log in XML format and transform it with XSL.

Apparently the author's link to the xslt is dead. Luckily a comment from March 2009 had a working link where I was able to get the xslt.

For the most part, it worked right out of the box. Some of the HTML used in the xslt is a little dated though so I did a few tiny cleanups. For instance I switched from a <table> for listing altered files to a <ul> with <abbr> used for the actions instead of spelling them out.

At the moment I'm using the following command to export the last 10 revisions from the SVN log, the "-v" switch can be removed when the list of altered files isn't wanted.

Code: [ Select ]
$ svn -v --xml --limit 10 log svn+ssh://localhost/path/to/repo > /path/to/log.xml

The blog post has an example for a Windows system, but since my SVN server is on a Linux server and that's where the cron job will be running, I have this for doing the transform.

Code: [ Select ]
$ xsltproc /path/to/svnlog.xslt /path/to/log.xml > /path/to/changelog.xml

From here I can either also export my full gzipped log then rsync the directory with the remote server, or take the time to pipe everything around so I can avoid intermediary files. I'll get to that later, but I have a feeling I'm going to go with rsync.

Here's my updated version of svnlog.xslt

XML Code: [ Select ]
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="" xmlns:date="" xmlns:func="" xmlns:str="" extension-element-prefixes="date func str" version="1.0">
   <xsl:output omit-xml-declaration="no" indent="yes" encoding="UTF-8" method="xml" />    
   <xsl:template match="log">
     <rss version="2.0">
            <title>RSS Feed Title</title>
            <description>RSS Description</description>
            <copyright>Compant Name</copyright>
            <xsl:apply-templates select="logentry" />
   <xsl:template match="logentry">
         <title>Revision <xsl:value-of select="@revision"/></title>
         <pubDate><xsl:call-template name="rfc822"><xsl:with-param name="isodate" select="date" /></xsl:call-template></pubDate>
         <author><xsl:value-of select="author" /></author>
         <description disable-output-escaping="yes">
            &lt;pre&gt;<xsl:value-of select="msg" />&lt;/pre&gt;
            &lt;ul style="font-size:small;"&gt;<xsl:apply-templates select="paths/path" />&lt;/ul&gt;
   <xsl:template match="paths/path">
      &lt;li&gt;&lt;strong&gt;<xsl:call-template name="svncommand"><xsl:with-param name="command" select="@action" /></xsl:call-template>&lt;/strong&gt;&amp;nbsp;<xsl:value-of select="."/>&lt;/li&gt;
   <xsl:template name="rfc822">
      <xsl:param name="isodate" />
      <xsl:variable name="dayOfWeek" select="date:day-abbreviation($isodate)" />
      <xsl:variable name="day" select="date:day-in-month($isodate)" />
      <xsl:variable name="monthAbbr" select="date:month-abbreviation($isodate)" />
      <xsl:variable name="year" select="date:year($isodate)" />
      <xsl:variable name="hour" select="date:hour-in-day($isodate)" />
      <xsl:variable name="minute" select="date:minute-in-hour($isodate)" />
      <xsl:variable name="second" select="round(date:second-in-minute($isodate))" />
      <xsl:value-of select="$dayOfWeek" />
      <xsl:text>, </xsl:text>
      <xsl:value-of select="$day" />
      <xsl:text> </xsl:text>
      <xsl:value-of select="$monthAbbr" />
      <xsl:text> </xsl:text>
      <xsl:value-of select="$year" />
         <xsl:when test="$hour and $minute and $second">
            <xsl:text> </xsl:text>
            <xsl:value-of select="str:align($hour, '00', 'right')" />
            <xsl:value-of select="str:align($minute, '00', 'right')" />
            <xsl:value-of select="str:align($second, '00', 'right')" />
            <xsl:text> GMT</xsl:text>
            <xsl:text> 00:00:00 GMT</xsl:text>
   <xsl:template name="svncommand">
      <xsl:param name="command"/>
         <xsl:when test="$command = 'A'">&lt;abbr title="Added"&gt;A&lt;/abbr&gt;</xsl:when>
         <xsl:when test="$command = 'D'">&lt;abbr title="Deleted"&gt;D&lt;/abbr&gt;</xsl:when>
         <xsl:when test="$command = 'M'">&lt;abbr title="Modified"&gt;M&lt;/abbr&gt;</xsl:when>
svnlog.xslt by Martin Pittenauer / TheCodingMonkeys        
Web:, Mail:                              
iso->rfc822 date conversion code heavily inspired by Steven Engelhardt (
Tested with libxslt.
HTML brought up to date (Oct 2010) by Joe Kovar
  1. <?xml version="1.0"?>
  2. <xsl:stylesheet xmlns:xsl="" xmlns:date="" xmlns:func="" xmlns:str="" extension-element-prefixes="date func str" version="1.0">
  4.    <xsl:output omit-xml-declaration="no" indent="yes" encoding="UTF-8" method="xml" />    
  6.    <xsl:template match="log">
  7.      <rss version="2.0">
  8.          <channel>
  9.             <title>RSS Feed Title</title>
  10.             <link></link>
  11.             <description>RSS Description</description>
  12.             <language>en-us</language>
  13.             <copyright>Compant Name</copyright>
  14.             <xsl:apply-templates select="logentry" />
  15.          </channel>
  16.      </rss>
  17.    </xsl:template>
  19.    <xsl:template match="logentry">
  20.      <item>
  21.          <title>Revision <xsl:value-of select="@revision"/></title>
  22.          <pubDate><xsl:call-template name="rfc822"><xsl:with-param name="isodate" select="date" /></xsl:call-template></pubDate>
  23.          <author><xsl:value-of select="author" /></author>
  24.          <description disable-output-escaping="yes">
  25.             &lt;pre&gt;<xsl:value-of select="msg" />&lt;/pre&gt;
  26.             &lt;ul style="font-size:small;"&gt;<xsl:apply-templates select="paths/path" />&lt;/ul&gt;
  27.          </description>
  28.      </item>
  29.    </xsl:template>
  31.    <xsl:template match="paths/path">
  32.       &lt;li&gt;&lt;strong&gt;<xsl:call-template name="svncommand"><xsl:with-param name="command" select="@action" /></xsl:call-template>&lt;/strong&gt;&amp;nbsp;<xsl:value-of select="."/>&lt;/li&gt;
  33.    </xsl:template>
  35.    <xsl:template name="rfc822">
  36.       <xsl:param name="isodate" />
  37.       <xsl:variable name="dayOfWeek" select="date:day-abbreviation($isodate)" />
  38.       <xsl:variable name="day" select="date:day-in-month($isodate)" />
  39.       <xsl:variable name="monthAbbr" select="date:month-abbreviation($isodate)" />
  40.       <xsl:variable name="year" select="date:year($isodate)" />
  41.       <xsl:variable name="hour" select="date:hour-in-day($isodate)" />
  42.       <xsl:variable name="minute" select="date:minute-in-hour($isodate)" />
  43.       <xsl:variable name="second" select="round(date:second-in-minute($isodate))" />
  45.       <xsl:value-of select="$dayOfWeek" />
  46.       <xsl:text>, </xsl:text>
  47.       <xsl:value-of select="$day" />
  48.       <xsl:text> </xsl:text>
  49.       <xsl:value-of select="$monthAbbr" />
  50.       <xsl:text> </xsl:text>
  51.       <xsl:value-of select="$year" />
  52.       <xsl:choose>
  53.          <xsl:when test="$hour and $minute and $second">
  54.             <xsl:text> </xsl:text>
  55.             <xsl:value-of select="str:align($hour, '00', 'right')" />
  56.             <xsl:text>:</xsl:text>
  57.             <xsl:value-of select="str:align($minute, '00', 'right')" />
  58.             <xsl:text>:</xsl:text>
  59.             <xsl:value-of select="str:align($second, '00', 'right')" />
  60.             <xsl:text> GMT</xsl:text>
  61.          </xsl:when>
  62.          <xsl:otherwise>
  63.             <xsl:text> 00:00:00 GMT</xsl:text>
  64.          </xsl:otherwise>
  65.       </xsl:choose>
  66.    </xsl:template>
  68.    <xsl:template name="svncommand">
  69.       <xsl:param name="command"/>
  70.       <xsl:choose>
  71.          <xsl:when test="$command = 'A'">&lt;abbr title="Added"&gt;A&lt;/abbr&gt;</xsl:when>
  72.          <xsl:when test="$command = 'D'">&lt;abbr title="Deleted"&gt;D&lt;/abbr&gt;</xsl:when>
  73.          <xsl:when test="$command = 'M'">&lt;abbr title="Modified"&gt;M&lt;/abbr&gt;</xsl:when>
  74.       </xsl:choose>
  75.    </xsl:template>
  77. <!--
  78. svnlog.xslt by Martin Pittenauer / TheCodingMonkeys        
  79. Web:, Mail:                              
  81. iso->rfc822 date conversion code heavily inspired by Steven Engelhardt (
  82. Tested with libxslt.
  84. HTML brought up to date (Oct 2010) by Joe Kovar
  86. -->
  88. </xsl:stylesheet>
  • joebert
  • Genius
  • Genius
  • User avatar
  • Posts: 13511
  • Loc: Florida

Post 3+ Months Ago

With the stuff I learned in my last post, I've been using this little shell script for the last couple of days, letting cron execute it once a day, and it's been working just fine.

I indeed ended up going with rsync.

I've got this script in a directory along with a sub-directory called "logs" and the xslt from my last post. I end up with an "rss.xml" and an "archive.tar.gz" in the /changelogs/ directory of the remote host.

BASH Code: [ Select ]
svn -v --xml --limit 10 log "$REPO_URL" > "$XML_PATH"
xsltproc "$XSLT_PATH" "$XML_PATH" > "$RSS_PATH"
svn -v log "$REPO_URL" > "$LOG_PATH"
tar --gzip -cf "$GZ_PATH" -C "$CRON_PATH" "$LOG_NAME"
rsync -qcah --rsh="ssh -i'/path/to/.ssh/key'" "$CRON_PATH/logs/"
  1. #!/bin/bash
  3. REPO_URL="http://localhost/svn/repo"
  4. CRON_PATH="/this/files/directory"
  5. ARCHIVE_NAME="archive.tar.gz"
  6. RSS_NAME="rss.xml"
  8. XML_PATH="$CRON_PATH/svnlog.xml"
  9. XSLT_PATH="$CRON_PATH/svnlog-to-rss.xslt"
  12. LOG_NAME="changelog.log"
  15. svn -v --xml --limit 10 log "$REPO_URL" > "$XML_PATH"
  16. xsltproc "$XSLT_PATH" "$XML_PATH" > "$RSS_PATH"
  18. svn -v log "$REPO_URL" > "$LOG_PATH"
  19. tar --gzip -cf "$GZ_PATH" -C "$CRON_PATH" "$LOG_NAME"
  21. rm $XML_PATH $LOG_PATH
  23. rsync -qcah --rsh="ssh -i'/path/to/.ssh/key'" "$CRON_PATH/logs/"

Post Information

  • Total Posts in this topic: 3 posts
  • Users browsing this forum: No registered users and 36 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum

© 1998-2017. Ozzu® is a registered trademark of Unmelted, LLC.