解决项目编译对SVN依赖的相关问题

发布时间 2023-04-30 12:53:10作者: 毛姆
一、背景
软件打包发布并在机器部署后并生命周期没有结束,后续会随着使用发现各种各样的Bug,整个生命周期都与Bug为伴,发现Bug并解决Bug就是软件产品的一部分,通常软件出现异常会有日志记录,当问题出现后,如何知道一个软件库的版本,从而快速从源码库拉取对应版本的源码,调试并修复呢?这就需要记录下软件库的源码版本。
以.net程序为例,.net程序主要是有一系列的dll构成,为每一个dll标记源码库的版本号就很有必要,这将能指明dll对应源码的版本号,在实际使用中很有帮助。
.net程序集的版本号规则:主版本.次版本.生成号.修订号
 
希望每次发布的时候将修订号使用该项目对应的SVN版本号,假设项目的最初版本为1.0.0.0,当项目改动并提交到SVN后SVN版本号为100,则希望生成的dll中文件版本为:1.0.0.100,这样就能通过查看dll文件版本知道该dll对应的源码SVN版本号
 
二、通过SubWcRev.exe实现程序集信息包含SVN版本号
参考文档:https://tortoisesvn.net/docs/release/TortoiseSVN_zh_CN/tsvn-subwcrev.html
 
方案简要概述:
(1)创建一个程序集模板文件:AssemblyInfo.tmpl
(2)将该文件中的[assembly: AssemblyFileVersion("1.0.0.0")]改为[assembly: AssemblyFileVersion("1.0.0.$WCREV$")]
(3)在预编译命令时执行SubWcRev.exe,将AssemblyInfo.tmpl模板文件生成AssemblyInfo.cs,步骤2中的程序集版本就会被自动替换为SVN最新版本号
以上最终实现编译后的dll文件版本包含SVN版本号
 
三、实际使用问题
But,实际使用中存在一些问题:SubWcRev.exe正确执行要求操作的目录必须为SVN Working Copy,否则无法编译通过,实际使用中有些机器并未预装SVN环境,结果就是编译报错。
显然,该方案源码编译是依赖于SVN环境的,是一种耦合问题
 
四、解决方案
那么,对于无SVN环境的机器,如何顺利编译通过?
1、方案一:为需要编译的项目源码提供SVN环境
在该机器安装VisualSVN Server Manager,将源码上传本地后再拉取副本,这样确保源码在新机器上是SVN Working Copy
虽然可行,但是这种方案比较繁琐,效率低下
 
问题根源在于SubWcRev.exe命令执行的源码目录是SVN Working Copy!!!
因此需要解决当源码目录不是SVN Woring Copy的情况下,依然能成功编译的问题,该问题的卡点在于如何判定指定源码目录是否为SVN Working Copy?
 
通过查阅资料,找到svn info命令可担此重任 :
(1)当源码目录是SVN Working Copy,会打印出详细信息
(2)当源码目录不是SVN Working Copy,会提示错误信息:XXX is not working copy
 
创建一个解决方案,命名为SVNVersion,该解决方案包含两个项目:

 
打开命令行,定位到上述源码目录,试验验证如下,执行成功:
E:\SvnVersion>svn info
Path: . Working Copy Root Path: E:\SvnVersion URL: https://xxx/svn/SvnVersion Relative URL: /SvnVersion Repository Root: https://xxx/svn/SvnVersion Repository UUID: ccdf0fd3-632d-c745-82a6-d8dcb4201352 Revision: 120 Node Kind: directory Schedule: normal Last Changed Author: xxx Last Changed Rev: 120 Last Changed Date: 2023-04-29 15:54:26 +0800

 

将.svn目录命名为.svn2,再次执行svn info,执行错误:
E:\SvnVersion>svn info
svn: E155007: 'E:
\SvnVersion' is not a working copy
 
以上试验说明svn info命令可以有效的检查一个指定目录是否为SVN Working Copy
 
如何判断svn info命令是否执行成功?
CMD命令执行成功返回0,可以通过判断ERRORLEVEL变量是否等于0,来确定svn info 是否执行成功
至此,构思完成,解决了最初遇到的问题,优雅的解除了源码编译对SVN环境的依赖
最终给出解决方案:通过svn info 判断要编译的源码目录是否为SVN Working Copy,若是执行SubWcRev.exe,若不是则不执行,这样无论源码是否为SVN Working Copy都能正确编译
 
2、方案二:摆脱项目编译对SVN环境的依赖
具体实施步骤:
(1)将SubWcRev.exe、SVN.exe文件拷贝到源码中,与解决方案文件(*.sln文件一个目录),这样可以确保没有SVN环境的机器同样可以执行SubWcRev、svn Info命令
(2)编写CMD代码:
cd /d $(SolutionDir)
svn info
if %ERRORLEVEL%==0 (
SubWcRev "$(ProjectDir)\" "$(ProjectDir)Properties\AssemblyInfo.tmpl" "$(ProjectDir)Properties\AssemblyInfo.cs"
) 
(3)将上述代码放到项目的生成前事件命令行中,分别在源码是SVN Working Copy和不是SVN Working Copy中编译试验,均能通过测试,只是后一种情况编译的dll无SVN版本号
至此,已解决编译项目对SVN环境依赖问题,即便没有SVN项目依然能编译通过。 
 
更近一步,对于实际项目中,通常有N多项目,每个项目都写这一段代码必然重复,违反了DRY原则,故重构上述代码,使之更整洁。
思路是将其提取到一个名为GenerateAssemblyInfo.bat文件中(与*.sln文件同一目录),将需要的目录作为变量传递:
set ProjectDir=%1
svn info
if %ERRORLEVEL%==0 (
SubWcRev %ProjectDir% %ProjectDir%Properties\AssemblyInfo.tmpl %ProjectDir%Properties\AssemblyInfo.cs
) 

 

项目属性中生成前事件命令行,改为调用bat文件:
cd /d $(SolutionDir)
call GenerateAssemblyInfo.bat $(ProjectDir)

 

 总结:
(1)本文从实际需求出发,给出软件dll版本号与SVN版本号产生关联的方案:通过SubWcRev.exe实现
(2)在实际使用中上述方案存在编译依赖SVN环境的问题,导致无SVN环境的机器在编译项目时报错,无法编译通过
(3)通过分析问题症结,找出问题卡点在于能否有效判定源码目录是否为SVN Working Copy,并通过执行svn info命令给出判定依据
(4)综合需求及实际问题,给出优化方案,最终解决项目编译对SVN环境的依赖:当源码目录被检测出是SVN Working Copy时,执行SubWcRev.exe,否则不予执行
(5)通过重构批处理命令,提取到一个文件中,项目统一调用该文件,便于多个项目复用,保持了方案的整洁性