由於每次將編譯好的程序提交時都要花費不少時間用來打包,所以我須要有一個讓程序自動完成這些瑣碎的工做。小程序
首先說一下個人目標。個人C#程序(在本文中暫時稱做Example.exe)編譯後暫時存放在Debug目錄中,該程序有兩種形態:平臺端和客戶端,它們分別給不一樣的用戶使用,這兩個客戶端的不一樣之處僅在與App.config(能夠被看作一個XML文件)中的配置不一樣。打包時須要先使用NSIS腳本對Debug目錄下的內容製做成安裝包,再使用WinRAR將安裝包進行壓縮。除了兩個安裝包外,還須要提供一些文件放置到自動更新的目錄下,這些文件須要單獨打成安裝包。緩存
爲此我使用VB.NET寫了一個小程序(暫時取名叫SoftwareRelease),來實現這個功能。app
配置文件以下:工具
<?xml version="1.0" encoding="gb2312"?> <!--SoftwareRelease配置文件--> <Config Software="SoftwareRelease"> <!--Debug目錄地址--> <DebugDir>D:\Example\bin\Debug</DebugDir> <!--打包完畢後軟件包所在目錄地址--> <ObjectDir>D:\ObjectPath</ObjectDir> <!--編譯器路徑 注意用 makensis.exe 而不是 makensisw.exe --> <CompilerPath>D:\NSIS\makensis.exe</CompilerPath> <!--"RAR壓縮工具路徑--> <WinRARPath>D:\WinRAR\rar.exe</WinRARPath> <!--編譯腳本路徑--> <ScriptList> <Script Name="platform" Directory="D:\PackageTools\打包腳本" Script="Platform.nsi" /> <Script Name="client" Directory="D:\PackageTools\打包腳本" Script="Client.nsi" /> </ScriptList> </Config>
將這個文件放置在編譯好的EXE文件相同路徑下便可。命令行
由於程序中要使用WinRAR和NSIS編譯工具,所以在配置文件中要寫明這兩個程序可執行文件的絕對路徑。debug
程序代碼以下:code
Imports System.Xml Imports System.IO ''' <summary> ''' SoftwareRelease 軟件自動打包工具 ''' </summary> ''' <remarks></remarks> Module ModuleMain ''' <summary> ''' SoftwareRelease 軟件自動打包工具 ''' </summary> ''' <remarks></remarks> Sub Main() '設置控制檯緩衝區大小 Console.BufferHeight = 5000 '控制檯文字顏色 - 青色 Console.ForegroundColor = ConsoleColor.Cyan '程序使用的標準時間 Dim dateTimeUni As DateTime = DateTime.Now Console.WriteLine("SoftwareRelease 軟件自動打包工具") Console.WriteLine("版本號:" & System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()) Console.WriteLine(New String("=", 20)) Console.WriteLine(dateTimeUni.ToString) Console.WriteLine() ' ----------- 一、讀入參數即相關準備工做 ----------- ' Dim Args As String() = System.Environment.GetCommandLineArgs() Dim bNeedPlatform As Boolean = False '打包平臺端 Dim bNeedClient As Boolean = False '打包客戶端 Dim bNeedUpdate As Boolean = False '打包自動更新文件 '分析傳入參數 If Args.Contains("/?") Or Args.Length = 1 Then '查看幫助 PrintUsage() Pause() Exit Sub ElseIf Args.Contains("/A") Or Args.Contains("/a") Then '全量包 bNeedPlatform = True bNeedClient = True bNeedUpdate = True Else If Args.Contains("/P") Or Args.Contains("/p") Then '打包平臺端 bNeedPlatform = True End If If Args.Contains("/C") Or Args.Contains("/c") Then '打包客戶端 bNeedClient = True End If If Args.Contains("/U") Or Args.Contains("/u") Then '打包自動更新文件 bNeedUpdate = True End If End If Console.WriteLine("本次執行任務:") If bNeedPlatform Then Console.WriteLine("打包平臺端") End If If bNeedClient Then Console.WriteLine("打包客戶端") End If If bNeedUpdate Then Console.WriteLine("打包自動更新文件") End If Console.WriteLine() '編譯完畢後程序目錄地址 Dim debugDir As String = "" '打包完畢後軟件包所在目錄地址 Dim objectDir As String = "" '編譯器路徑 Dim compilerPath As String = "" 'WinRAR壓縮工具路徑 Dim winRARPath As String = "" '編譯腳本所在目錄:平臺端 Dim scriptDirOfPlatform As String = "" '編譯腳本名稱:平臺端 Dim scriptFileOfPlatform As String = "" '編譯腳本所在目錄:客戶端 Dim scriptDirOfClient As String = "" '編譯腳本路徑:客戶端 Dim scriptFileOfClient As String = "" '讀取配置 Console.WriteLine("正在讀取配置...") Dim xmlDoc As XmlDocument = New XmlDocument() xmlDoc.Load("Config.xml") Dim xmlRoot As XmlNode = xmlDoc.SelectSingleNode("Config") For Each xmlObj In xmlRoot.ChildNodes If xmlObj.GetType().ToString() = "System.Xml.XmlElement" Then Dim xmlEle As XmlElement = DirectCast(xmlObj, XmlElement) Select Case xmlEle.Name Case "DebugDir" debugDir = xmlEle.InnerText.ToString.Trim Console.WriteLine("編譯完畢後程序目錄地址:" & debugDir) Case "ObjectDir" objectDir = xmlEle.InnerText.ToString.Trim Console.WriteLine("打包完畢後軟件包所在目錄地址:" & objectDir) Case "CompilerPath" compilerPath = xmlEle.InnerText.ToString.Trim Console.WriteLine("編譯器路徑:" & compilerPath) Case "WinRARPath" winRARPath = xmlEle.InnerText.ToString.Trim Console.WriteLine("WinRAR壓縮工具路徑:" & winRARPath) Case "ScriptList" For Each xmlObj2 In xmlEle.ChildNodes If xmlObj2.GetType().ToString() = "System.Xml.XmlElement" Then Dim xmlEle2 As XmlElement = DirectCast(xmlObj2, XmlElement) If xmlEle2.Name = "Script" And xmlEle2.GetAttribute("Name") = "platform" Then scriptDirOfPlatform = xmlEle2.GetAttribute("Directory").ToString Console.WriteLine("編譯腳本所在目錄(平臺端):" & scriptDirOfPlatform) scriptFileOfPlatform = xmlEle2.GetAttribute("Script").ToString Console.WriteLine("編譯腳本名稱(平臺端):" & scriptFileOfPlatform) End If If xmlEle2.Name = "Script" And xmlEle2.GetAttribute("Name") = "client" Then scriptDirOfClient = xmlEle2.GetAttribute("Directory").ToString Console.WriteLine("編譯腳本所在目錄(客戶端):" & scriptDirOfClient) scriptFileOfClient = xmlEle2.GetAttribute("Script").ToString Console.WriteLine("編譯腳本名稱(客戶端):" & scriptFileOfClient) End If End If Next Case Else End Select End If Next '釋放資源 xmlDoc.RemoveAll() xmlDoc = Nothing '判斷配置合法性 Dim isConfigLegal As Boolean = True If String.IsNullOrWhiteSpace(debugDir) Then Console.WriteLine("編譯完畢後程序目錄地址缺失") isConfigLegal = False End If If String.IsNullOrWhiteSpace(objectDir) Then Console.WriteLine("打包完畢後軟件包所在目錄地址缺失") isConfigLegal = False End If If String.IsNullOrWhiteSpace(compilerPath) Then Console.WriteLine("編譯器路徑缺失") isConfigLegal = False End If If String.IsNullOrWhiteSpace(winRARPath) Then Console.WriteLine("RAR壓縮工具路徑缺失") isConfigLegal = False End If If String.IsNullOrWhiteSpace(scriptDirOfPlatform) Then Console.WriteLine("編譯腳本所在目錄(平臺端)缺失") isConfigLegal = False End If If String.IsNullOrWhiteSpace(scriptFileOfPlatform) Then Console.WriteLine("編譯腳本名稱(平臺端)缺失") isConfigLegal = False End If If String.IsNullOrWhiteSpace(scriptDirOfClient) Then Console.WriteLine("編譯腳本所在目錄(客戶端)缺失") isConfigLegal = False End If If String.IsNullOrWhiteSpace(scriptFileOfClient) Then Console.WriteLine("編譯腳本名稱(客戶端)缺失") isConfigLegal = False End If If Not isConfigLegal Then Pause() Exit Sub End If Console.WriteLine("配置讀取完畢!") Console.WriteLine() ' ----------- 二、檢查Debug目錄 ----------- ' If Not Directory.Exists(debugDir) Then Console.WriteLine("待打包程序目錄不存在!") Pause() Exit Sub End If If Not File.Exists(debugDir + "\Example.exe") Then Console.WriteLine("待打包程序不存在!") Pause() Exit Sub End If If Not File.Exists(debugDir + "\Example.exe.config") Then Console.WriteLine("待打包程序關鍵配置文件缺失!") Pause() Exit Sub End If '清理掉全部pdb文件,這些文件是不須要的 Console.WriteLine("正在清理PDB文件") DeleteAllPdb(New DirectoryInfo(debugDir)) Console.WriteLine("正在清理登陸信息") '清理登陸信息,打包後的登陸信息必須是乾淨的 If File.Exists(debugDir + "\Config\LoginData.xml") Then 'TODO:清理登錄信息 End If Console.WriteLine("待打包程序目錄檢查完畢") Console.WriteLine() ' ----------- 三、將Debug目錄中的程序配置成平臺端 ----------- ' If bNeedPlatform Or bNeedUpdate Then Console.WriteLine("將程序設置爲平臺端") If (SetAppConfig(debugDir + "\Example.exe.config", "platform")) Then Console.WriteLine("設置完畢") Console.WriteLine() Else Console.WriteLine("設置失敗!") Pause() Exit Sub End If End If ' ----------- 四、複製一份,用於以後自動更新 ----------- ' If bNeedUpdate Then If (Directory.Exists(objectDir & "\platform")) Then Console.WriteLine("目錄【" & objectDir & "\platform】已存在,正在刪除該目錄") Directory.Delete(objectDir & "\platform", True) Console.WriteLine("刪除完畢!") End If Console.WriteLine("正在複製文件到目錄【" & objectDir & "\platform】") My.Computer.FileSystem.CopyDirectory(debugDir, objectDir & "\platform", True) Console.WriteLine("複製完畢!") Console.WriteLine("正在刪除冗餘文件") 'TODO:刪除冗餘文件(即不用自動更新下來的文件) Console.WriteLine("冗餘文件刪除完畢!") Console.WriteLine() End If ' ----------- 五、爲Debug目錄中內容打包 ----------- ' If bNeedPlatform Then Console.WriteLine("正在打包:平臺端") Shell(compilerPath & " " & scriptDirOfPlatform & "\" & scriptFileOfPlatform) Console.WriteLine("平臺端打包完畢") '壓縮到RAR文件 Dim packageName = scriptDirOfPlatform & "\平臺端打包後文件.exe" '這裏要作對應修改! If File.Exists(packageName) Then Dim rarName As String = dateTimeUni.ToString("yyyyMMdd") & "_PLATFORM.rar" 'a表示壓縮文件,-r表示遞歸,-ep表示忽略路徑信息 Shell(winRARPath & " a -ep " & objectDir & "\" & rarName & " " & packageName, AppWinStyle.NormalFocus, True) End If End If ' ----------- 六、將Debug目錄中的程序配置成客戶端 ----------- ' If bNeedClient Or bNeedUpdate Then Console.WriteLine("將程序設置爲客戶端") If (SetAppConfig(debugDir + "\Example.exe.config", "client")) Then Console.WriteLine("設置完畢") Console.WriteLine() Else Console.WriteLine("設置失敗!") Pause() Exit Sub End If End If ' ----------- 七、複製一份,用於以後自動更新 ----------- ' If bNeedUpdate Then If (Directory.Exists(objectDir & "\client")) Then Console.WriteLine("目錄【" & objectDir & "\client】已存在,正在刪除該目錄") Directory.Delete(objectDir & "\client", True) Console.WriteLine("刪除完畢!") End If Console.WriteLine("正在複製文件到目錄【" & objectDir & "\client】") My.Computer.FileSystem.CopyDirectory(debugDir, objectDir & "\client", True) Console.WriteLine("複製完畢!") Console.WriteLine("正在刪除冗餘文件") 'TODO:刪除冗餘文件(即不用自動更新下來的文件) Console.WriteLine("冗餘文件刪除完畢!") Console.WriteLine() End If ' ----------- 八、爲Debug目錄中內容打包 ----------- ' If bNeedClient Then Console.WriteLine("正在打包:客戶端") Shell(compilerPath & " " & scriptDirOfClient & "\" & scriptFileOfClient) Console.WriteLine("客戶端打包完畢") '壓縮到RAR文件 Dim packageName = scriptDirOfPlatform & "\客戶端打包後文件.exe" '這裏要作對應修改! If File.Exists(packageName) Then Dim rarName As String = dateTimeUni.ToString("yyyyMMdd") & "_CLIENT.rar" 'a表示壓縮文件,-r表示遞歸,-ep表示忽略路徑信息 Shell(winRARPath & " a -ep " & objectDir & "\" & rarName & " " & packageName, AppWinStyle.NormalFocus, True) End If End If ' ----------- 九、打包自動更新包 ----------- ' If bNeedUpdate Then Dim rarNameUpdate As String = dateTimeUni.ToString("yyyyMMdd") & "_UPDATE.rar" 'a表示壓縮文件,-r表示遞歸,-ep1表示忽略被壓縮的根文件夾 Dim command As String = winRARPath & " a -r -ep1 " & objectDir & "\" & rarNameUpdate & " " & objectDir & "\platform" & " " & objectDir & "\client" Shell(command, AppWinStyle.NormalFocus, True) End If Console.WriteLine("打包工做所有完成!") Pause() End Sub ''' <summary> ''' 配置AppConfig中的客戶端類型 ''' </summary> ''' <param name="appConfigPath">AppConfig文件路徑</param> ''' <param name="clientType">客戶端類型字符串</param> ''' <returns>true:修改爲功,false:修改失敗</returns> ''' <remarks></remarks> Function SetAppConfig(appConfigPath As String, clientType As String) Dim xmlAppConfig As XmlDocument = New XmlDocument xmlAppConfig.Load(appConfigPath) Dim xmlRoot As XmlNode = xmlAppConfig.SelectSingleNode("configuration") 'TODO:更改App.config中配置,更改爲功則 GoTo 到 END_CONFIG Return False END_CONFIG: xmlAppConfig.Save(appConfigPath) xmlAppConfig.RemoveAll() xmlAppConfig = Nothing Return True End Function ''' <summary> ''' 刪除全部PDB文件 ''' </summary> ''' <param name="dif"></param> ''' <remarks></remarks> Private Sub DeleteAllPdb(dif As DirectoryInfo) '遍歷各個子文件夾 For Each di As IO.DirectoryInfo In dif.GetDirectories DeleteAllPdb(di) Next For Each f As System.IO.FileInfo In dif.GetFiles If f.Extension.ToLower = ".pdb" Then f.Delete() End If Next End Sub ''' <summary> ''' 打印程序用法 ''' </summary> ''' <remarks></remarks> Sub PrintUsage() Dim Usage(7) As String Usage(0) = "程序使用方法" Usage(1) = "SoftwareRelease [ /? | /p | /c | /u | /a ]" Usage(2) = "沒有參數:顯示幫助,這與鍵入 /? 是同樣的" Usage(3) = "/p:打包平臺端" Usage(4) = "/c:打包客戶端" Usage(5) = "/u:打包自動更新包" Usage(6) = "/a:打包所有內容,至關於 /p /m /u 同時存在" Console.WriteLine(Join(Usage, vbCrLf)) End Sub ''' <summary> ''' 按任意鍵繼續 ''' </summary> ''' <remarks></remarks> Sub Pause() Console.WriteLine("按任意鍵繼續") System.Console.ReadKey() System.Console.Write(Chr(8) + " ") '刪除按下的「任意鍵」字符 End Sub End Module
以上代碼須要注意的方面有:orm
一、打包前要先刪除冗餘文件,如*.pdb文件。對於自動更新端,還要刪除那些可能會隨着每次登陸發生改變的文件和目錄(如本地緩存數據用的文件等)xml
二、WinRAR程序(rar.exe)和NSIS編譯工具(makensis.exe)都提供了功能強大的命令,能夠利用這些命令完成不少自動化操做內容。注意NSIS編譯工具使用makensis.exe而不是makensisw.exe,後者是一個具有GUI的工具,前者是爲命令行提供的工具。遞歸
三、本程序接收的命令行參數爲 /p(打包平臺端)、/c(打包客戶端)、/u(打包自動更新)、/a(打包所有)和/?(幫助),若是無參數則默認顯示幫助
四、控制檯緩衝區大小要設置得大一些,不然Windows的控制檯默認只支持保留最後的300行內容
五、爲了更方便使用本程序,能夠寫一個bat腳本直接調用本程序。內容以下:
SoftwareRelease.exe /a
END