根據工作需要,項目將采用SVN做版本控制,於是乎就安裝了如下軟件:
1、TortoiseSVN Version:1.6.7
2、Subversion Version:1.6.5
3、VisualSVN Version:2.0.6
其中1是SVN客戶端,2是服務器,3是用於與VS .Net framework集成的組件。
具體安裝步驟就不多講了,網上很多帖子都詳細描述過了,本文主要講的是如何實現最新提交自動更新到測試服務器工作副本。
背景:
為什么要實現SVN自動更新呢?因為實際開發過程中,程序員一般都是在本地開發機上開發,本地驗證無誤后上傳至測試服務器驗證生產環境正確性,修改代碼多的時候,上傳文件也是一件累人的活,還浪費時間,所以就有了實現SVN自動更新到測試服務器工作副本的需求,既省時,又能保證文件不遺漏。
過程:
要實現SVN自動更新,無非就是使用SVN的鈎子,網絡上不少帖子都是講如何通過版本庫hooks文件夾下post-commit文件實現自動更新的,有的是寫成.bat文件,有的是shell腳本。筆者開始是借鑒網上的方法,寫成了post-commit.bat文件,實現了自動更新。但是,由於我們的項目比較大,寫成.bat文件的話,就只能在根目錄下執行update操作,速度非常的慢,大概是2分鍾。是可忍孰不可忍,於是上網查找,發現.exe文件也可以作為鈎子程序嘛,這不就簡單了,於是用C#寫了個Winform程序,commit+update瞬間完成!下面是C#代碼,有詳細的備注,供大家參考!
1
using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Text;
7 using System.Windows.Forms;
8 using System.Diagnostics;
9 using System.IO;
10 using System.Text.RegularExpressions;
11
12 namespace SVNGetTheLastRes
13 {
14 public partial class Form1 : Form
15 {
16 /// <summary>
17 ///
18 /// </summary>
19 public Form1()
20 {
21 InitializeComponent();
22 }
23
24 private void Form1_Load( object sender, EventArgs e)
25 {
26 try
27 {
28 // 查找最近更新文件,並將命令返回結果輸出至txt文件
29 Execute( " svnlook changed D:/subversion/project1 > D:/Subversion/project1/hooks/test.txt ");
30
31 // 讀取生成的文件
32 string strPath = ResumeTxt( " D:/Subversion/project1/hooks/test.txt ");
33
34 // 文件內容處理:按換行符將讀取的字符串轉換成字符串數組
35 string[] aryPath = strPath.Split( ' \n ');
36
37 // 循環更新文件
38 for ( int i = 0; i < aryPath.Length; i++)
39 {
40 // 處理掉回車符
41 aryPath[i].Replace( ' \r ', ' ');
42
43 // 經測試,文件中最后一行是空行,但為了避免遺漏,用非空判斷,而不是循環的length-1
44 if (!aryPath[i].Trim().Equals( ""))
45 {
46 // 根據文件中的數據格式,從第五個字符開始才是文件路徑
47 string strFile = aryPath[i].Trim().Substring( 4);
48 // 組織命令並執行,其中D:/是項目所在文件夾,根據自己的情況組織
49 string strCmd = " svn update D:/ " + strFile + " --username *** --password *** ";
50 Execute(strCmd);
51 }
52 }
53 }
54 catch (Exception ex)
55 {
56
57 }
58 finally
59 {
60 this.Close();
61 }
62 }
63
64 public string ResumeTxt( string path)
65 {
66 string str = string.Empty;
67
68 StreamReader reader = new StreamReader(path, System.Text.Encoding.Default);
69 str = reader.ReadToEnd();
70
71 // 再通過查詢解析出來的的字符串有沒有GB2312的字段,來判斷是否是GB2312格式的,如果是,則重新以GB2312的格式解析
72 Regex reGB = new Regex( " GB2312 ", RegexOptions.IgnoreCase);
73 Match mcGB = reGB.Match(str);
74 if (mcGB.Success)
75 {
76 StreamReader reader2 = new StreamReader(path, System.Text.Encoding.GetEncoding( " GB2312 "));
77 str = reader2.ReadToEnd();
78 }
79
80 return str;
81 }
82
83 /// <summary>
84 /// 執行DOS命令並返回結果
85 /// </summary>
86 /// <param name="dosCommand"> Dos命令語句 </param>
87 /// <returns> DOS命令返回值 </returns>
88 public string Execute( string dosCommand)
89 {
90 return Execute(dosCommand, 0);
91 }
92
93 /// <summary>
94 /// 執行DOS命令,返回DOS命令的輸出
95 /// </summary>
96 /// <param name="dosCommand"> dos命令 </param>
97 /// <param name="milliseconds"> 等待命令執行的時間(單位:毫秒),如果設定為0,則無限等待 </param>
98 /// <returns> 返回DOS命令的輸出 </returns>
99 public static string Execute( string dosCommand, int seconds)
100 {
101 string output = ""; // 輸出字符串
102 if (dosCommand != null && dosCommand != "")
103 {
104 Process process = new Process(); // 創建進程對象
105 ProcessStartInfo startInfo = new ProcessStartInfo();
106 startInfo.FileName = " cmd.exe "; // 設定需要執行的命令
107 startInfo.Arguments = " /C " + dosCommand; // 設定參數,其中的“/C”表示執行完命令后馬上退出
108 startInfo.UseShellExecute = false; // 不使用系統外殼程序啟動
109 startInfo.RedirectStandardInput = false; // 不重定向輸入
110 startInfo.RedirectStandardOutput = true; // 重定向輸出
111 startInfo.CreateNoWindow = true; // 不創建窗口
112 process.StartInfo = startInfo;
113 try
114 {
115 if (process.Start()) // 開始進程
116 {
117 if (seconds == 0)
118 {
119 process.WaitForExit(); // 這里無限等待進程結束
120 }
121 else
122 {
123 process.WaitForExit(seconds); // 這里等待進程結束,等待時間為指定的毫秒
124 }
125 output = process.StandardOutput.ReadToEnd(); // 讀取進程的輸出
126 }
127 }
128 catch
129 {
130
131 }
132 finally
133 {
134 if (process != null)
135 process.Close();
136 }
137 }
138 return output;
139 }
140 }
141 }
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Text;
7 using System.Windows.Forms;
8 using System.Diagnostics;
9 using System.IO;
10 using System.Text.RegularExpressions;
11
12 namespace SVNGetTheLastRes
13 {
14 public partial class Form1 : Form
15 {
16 /// <summary>
17 ///
18 /// </summary>
19 public Form1()
20 {
21 InitializeComponent();
22 }
23
24 private void Form1_Load( object sender, EventArgs e)
25 {
26 try
27 {
28 // 查找最近更新文件,並將命令返回結果輸出至txt文件
29 Execute( " svnlook changed D:/subversion/project1 > D:/Subversion/project1/hooks/test.txt ");
30
31 // 讀取生成的文件
32 string strPath = ResumeTxt( " D:/Subversion/project1/hooks/test.txt ");
33
34 // 文件內容處理:按換行符將讀取的字符串轉換成字符串數組
35 string[] aryPath = strPath.Split( ' \n ');
36
37 // 循環更新文件
38 for ( int i = 0; i < aryPath.Length; i++)
39 {
40 // 處理掉回車符
41 aryPath[i].Replace( ' \r ', ' ');
42
43 // 經測試,文件中最后一行是空行,但為了避免遺漏,用非空判斷,而不是循環的length-1
44 if (!aryPath[i].Trim().Equals( ""))
45 {
46 // 根據文件中的數據格式,從第五個字符開始才是文件路徑
47 string strFile = aryPath[i].Trim().Substring( 4);
48 // 組織命令並執行,其中D:/是項目所在文件夾,根據自己的情況組織
49 string strCmd = " svn update D:/ " + strFile + " --username *** --password *** ";
50 Execute(strCmd);
51 }
52 }
53 }
54 catch (Exception ex)
55 {
56
57 }
58 finally
59 {
60 this.Close();
61 }
62 }
63
64 public string ResumeTxt( string path)
65 {
66 string str = string.Empty;
67
68 StreamReader reader = new StreamReader(path, System.Text.Encoding.Default);
69 str = reader.ReadToEnd();
70
71 // 再通過查詢解析出來的的字符串有沒有GB2312的字段,來判斷是否是GB2312格式的,如果是,則重新以GB2312的格式解析
72 Regex reGB = new Regex( " GB2312 ", RegexOptions.IgnoreCase);
73 Match mcGB = reGB.Match(str);
74 if (mcGB.Success)
75 {
76 StreamReader reader2 = new StreamReader(path, System.Text.Encoding.GetEncoding( " GB2312 "));
77 str = reader2.ReadToEnd();
78 }
79
80 return str;
81 }
82
83 /// <summary>
84 /// 執行DOS命令並返回結果
85 /// </summary>
86 /// <param name="dosCommand"> Dos命令語句 </param>
87 /// <returns> DOS命令返回值 </returns>
88 public string Execute( string dosCommand)
89 {
90 return Execute(dosCommand, 0);
91 }
92
93 /// <summary>
94 /// 執行DOS命令,返回DOS命令的輸出
95 /// </summary>
96 /// <param name="dosCommand"> dos命令 </param>
97 /// <param name="milliseconds"> 等待命令執行的時間(單位:毫秒),如果設定為0,則無限等待 </param>
98 /// <returns> 返回DOS命令的輸出 </returns>
99 public static string Execute( string dosCommand, int seconds)
100 {
101 string output = ""; // 輸出字符串
102 if (dosCommand != null && dosCommand != "")
103 {
104 Process process = new Process(); // 創建進程對象
105 ProcessStartInfo startInfo = new ProcessStartInfo();
106 startInfo.FileName = " cmd.exe "; // 設定需要執行的命令
107 startInfo.Arguments = " /C " + dosCommand; // 設定參數,其中的“/C”表示執行完命令后馬上退出
108 startInfo.UseShellExecute = false; // 不使用系統外殼程序啟動
109 startInfo.RedirectStandardInput = false; // 不重定向輸入
110 startInfo.RedirectStandardOutput = true; // 重定向輸出
111 startInfo.CreateNoWindow = true; // 不創建窗口
112 process.StartInfo = startInfo;
113 try
114 {
115 if (process.Start()) // 開始進程
116 {
117 if (seconds == 0)
118 {
119 process.WaitForExit(); // 這里無限等待進程結束
120 }
121 else
122 {
123 process.WaitForExit(seconds); // 這里等待進程結束,等待時間為指定的毫秒
124 }
125 output = process.StandardOutput.ReadToEnd(); // 讀取進程的輸出
126 }
127 }
128 catch
129 {
130
131 }
132 finally
133 {
134 if (process != null)
135 process.Close();
136 }
137 }
138 return output;
139 }
140 }
141 }
需要注意的是,用update命令更新時,要求測試服務器工作副本必須是受控的,否則,應該改用export命令,export命令用法請查看"SVN export --help"。
結果:
實現了SVN自動更新的功能。實際上,既然能用exe程序作為SVN鈎子使用,那就可以擴展很多功能了,包括每次更新的郵件提醒,甚至是重要文件更新時的短信提醒,還能做文件更新日志等等。