<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Wolfmans Howlings: Using Ruby SVN bindings to get file status</title>
    <link>http://blog.wolfman.com/articles/2006/09/04/using-ruby-svn-bindings-to-get-file-status</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>A programmers Blog about Ruby, Rails and a few other issues</description>
    <item>
      <title>Using Ruby SVN bindings to get file status</title>
      <description>&lt;p&gt;If you Google around for information or even some documentation on
the ruby SVN bindings you will find plenty of comments that it simply
is not documented, so when I wanted to add an SVN status check to a UI
I was working on (a project browser window for Rails), I had to "Use
the source Luke". However given the bindings are actually mostly
automatically generated by SWIG, and the actual details are hidden in
a goo of swig generated c code, even that was a challenge.&lt;/p&gt;

&lt;p&gt;Eventually I realized that the API was almost identical to the c level
subversion API, not surprisingly, and for the most part it works the
way you would expect. However I could not find any examples of the
client status call, so here it is for anyone else struggling with this
issue.&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;svn/core&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;svn/client&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;svn/wc&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;svn/repos&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="comment"&gt;# define Consts for all the numeric status values&lt;/span&gt;
&lt;span class="constant"&gt;NONE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;
&lt;span class="constant"&gt;UNVERSIONED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;
&lt;span class="constant"&gt;NORMAL&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;3&lt;/span&gt;
&lt;span class="constant"&gt;ADDED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;4&lt;/span&gt;
&lt;span class="constant"&gt;MISSING&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;
&lt;span class="constant"&gt;DELETED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;6&lt;/span&gt;
&lt;span class="constant"&gt;REPLACED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;7&lt;/span&gt;
&lt;span class="constant"&gt;MODIFIED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;8&lt;/span&gt;
&lt;span class="constant"&gt;MERGED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;9&lt;/span&gt;
&lt;span class="constant"&gt;CONFLICTED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;10&lt;/span&gt;
&lt;span class="constant"&gt;IGNORED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;11&lt;/span&gt;
&lt;span class="constant"&gt;OBSTRUCTED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;12&lt;/span&gt;
&lt;span class="constant"&gt;EXTERNAL&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;13&lt;/span&gt;
&lt;span class="constant"&gt;INCOMPLETE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;14&lt;/span&gt;
&lt;span class="comment"&gt;# I added these so I can amalgamate repo and local status&lt;/span&gt;
&lt;span class="constant"&gt;UPDATED&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;15&lt;/span&gt;
&lt;span class="constant"&gt;MODIFIED_NEWER&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;16&lt;/span&gt;
&lt;span class="constant"&gt;NEWFILE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;17&lt;/span&gt;

&lt;span class="global"&gt;$modes&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="comment"&gt;# Map status to English&lt;/span&gt;
    &lt;span class="constant"&gt;NONE&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;None&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;UNVERSIONED&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;unversioned&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;NORMAL&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;normal&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;ADDED&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;file added&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;MISSING&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;missing&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;DELETED&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;file removed&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;REPLACED&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;deleted and then re-added&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;MODIFIED&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;modified&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;MERGED&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;received repos mods&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;CONFLICTED&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;file modified and in conflict&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;IGNORED&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;ignored&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;OBSTRUCTED&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;unversioned resource is in the way of the versioned resource&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;EXTERNAL&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;unversioned path populated by an svn:external property&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;INCOMPLETE&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;directory doesn't contain a complete entries list&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;UPDATED&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;newer version in repository&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;MODIFIED_NEWER&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;modified and newer version in repository&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;NEWFILE&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;new file in repository&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
    &lt;span class="constant"&gt;nil&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Unknown status&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="punct"&gt;}&lt;/span&gt;

