sexta-feira, 18 de abril de 2008

NSvn Handling of Repository Externals Property Text

This first post does not entirely relate to the .NET framework itself, but rather to a useful assembly implemented by the Ankh SVN project: NSvn.

NSvn is a managed assembly to programmatically call Subversion commands like Update, Commit and others. It's a rather straightforward, and usable, library. However, there are some strange behaviors regarding some of its innards which can lead to some rather obscure bugs.

One of the latest I encountered was the handling of the svn:externals property in code. Here's a small annotated snippet of the endeavour:

Client client = new Client();
client.Checkout(sourceSVN, projectName,
Revision.Head, NSvn.Common.Recurse.Full);

Basically I instantiated a NSvn.Client instance and performed a checkout of a repository located in sourceSVN into the directory projectName.

PropertyDictionary dictionary = client.PropGet("svn:externals", projectExternalsDir, Revision.Head, Recurse.None);
Property externalsProperty = dictionary[Path.Combine(sourceSVN, "Externals")];

One can then proceed to access the svn:externals property via the PropGet method. This returns a PropertyDictionary which one can access. The Externals property itself has to be retrieved from the dictionary by specifying the full repository path.

The problem began when we reached the point of actually modifying the value of the property, in particular, when adding a new external repository line:

string values = Encoding.UTF8.GetString(externalsProperty.Data);
values += newExternal +
values += newExternal +
byte[] vals = Encoding.UTF8.GetBytes(values);
Property(externalsProperty.Name, vals), projectExternals, Recurse.None);

By doing this, NSvn threw a SvnClientException indicating that there was an error parsing the property text.

It turns out that each Externals line has to be separated by a '\n' (not a '\r\n'!), but it's absolutely vital that the last line does not have ANY separator whatsoever. Adding a TrimEnd call to the end of values does the trick:

byte[] vals = Encoding.UTF8.GetBytes(newValues.TrimEnd('\n'));

Strange thing...

Sem comentários: