たぷつきません

おなかがでてきた。もうたぷついてるやん。

アセンブリバージョンの管理

 Microsoftの定義と意味合いが若干異なるが、バージョン番号の書式は「Major.Minor.Build.Revision」なので、Buildはビルド回数、RevisionはSubversionのリビジョンとなるようにしたい...ということで色々調査。
 自動インクリメントはBuild Version Increment Add-In Visual Studio - Homeを、リビジョンの更新には、TortoiseSVN第6章 SubWCRev プログラムを使うことにしたが、SubWCRevコマンドはテンプレートファイルからAssemblyInfo.csを上書きするため、Build Version Increment Add-Inがせっかくインクリメントしたビルド番号を消してしまうことになる。しかも、AssemblyInfoを修正する際も、テンプレートファイルの方を修正しなければならないので、Visual StudioのPropertiesエディタが意味をなさなくなったり、一々気を遣うことになる。
 そんなわけで、ビルド前イベントでテンプレートをAssembliyInfo.csに変換するだけではなく、その前に動的にテンプレートを最新のAssemblyInfo.csから作成するWSH用のVBSコマンドを作成した。

makeVersionInfoTemplate.vbs
'Usage: CScript //nologo makeVersionInfoTemplate.vbs
Const ForReading = 1, ForWriting = 2
Const adTypeText = 2
Const adCRLF = -1
Const adLF = 10
Const adCR = 13
Const adReadAll = -1
Const adReadLine = -2
Const adWriteLine = 1
Const adSaveCreateNotExist = 1
Const adSaveCreateOverWrite = 2

If WScript.Arguments.Length <> 2 Then
    WScript.Echo "Usage...:" & vbCRLF & " makeVersionInfoTemplate.vbs AssemblyInfo.csパス 出力するAssemblyInfoテンプレートファイル"
    WScript.Quit 1
End If

fromAssemblyInfoFileName = WScript.Arguments(0)
toAssemblyInfoTemplateFileName = WScript.Arguments(1)
'UTF-8は処理できないので、Scripting.FileSystemObjectではなく asodb.streamを使う。
'Set fso = CreateObject("Scripting.FileSystemObject")
'Set fHandle = fso.OpenTextFile(fromAssemblyInfoFileName, ForReading)
'allText = fHandle.ReadAll
'fHandle.Close
Set InStream = CreateObject("ADODB.Stream")
InStream.Open
InStream.Charset = "UTF-8"
InStream.LoadFromFile(fromAssemblyInfoFileName)
If Err.number > 0 Then
    WScript.Echo "Can't open " & fromAssemblyInfoFileName & " for reading."
    WScript.Quit 1
End If
allText = InStream.ReadText(adReadAll)

pattern = "\[assembly: Assembly(.*)Version\(""([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)""\)\]"
replacer = "[assembly: Assembly$1Version(""$2.$3.$4.$$WCREV$$"")]"

Set regEx = New RegExp
regEx.Pattern = pattern
regEx.IgnoreCase = False
regEx.Global = True
replacedText = regEx.Replace(allText, replacer)

'UTF-8は処理できないので、Scripting.FileSystemObjectではなく asodb.streamを使う。
'Set fHandle = fso.OpenTextFile(toAssemblyInfoTemplateFileName, ForWriting, True)
'fHandle.Write replacedText
'fHandle.Close
Set OutStream = CreateObject("ADODB.Stream")
OutStream.Open
OutStream.Charset = "UTF-8"
OutStream.WriteText replacedText
OutStream.SaveToFile toAssemblyInfoTemplateFileName, adSaveCreateOverWrite
OutStream.Close

Set InStream = Nothing
Set OutStream = Nothing

 正規表現置換では、AssemblyVersionだけではなくAssemblyFileVersionにも同じリビジョンが入るようにしている。上記のスクリプトファイルをソリューションディレクトリに配置して、各プロジェクトのビルド前イベントに以下を設定した。

"$(SolutionDir)makeVersionInfoTemplate.vbs" $(ProjectDir)Properties\AssemblyInfo.cs $(ProjectDir)Properties\AssemblyInfoTemplate.txt

"C:\Program Files\TortoiseSVN\bin\SubWCRev.exe" "$(SolutionDir)\" $(ProjectDir)Properties\AssemblyInfoTemplate.txt  $(ProjectDir)Properties\AssemblyInfo.cs

del $(ProjectDir)Properties\AssemblyInfoTemplate.txt

 これでビルド番号はビルドの度にインクリメントしつつ、リビジョンはSubversionのリビジョンが使われるようになった。しかもテンプレートファイルをSubversionで管理する必要もない(なのでビルド前イベントの中だけで作成され削除される只の中間ファイルでしかなくなっている)。
 もうリリース作業の際にMajorとMinorをいじる以外には何もしなくて良くなった。良い感じ。

追記(2010/07/16)

微妙に、間違っていてうまく当たっていなかった。SolutionDirの末尾には\が付き、これが SubWCRev.exeに怒られていた。

The WorkingCopyPath contains a quotation mark.
this indicates a problem when calling SubWCRev from an interpreter which treats
a backslash char specially.
Try using double backslashes or insert a dot after the last backslash when
calling SubWCRev
Examples:
SubWCRev "path to wc\\"
SubWCRev "path to wc\."

\を外すことはできないので、\\とさせることでうまくいった。
↑はすでに修正している。