&lt;span class="comment"&gt;# this amalgamates the most common status between local and repository&lt;/span&gt;
&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;compute_status&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="comment"&gt;# if modified in repo and localy&lt;/span&gt;
  &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;MODIFIED_NEWER&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;repos_text_status&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="constant"&gt;MODIFIED&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;text_status&lt;/span&gt; &lt;span class="punct"&gt;!=&lt;/span&gt; &lt;span class="constant"&gt;NORMAL&lt;/span&gt;
  &lt;span class="comment"&gt;# if added in repo and does not exist locally&lt;/span&gt;
  &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;NEWFILE&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;repos_text_status&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="constant"&gt;ADDED&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;text_status&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="constant"&gt;NONE&lt;/span&gt;
  &lt;span class="comment"&gt;# if repo is none then use local status&lt;/span&gt;
  &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;text_status&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;text_status&lt;/span&gt; &lt;span class="punct"&gt;!=&lt;/span&gt; &lt;span class="constant"&gt;NORMAL&lt;/span&gt;
  &lt;span class="comment"&gt;# if normal locally but changed in repo&lt;/span&gt;
  &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;UPDATED&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;repos_text_status&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="constant"&gt;MODIFIED&lt;/span&gt;
  &lt;span class="comment"&gt;# otherwise it must be normal&lt;/span&gt;
  &lt;span class="constant"&gt;NORMAL&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;ctx&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Svn&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Client&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Context&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;

&lt;span class="ident"&gt;rev&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;ctx&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;/home/user/project/myproject&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;HEAD&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;path&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="ident"&gt;astat&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;compute_status&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{path}&lt;/span&gt;: &lt;span class="expr"&gt;#{status.text_status}&lt;/span&gt;,&lt;span class="expr"&gt;#{status.repos_text_status}&lt;/span&gt; = &lt;span class="expr"&gt;#{$modes[astat]}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

  &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="ident"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;entry&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nil?&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....name: &lt;span class="expr"&gt;#{status.entry.name}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....url: &lt;span class="expr"&gt;#{status.entry.url}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....repos: &lt;span class="expr"&gt;#{status.entry.repos }&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....revision: &lt;span class="expr"&gt;#{status.entry.revision}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....kind: &lt;span class="expr"&gt;#{status.entry.kind}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....schedule: &lt;span class="expr"&gt;#{status.entry.schedule}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....deleted: &lt;span class="expr"&gt;#{status.entry.deleted}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....absent: &lt;span class="expr"&gt;#{status.entry.absent}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....incomplete: &lt;span class="expr"&gt;#{status.entry.incomplete}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....cmt_date: &lt;span class="expr"&gt;#{status.entry.cmt_date}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....cmt_rev: &lt;span class="expr"&gt;#{status.entry.cmt_rev}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....cmt_author: &lt;span class="expr"&gt;#{status.entry.cmt_author}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....prop_time: &lt;span class="expr"&gt;#{status.entry.prop_time}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.....text_time: &lt;span class="expr"&gt;#{status.entry.text_time}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a sample, it shows how to setup the client context, call the
status call, and parse the results. I also added some sugar by
defining the numeric status codes and adding a hash to translate them
to english. I also compute an amalgamated status code from the local
status and status in the repository, to get the extra status codes I
added above.&lt;/p&gt;

&lt;p&gt;The status parameter returned by the status() call turns out to be a
standard svn status structure, containing various fields, the most
interesting one as far as status is concerned are text_status and
repos_text_status fields which are numeric fields which specifies the
SVN status of the file locally and in the repository, I have created
in the example above a bunch of constants to define each of the
states, and a hash to turn them into english.&lt;/p&gt;

&lt;p&gt;Note the compute_status() method which looks at both the local status
and repository status to see what the relative state of any file is
wrt the repository.&lt;/p&gt;

&lt;p&gt;The other interesting field is the entry field, which contains bunch
of data as shown above, and in the structure definition below.&lt;/p&gt;

&lt;p&gt;There are more parameters that can be passed to the status
call, but the last two I show should be set to true, as that allows
recursion into sub directories and shows all files, by default
recursion is true but all_files is false which only show files not
under svn control. &lt;/p&gt;

&lt;p&gt;The developers have made some attempt to make this relatively easy to
use, you can forget about the apr pools and stuff, and the second
parameter is usually a structure that tells it the version or revision
to search for, this has been simplified so you can pass in a string
describing the revision ("HEAD", "TAIL", etc) or a number denoting the
revision number.&lt;/p&gt;

