使用 DotSVN 从 .NET 访问 Subversion 仓库
一篇关于如何从 .NET 应用程序访问 Subversion 仓库的文章。
引言
本文介绍了开源 DotSVN 库的理念,以及如何使用它从 .NET 应用程序连接到 Subversion 文件仓库。
背景
Subversion 是开源项目中增长最快的版本控制系统。下图显示了 Subversion 在公共 Apache 服务器上的采用情况。(此图取自 CollabNet 网站,基于 E-Soft 提供的数据。)
随着 Subversion 的普及,许多开发人员和组件供应商正在开发访问 Subversion 的应用程序或组件。他们希望以编程方式连接到 Subversion 仓库,以便开发仓库浏览器、源代码查看器等。 DotSVN 就是实现这一目标的 .NET 库。
Subversion 架构
Subversion 架构包含多个层,每一层执行特定的任务,并提供良好的封装和模块化。以下是各层:
fs
(文件系统): 这是实现版本化文件系统的最低层。repos
(仓库): 这是围绕文件系统实现许多辅助功能的仓库层。mod_dav_svn
: 提供对仓库的 WebDAV 访问。ra
(仓库访问): 此层处理本地和远程的仓库访问。wc
(工作副本): 此层管理本地工作副本,这些副本是仓库部分内容的本地镜像。client
: 此层使用工作副本库提供常见的客户端任务,如用户身份验证、版本比较等。
下图取自 SVN book,描绘了 Subversion 架构(由 SVN book 提供)。
Subversion 文件系统是一个三维文件系统,其中两维是目录视图,第三维是修订版本。在 Subversion 中,文件存储为指向前一个更改的链接;因此,Subversion 仓库非常紧凑。此外,Subversion 文件系统使用事务来保持更改的原子性——全有或全无。
什么是 DotSVN?
DotSVN 是 Subversion 的完整 .NET 实现。DotSVN 直接在仓库级别(而不是在客户端/工作副本级别)访问 Subversion 仓库。它用 .NET 完全实现了 Subversion 仓库访问层,而不使用任何 Subversion 库。它公开了 API,这些 API 将帮助 .NET 开发人员连接到 SVN 仓库并对其进行操作。DotSVN 是作为一个开源项目开发的,托管在 Google Code 上。最近,DotSVN 团队发布了 DotSVN 库的第一个版本,该版本支持读取 Subversion 中托管的 FSFS 仓库的内容。它可以读取仓库的目录结构、修订版本的属性以及单个文件内容。此版本的 DotSVN 还包含一个演示 DotSVN API 用法的示例应用程序。该示例应用程序是一个基于 WinForms 的仓库浏览器,非常类似于 Tortoise SVN 的仓库浏览器。它以分层方式显示 FSFS 仓库的内容,并在每个目录或文件旁边显示 Windows 文件类型图标。
如何使用 DotSVN API?
DotSVN API 非常简单易用。使用 DotSVN 访问 SVN 仓库涉及三个步骤:
- 打开仓库
- 执行相关操作(例如:获取仓库的目录内容)
- 关闭仓库
让我们逐一了解这些步骤。
打开仓库
为了打开一个仓库,我们必须指定将如何访问该仓库。可以使用以下三种协议之一来访问 Subversion 仓库:
- file:// 访问本地计算机上的仓库
- http:// 或 https:// 通过 Web(使用 WebDav 协议)访问仓库
- svn:// Subversion 的专有自定义协议
DotSVN 目前支持使用 file:// 协议进行仓库访问,该协议实现在 FSRepository
类中。因此,要连接到本地文件系统上的仓库,我们必须首先实例化一个 FSRepository
,提供仓库的完整本地路径。在 DotSVN 中,仓库访问层被抽象在 ISVNRepository
接口和 SVNRepository
类中。实例化仓库类的过程封装在一个工厂类中。以下代码片段演示了这一点:
string repositoryPath = @"file://C:\DummyRepos";
ISVNRepository repository =
SVNRepositoryFactory.Create(new SVNURL(repositoryPath));
此外,DotSVN 还提供了一个 TestConnection
方法,用于检查 URL 是否对应于一个有效的仓库。此方法会快速打开和关闭具有给定 URL 的仓库,并在访问仓库时出现任何问题时抛出异常。
private static bool IsValidRepository(string repositoryPath)
{
bool isValid = true;
try
{
repository = SVNRepositoryFactory.Create(new SVNURL(repositoryPath));
// Check the repository connection.
// If there is a problem, this method will throw an exception
repository.TestConnection();
}
catch
{
isValid = false;
}
return isValid;
}
public static void Main()
{
string repositoryPath = @"file://C:\DummyRepos";
if( IsValidRepository(repositoryPath) )
{
// Create a connection to the repository
repository = SVNRepositoryFactory.Create(new SVNURL(repositoryPath));
// Open the repository
repository.OpenRepository();
}
}
与仓库交互
既然我们已经学会了如何打开仓库,现在让我们使用 DotSVN 库对仓库执行一些操作。例如,我们将读取并显示仓库的内容。以下 DotSVN API 是执行此操作的正确选择:
public override ICollection<SVNDirEntry> GetDir(string path,
long revision, IDictionary<string, string> properties);
此方法会获取指定路径下的目录在特定修订版本中的内容和属性。每个目录项的信息由一个 SVNDirEntry
对象表示。目录项可以是文件系统上的目录或文件。此方法的输入在前两个参数中指定:第一个参数 path
是要读取其内容的目录的路径。此路径可以是相对于仓库位置的,也可以是绝对的(以“/”开头)。第二个参数 revision
是要获取的修订版本的编号。方法的输出由返回值和第三个参数提供。返回值是一个包含从仓库获取的目录条目(SVNDirEntry
对象)的集合。第三个参数是一组键值对,代表目录的属性。请参见下面的示例代码。此示例使用了一个名为 TreeListView
的自定义 WinForms 控件,它结合了树视图和列表视图。
// Get the contents of the repository and display them
long revision = -1; // -1 will retrieve the latest revision
IDictionary<string, string> properties = new Dictionary<string, string>();
ICollection<SVNDirEntry> dirEntries = repository.GetDir(string.Empty,
revision, properties);
// Add the root entry to the repository browser's tree view
string rootPath = repository.GetRepositoryRoot(true).ToString();
// repositoryTreeView is an instance of System.Windows.Forms.TreeListView
TreeListViewItem rootItem = repositoryTreeView.Items.Add(rootPath, 0);
// Add the other entries one by one to the tree view
foreach (SVNDirEntry dirEntry in dirEntries)
{
TreeListViewItem newItem = new TreeListViewItem(dirEntry.Name, 0);
string fileExtension = Path.GetExtension(dirEntry.Name);
newItem.SubItems.Add(fileExtension.TrimStart('.')); // Extension
newItem.SubItems.Add(dirEntry.Revision.ToString()); // Revision
newItem.SubItems.Add(dirEntry.Author); // Author
string size = string.Format("{0}", dirEntry.Size); // Size
newItem.SubItems.Add( size );
string date = dirEntry.Date.ToLocalTime().ToString(); // Commit Date
newItem.SubItems.Add(date);
// Add the new item to the root node in tree view
rootItem.Items.Add(newItem);
}
// Read the properties
foreach (string property in properties)
{
// ........
}
此示例仅展示了在 TreeView
控件中显示目录结构的粗略代码。可以进一步增强,以显示带有“+”图标前缀的目录节点,或根据文件扩展名显示文件的 Windows 文件类型图标。所有这些功能都在 DotSVN 源代码附带的 GUI 示例项目中得到了演示。
关闭仓库
是的。非常简单。只需这样做:
// Close the repository
repository.CloseRepository();
要对这个示例进行一次演练,请下载并运行本文附加的 GUI 示例。您可以通过在URL文本框中提供仓库的完整file://路径来选择一个仓库,或者只需单击“...”按钮并浏览到仓库的根目录。请参见上面 GUI 示例应用程序的屏幕截图。有关实现细节,请下载本文附加的 GUI 示例源代码。
DotSVN 中的其他 API
除了上面描述的 API 之外,DotSVN 还通过 ISVNRepository
接口公开了一些额外的 API 来操作仓库。以下列出了一些:
// Gives the UUID (Universal Unique Identifier) of the repository
string GetRepositoryUUID(bool ForceConnection);
// Gives the latest revision of the repository
long GetLatestRevision();
// Fetches the contents and or properties of a file
// located at the specified path in a particular revision.
long GetFile(string path,
long revision,
IDictionary<string, string> properties,
Stream contents);
有关这些 API 用法的详细信息,请参阅 DotSVN 源代码中的文档。
结论
本文概述了 DotSVN 库在 .NET 应用程序中访问 Subversion 仓库的用法。更详细的实现可在 DotSVN 附带的示例项目中找到。示例项目包括一个 WinForms 示例、一个控制台应用程序和一个 Web 应用程序。DotSVN 的完整源代码可以从 DotSVN 项目主页 下载。您也可以下载本文附加的 DotSVN 编译的二进制文件 来获取库的最新构建版本。您还可以使用 此链接 anonymously 检出 DotSVN 源代码的最新工作副本。
参考文献
理解 DotSVN 库的最佳参考是阅读源代码本身。以下是一些额外的参考资料:
历史
初始版本。