在 Visual Studio 项目中使用 Subversion 修订号






4.52/5 (14投票s)
SVN 关键字不足以检索您项目的最高修订号。这个简单的方法解决了这个问题。
引言
我使用 TortoiseSVN 已经有一段时间了,它证明了在 Windows / Visual Studio 环境中使用 Subversion 的绝佳方式。
我最近发现了如何在我的项目中应用 SVN 关键字。如果您启用 SVN 关键字,那么每次签入项目时,Subversion 都会扫描文件中的特定“关键字”并用一些信息替换这些关键字。例如,在我的源文件顶部,我会创建一个包含以下关键字的头部
'$Author:$
'$Id:$
'$Rev:$
当我将此文件签入 Subversion 时,这些关键字将被替换为以下内容
'$Author: paulbetteridge $
'$Id: myfile.vb 145 2008-07-16 15:24:29Z paulbetteridge $
'$Rev: 145 $
我认为,如果我使用 $Rev$
关键字,我可以将其用作软件版本的一部分,以便跟踪发布时的版本和构建。我的版本将看起来像 1.0.0.145。
使用 $Rev$
关键字的限制在于,它只能提供文件的修订号,而不是整个项目的修订号,因此使用 $rev$
关键字不能作为我软件版本控制的一部分。
阅读 Tortoise 的帮助文件,我发现 Tortoise SVN 提供了一个名为 *SubWCRev.exe* 的工具。
SubWCRev 是一个 Windows 控制台程序,可用于读取 Subversion 工作副本的状态并在模板文件中执行关键字替换。
本文介绍了如何使用 SubWCRev 将顶级修订号嵌入您的项目中。
Using the Code
代码执行三项任务
- 创建一个包含 SubWCRev 读取的关键字的模板文件。
- 运行 SubWCRev.exe,它将根据模板文件中的关键字生成一个包含 Subversion 信息的输出文本文件。
- 读取输出文件并将文件中的值返回到一个数组中,供您的项目使用。
附件中的项目是用 VB.NET 编写的,但我也在本文中提供了 C# 的实现。
模板文件
此代码创建模板文件,并将包含 所有 SubWCRev 可读取的命令
关键字 | 描述 |
---|---|
$WCREV$ |
替换为工作副本中的最高提交修订号。 |
$WCDATE$ |
替换为最高提交修订号的提交日期/时间。默认情况下,使用国际格式:yyyy-mm-dd hh:mm:ss。或者,您可以指定一个自定义格式,它将与 strftime() 一起使用,例如:$WCDATE=%a %b %d %I:%M:%S %p$ 。有关可用格式字符的列表,请查看在线参考。 |
$WCNOW$ |
替换为当前的系统日期/时间。这可以用来指示构建时间。时间格式如上所述。 |
$WCRANGE$ |
替换为工作副本中的更新修订号范围。如果工作副本处于一致状态,则为单个修订号。如果工作副本包含混合修订号,无论是由于过期还是由于故意更新到某个修订号,那么范围将显示为 100:200 的形式。 |
$WCMIXED$ |
如果存在混合更新修订号,则 $WCMIXED?TText:FText$ 被替换为 TText ;如果不存在,则被替换为 FText 。 |
$WCMODS$ |
如果存在本地修改,则 $WCMODS?TText:FText$ 被替换为 TText ;如果不存在,则被替换为 FText 。 |
$WCURL$ |
替换为传递给 SubWCRev 的工作副本路径的存储库 URL。 |
$WCNOW$ |
替换为当前时间和日期。 |
$WCNOW= |
以标准格式替换为当前时间和日期。 |
$WCINSVN$ |
如果条目已版本化,则 $WCINSVN?TText:FText$ 被替换为 TText ;如果未版本化,则被替换为 FText 。 |
$WCNEEDSLOCK$ |
如果条目设置了 svn:needs-lock 属性,则 $WCNEEDSLOCK?TText:FText$ 被替换为 TText ;否则替换为 FText 。 |
$WCISLOCKED$ |
如果条目已锁定,则 $WCISLOCKED?TText:FText$ 被替换为 TText ;否则替换为 FText 。 |
$WCLOCKDATE$ |
替换为锁定日期。 |
$WCLOCKOWNER$ |
替换为锁定所有者的名称。 |
$WCLOCKCOMMENT$ |
替换为锁定的注释。 |
Dim strTemplateFile As String = "SvnTemplate.txt"
Dim bAns As Boolean = False
Dim objReader As StreamWriter
Dim strData As String
strData = "$WCREV$" + vbCrLf + _
"$WCDATE$" + vbCrLf + _
"$WCNOW$" + vbCrLf + _
"$WCRANGE$" + vbCrLf + _
"$WCMIXED?Mixed update revision:Not mixed$" + vbCrLf + _
"$WCMODS?Modified:Not modified$" + vbCrLf + _
"$WCURL$" + vbCrLf + _
"$WCNOW$" + vbCrLf + _
"$WCINSVN?Versioned:Not Versioned$" + vbCrLf + _
"$WCNEEDSLOCK?Lock Required:Lock not required$" + vbCrLf + _
"$WCISLOCKED?Locked:Not Locked$" + vbCrLf + _
"$WCLOCKDATE$" + vbCrLf + _
"$WCLOCKOWNER$" + vbCrLf + _
"$WCLOCKCOMMENT$" + vbCrLf
Try
objReader = New StreamWriter(strTemplateFile)
objReader.Write(strData)
objReader.Close()
Catch Ex As Exception
Console.WriteLine(Ex.Message)
End Try
string strTemplateFile = @"SvnTemplate.txt"
bool bAns = false;
StreamWriter objReader;
string strData;
strData = "$WCREV$" + Constants.vbCrLf +
"$WCDATE$" + Constants.vbCrLf +
"$WCNOW$" + Constants.vbCrLf +
"$WCRANGE$" + Constants.vbCrLf +
"$WCMIXED?Mixed update revision:Not mixed$" + Constants.vbCrLf +
"$WCMODS?Modified:Not modified$" + Constants.vbCrLf +
"$WCURL$" + Constants.vbCrLf +
"$WCNOW$" + Constants.vbCrLf +
"$WCINSVN?Versioned:Not Versioned$" + Constants.vbCrLf +
"$WCNEEDSLOCK?Lock Required:Lock not required$" + Constants.vbCrLf +
"$WCISLOCKED?Locked:Not Locked$" + Constants.vbCrLf +
"$WCLOCKDATE$" + Constants.vbCrLf +
"$WCLOCKOWNER$" + Constants.vbCrLf +
"$WCLOCKCOMMENT$" + Constants.vbCrLf;
try {
objReader = new StreamWriter(strTemplateFile);
objReader.Write(strData);
objReader.Close();
}
catch (Exception Ex) {
Console.WriteLine(Ex.Message);
}
创建修订信息
有了模板文件后,您需要运行命令行工具 SubWCRev.exe,并提供三个参数 - 源代码的工作目录、模板文件位置以及您希望存储包含修订信息的输出文件的位置。
Dim strRev As String = ""
' Input file containing the SubWcRev keywords
Dim strTemplateFile As String = "svntemplate.txt"
' Output file that will contain the SVN revisions after calling SubWcRev.exe
Dim strRevOutputFile As String = "svnrev.txt"
' If we are running as an exe (i.e. not in the Visual Studio IDE)
' then we dont want to create the revisions but read what is
' already there. This assumes that the exe is being used on a
' non-subversion machine
' Check for the IDE, True is it is or false if it is not
' (assume false is running as an exe)
If System.Diagnostics.Debugger.IsAttached Then
' Get the working directory of the application exe - not the most
' glamourous way to do this so need to rethink this!!!
Dim dirInfo As New DirectoryInfo(Application.ExecutablePath)
Dim dirinfoSourceWorkingDir As DirectoryInfo
dirinfoSourceWorkingDir = dirInfo.Parent().Parent().Parent()
Dim strSourceWorkingDir As String = dirinfoSourceWorkingDir.FullName
' The template file is a text file containing some
' keyword that are recognised by SubWcRev.exe when it
' is run against the root project directory.
' Creates the template file is it is not already there
SvnCreateTemplate(strTemplateFile)
' Now create a process to run the SubWcRec.exe
Try
Dim p As New Process
With p.StartInfo
.UseShellExecute = True
.FileName = "subwcrev.exe"
.Arguments = """" + strSourceWorkingDir + """ """ + _
strTemplateFile + """ """ + _
strRevOutputFile + """"
.UseShellExecute = False
.RedirectStandardOutput = True
End With
' Execute the process and wait for it to exit
If p.Start() Then
Dim output As String = p.StandardOutput.ReadToEnd()
Console.WriteLine(output)
p.WaitForExit()
End If
Catch ex As Exception
Console.WriteLine(ex.Message)
' Probably because Subversion not installed
' and SubWcRev.exe was not found
End Try
End If
string strRev = "";
// Input file containing the SubWcRev keywords
string strTemplateFile = "svntemplate.txt"
// Output file that will contain the SVN revisions after calling SubWcRev.exe
string strRevOutputFile = "svnrev.txt";
// If we are running as an exe (i.e. not in the Visual Studio IDE)
// then we dont want to create the revisions but read what
// is already there. This assumes that the exe is being used
// on a non-subversion machine
// Check for the IDE, True is it is or false if it is not
// (assume false is running as an exe)
if (System.Diagnostics.Debugger.IsAttached) {
// Get the working directory of the application exe - not the most
// glamourous way to do this so need to rethink this!!!
DirectoryInfo dirInfo = new DirectoryInfo(Application.ExecutablePath);
DirectoryInfo dirinfoSourceWorkingDir;
dirinfoSourceWorkingDir = dirInfo.Parent().Parent().Parent();
string strSourceWorkingDir = dirinfoSourceWorkingDir.FullName;
// The template file is a text file containing some keyword that are ~
// recognised by SubWcRev.exe when it
// is run against the root project directory.
// Creates the template file is it is not already there
SvnCreateTemplate(strTemplateFile);
// Now create a process to run the SubWcRec.exe
try {
Process p = new Process();
{
p.StartInfo.UseShellExecute = true;
p.StartInfo.FileName = "subwcrev.exe";
p.StartInfo.Arguments = "\"" + strSourceWorkingDir +
"\" \"" + strTemplateFile + "\" \"" +
strRevOutputFile + "\"";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
}
// Execute the process and wait for it to exit
if (p.Start()) {
string output = p.StandardOutput.ReadToEnd();
Console.WriteLine(output);
p.WaitForExit();
}
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
// Probably because Subversion not installed and SubWcRev.exe was not found
}
}
现在您已经创建了输出文件,接下来,您需要将此文件读取到您的应用程序中,以便开始使用修订信息。
' The revison should now be available in the output file -
' reading this will get the revision
' There are three lines (Rev, Modifed status and Rev Date)
Dim strContents As String = ""
Dim objReader As StreamReader
Try
objReader = New StreamReader(strRevOutputFile)
strContents = objReader.ReadToEnd()
objReader.Close()
' Get the revision from the contents of the file
aRevData = Split(strContents, vbCrLf)
Catch Ex As Exception
Console.WriteLine(Ex.Message)
' Probably because Subversion is not installed or this
' project has not been checked into
' subversion yet. You muct make sure it is checked in to create a revision
If System.Diagnostics.Debugger.IsAttached Then
MessageBox.Show(Ex.Message + vbCrLf + vbCrLf + _
"This is probably because this project is not " + _
"under subversion revision control yet or the " + _
"output file was not created by ""subwcrev.exe""")
Else
MessageBox.Show(Ex.Message + vbCrLf + vbCrLf + _
"This is probably because the output file " + _
"""svnrev.txt"" has not been created yet - need " + _
"run this using the Visual Studio IDE first to " + _
"create the svnrev.txt file containing the SVN values!")
End If
aRevData(0) = """svnrev.txt"" file not Found"
End Try
{
// The revison should now be available in the output file - reading this
// will get the revision
// There are three lines (Rev, Modifed status and Rev Date)
string strContents = "";
StreamReader objReader;
try {
objReader = new StreamReader(strRevOutputFile);
strContents = objReader.ReadToEnd();
objReader.Close();
// Get the revision from the contents of the file
aRevData = Strings.Split(strContents, Constants.vbCrLf);
}
catch (Exception Ex) {
Console.WriteLine(Ex.Message);
// Probably because Subversion is not installed or this project
// has not been checked into
// subversion yet. You muct make sure it is checked in to create a revision
if (System.Diagnostics.Debugger.IsAttached) {
MessageBox.Show(Ex.Message + Constants.vbCrLf + Constants.vbCrLf +
"This is probably because this project is not under subversion " +
"revision control yet or the output file was not " +
"created by \"subwcrev.exe\"");
}
else {
MessageBox.Show(Ex.Message + Constants.vbCrLf + Constants.vbCrLf +
"This is probably because the output file \"svnrev.txt\" " +
"has not been created yet - need run this using the " +
"Visual Studio IDE first to create the svnrev.txt file " +
"containing the SVN values!");
}
aRevData(0) = "\"svnrev.txt\" file not Found";
}
}
我将文件的内容返回到一个名为“aRevData
”的字符串数组中。
我预先初始化了这个数组,以防模板文件未创建,或者 somewhere 出现了问题。这样,如果您无法获取 SVN 值(例如,您没有安装 Subversion 或尚未将项目签入 Subversion),您就可以使用预初始化的值。
使用修订数据
这篇文章的结尾部分展示了我是如何使用这段代码的 - 请查看发布的项目。
我在我的关于窗体/启动屏幕等中使用了“AppVersion
”变量,并将其作为应用程序官方发布版本的软件版本。
' Create the revision data array - initialise to initial values - date will be
' overwritten if reading the svn file is ok
Dim aRevHeaders() As String = {"$WCREV$", _
"$WCDATE$", _
"$WCNOW$", _
"$WCRANGE$", _
"$WCMIXED$", _
"$WCMODS$", _
"$WCURL$", _
"$WCNOW$", _
"$WCINSVN?Versioned:Not Versioned$", _
"$WCNEEDSLOCK$", _
"$WCISLOCKED$", _
"$WCLOCKDATE$", _
"$WCLOCKOWNER$", _
"$WCLOCKCOMMENT$"}
Dim aRevData() As String = {"0", "", "", "", "", "", "", "", "", "", "", "", "", "", ""}
' Read and write to the svnrevisions text file so that it forces subversion to update
' the file with the latest revision - there are no global revisions keyword so this
' is an alternative!
Try
SvnGetlatestRev(aRevData) ' Create and read the svn revision file
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
Dim strVersion As String() = Split(Application.ProductVersion, ".")
Dim AppVersion As String = String.Format("{0}.{1}.{2}.{3}", _
strVersion(0), _
strVersion(1), _
strVersion(2), _
aRevData(0))
// Create the revision data array - initialise to initial values - date will be
// overwritten if reading the svn file is ok
string[] aRevHeaders = {"$WCREV$",
"$WCDATE$",
"$WCNOW$",
"$WCRANGE$",
"$WCMIXED$",
"$WCMODS$",
"$WCURL$",
"$WCNOW$",
"$WCINSVN?Versioned:Not Versioned$",
"$WCNEEDSLOCK$",
"$WCISLOCKED$",
"$WCLOCKDATE$",
"$WCLOCKOWNER$",
"$WCLOCKCOMMENT$"};
string[] aRevData = {"0", "", "", "", "", "", "", "", "", "", "", "", "", "", ""};
// Read and write to the svnrevisions text file so that it forces subversion to update
// the file with the latest revision - there are no global revisions keyword so this
// is an alternative!
try {
SvnGetlatestRev(aRevData);
// Create and read the svn revision file
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
string[] strVersion = Strings.Split(Application.ProductVersion, ".");
string AppVersion = string.Format("{0}.{1}.{2}.{3}", strVersion(0),
strVersion(1), strVersion(2), aRevData(0));
我在 Tortoise 的帮助文件中看到,我可以使用 COM 接口 - 这留待以后处理。
感谢您阅读本文。请留下您对如何改进本文的建议。
历史
- pbRevsion: v1.0。