&lt;p&gt;The status and entry structures have also had the types converted into
convenient ruby types, but for reference I show the c struct
definitions from the various svn header files...&lt;/p&gt;

&lt;p&gt;Here is the full status structure from svn_wc.h&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;typedef struct svn_wc_status2_t
{
  /** Can be @c NULL if not under version control. */
  svn_wc_entry_t *entry;

  /** The status of the entries text. */
  enum svn_wc_status_kind text_status;

  /** The status of the entries properties. */
  enum svn_wc_status_kind prop_status;

  /** a directory can be 'locked' if a working copy update was interrupted. */
  svn_boolean_t locked;

  /** a file or directory can be 'copied' if it's scheduled for
   * addition-with-history (or part of a subtree that is scheduled as such.).
   */
  svn_boolean_t copied;

  /** a file or directory can be 'switched' if the switch command has been
   * used.
   */
  svn_boolean_t switched;

  /** The entry's text status in the repository. */
  enum svn_wc_status_kind repos_text_status;

  /** The entry's property status in the repository. */
  enum svn_wc_status_kind repos_prop_status;

  /** The entry's lock in the repository, if any. */
  svn_lock_t *repos_lock;

}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and the entry structure&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;typedef struct svn_wc_entry_t
{
  /* IMPORTANT: If you extend this structure, check svn_wc_entry_dup() to see
     if you need to extend that as well. */

  /* General Attributes */

  /** entry's name */
  const char *name;

  /** base revision */
  svn_revnum_t revision;

  /** url in repository */
  const char *url;

  /** canonical repository URL or NULL if not known */
  const char *repos;

  /** repository uuid */
  const char *uuid;

  /** node kind (file, dir, ...) */
  svn_node_kind_t kind;

  /* State information */

  /** scheduling (add, delete, replace ...) */
  svn_wc_schedule_t schedule;

  /** in a copied state */
  svn_boolean_t copied;
  /** deleted, but parent rev lags behind */
  svn_boolean_t deleted;

  /** absent -- we know an entry of this name exists, but that's all
      (usually this happens because of authz restrictions)  */
  svn_boolean_t absent;

  /** for THIS_DIR entry, implies whole entries file is incomplete */
  svn_boolean_t incomplete;

  /** copyfrom location */
  const char *copyfrom_url;

  /** copyfrom revision */
  svn_revnum_t copyfrom_rev;

  /** old version of conflicted file */
  const char *conflict_old;

  /** new version of conflicted file */
  const char *conflict_new;

  /** working version of conflicted file */
  const char *conflict_wrk;

  /** property reject file */
  const char *prejfile;

  /** last up-to-date time for text contents (0 means no information available)
   */
  apr_time_t text_time;

  /** last up-to-date time for properties (0 means no information available) */
  apr_time_t prop_time;

  /** base64-encoded checksum for the untranslated text base file,
   * can be @c NULL for backwards compatibility.
   */
  const char *checksum;

  /* "Entry props" */

  /** last revision this was changed */
  svn_revnum_t cmt_rev;

  /** last date this was changed */
  apr_time_t cmt_date;

  /** last commit author of this item */
  const char *cmt_author;

  /** lock token or NULL if path not locked in this WC
   * @since New in 1.2.
   */
  const char *lock_token;
  /** lock owner, or NULL if not locked in this WC
   * @since New in 1.2.
   */
  const char *lock_owner;
  /** lock comment or NULL if not locked in this WC or no comment
   * @since New in 1.2.
   */
  const char *lock_comment;
  /** Lock creation date or 0 if not locked in this WC
   * @since New in 1.2.
   */
  apr_time_t lock_creation_date;

  /* IMPORTANT: If you extend this structure, check svn_wc_entry_dup() to see
     if you need to extend that as well. */
} svn_wc_entry_t;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For the most part you can simply reference the fields in the structure
and get a relatively understandable result.&lt;/p&gt;

&lt;p&gt;The status call is defined in ruby as this&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;status&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;path&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;rev&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;recurse&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;true&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;get_all&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;false&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;
           &lt;span class="ident"&gt;update&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;true&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;no_ignore&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;false&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;
           &lt;span class="ident"&gt;ignore_externals&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="constant"&gt;false&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;status_func&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first parameter is the path on the local file system to get the
status of, the second is the revision to get, something like "HEAD",
or 2345 can be passed in, the next parameter is whether to recurse
into subdirectories, the next tells it to return the status of all
files if set to true, default of false and only returns "interesting
files" ie local mods and/or out-of-date or not versioned. Update is
set to true it will contact the repository to get more information wrt
to the version specified in the first parameter (which is ignored
otherwise). I couldn't find any documentation in the c stuff about
the no_ignore parameter, but the ignore_externals tells it to return
status on externals or not. See the header file svn_client.h and the
call svn_client_status2 for more documentation.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://technorati.com/tag/ruby+svn" rel="tag"&gt;ruby svn&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Mon, 04 Sep 2006 11:51:35 -0700</pubDate>
      <guid isPermaLink="false">urn:uuid:4e38e341-a33f-4fc3-b4cd-b9a982f254fa</guid>
      <author>Jim Morris</author>
      <link>http://blog.wolfman.com/articles/2006/09/04/using-ruby-svn-bindings-to-get-file-status</link>
      <category>Ruby</category>
      <category>svn</category>
      <category>ruby</category>
      <category>subversion</category>
      <category>svn</category>
      <category>rubysvn</category>
      <trackback:ping>http://blog.wolfman.com/articles/trackback/44</trackback:ping>
    </item>
    <item>
      <title>"Using Ruby SVN bindings to get file status" by Tim Coulter</title>
      <description>&lt;p&gt;To anyone interested:&lt;/p&gt;

&lt;p&gt;A lot of people seem to be having trouble finding documentation for the Ruby Subversion bindings. I've found a couple things out, and blogged about it here:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.oneofthewolves.com/2007/03/06/ruby-subversion-bindings-finally-some-documentation/" rel="nofollow"&gt;http://www.oneofthewolves.com/2007/03/06/ruby-subversion-bindings-finally-some-documentation/&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Mon, 05 Mar 2007 22:48:27 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:e013e227-7f87-40b4-8107-99cd3d8e5c4a</guid>
      <link>http://blog.wolfman.com/articles/2006/09/04/using-ruby-svn-bindings-to-get-file-status#comment-64</link>
    </item>
    <item>
      <title>"Using Ruby SVN bindings to get file status" by wolfmanjm</title>
      <description>&lt;p&gt;you can ask questions, but there is little to no documentation. Use the SVN c bindings docs as a guide, there is almost a 1:1 mapping from c to ruby.&lt;/p&gt;</description>
      <pubDate>Fri, 22 Dec 2006 13:54:35 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:f0df9ae3-5781-42d1-b484-1880c17233dd</guid>
      <link>http://blog.wolfman.com/articles/2006/09/04/using-ruby-svn-bindings-to-get-file-status#comment-33</link>
    </item>
    <item>
      <title>"Using Ruby SVN bindings to get file status" by Toni Schilling</title>
      <description>&lt;p&gt;Great! This is the 1st (first) example for ruby+svn I've found.
I experienced exactly what you write in your intro.
I'm new in Ruby, but I use SVN, C++, cygwin ... so may be I'll have some questions.
May I?
E.g.: can you point me to some docu/howto/sample for the svn-api ? Not the just the source code but some thing like an overview/what-is-what ...
Thank you and Merry Christmas
Toni&lt;/p&gt;</description>
      <pubDate>Fri, 22 Dec 2006 08:01:40 -0800</pubDate>
      <guid isPermaLink="false">urn:uuid:23e23b14-72b1-4cb6-854f-c9fc3634c701</guid>
      <link>http://blog.wolfman.com/articles/2006/09/04/using-ruby-svn-bindings-to-get-file-status#comment-21</link>
    </item>
  </channel>
</rss>
