什么是SVN Hook
SVN hook 腳本,大都譯為SVN鉤子,提供了一種非常強(qiáng)大而且靈活的方式把代碼庫(kù)的各種事件與自定義操作聯(lián)系起來(lái)。舉個(gè)例子來(lái)說(shuō),代碼提交到服務(wù)器以前要進(jìn)行基于自定義規(guī)則的審查和檢查,審查通過(guò)則繼續(xù)提交,審查失敗則拒絕提交。
客戶(hù)端Hook VS 服務(wù)器端Hook
服務(wù)器端Hook
服務(wù)器端Hook腳本程序在服務(wù)器上執(zhí)行,鉤子可以調(diào)用bat批處理文件(在Windows系統(tǒng)中)、bash腳本、可執(zhí)行文件或者一些類(lèi)似于perl、python等的腳本,一共提供了一下9種情況來(lái)實(shí)現(xiàn)不同階段的自定義操作:
-
關(guān)于鎖定的2種
- pre-lock
- post-lock
-
關(guān)于解鎖的2種
- pre-unlock
- post-unlock
-
關(guān)于提交的3種
- start-commit
- pre-commit
- post-commit
-
關(guān)于屬性的2種
- pre-revprop-change
- post-revprop-change
使用svn admin create命令創(chuàng)建出來(lái)的代碼倉(cāng)庫(kù),根目錄下面有個(gè)hooks文件夾,里面已經(jīng)預(yù)置了上述幾種鉤子腳本的模板,看了一下里面是bash腳本,如下圖所示。如果要自定義其中的某一個(gè),比如pre-commit.tmpl,把該文件拷貝一份并且重命名為pre-commit,注意要有可執(zhí)行權(quán)限!
客戶(hù)端Hook
svn的客戶(hù)端也具備Hook的功能,比如windows上常用的TortoiseSVN,可以在設(shè)置的界面中設(shè)置腳本程序的類(lèi)型、工作目錄、執(zhí)行命令等內(nèi)容。如下圖所示。
兩者對(duì)比
對(duì)比兩者的作用、功能以及實(shí)現(xiàn)方式,大概有下面幾點(diǎn)不同:
- 作用范圍不同:服務(wù)器端的hook作用于所有提交到svn server上面的代碼;而客戶(hù)端只是在本機(jī)上進(jìn)行檢查;
- 提供的鉤子類(lèi)型不同:從上述圖片中可以看到兩者所提供的鉤子類(lèi)型存在差別;
- 執(zhí)行環(huán)境不同:客戶(hù)端的環(huán)境復(fù)雜多樣,Windows、Linux、Mac OS X都有,每個(gè)系統(tǒng)上執(zhí)行hook腳本的環(huán)境是不同的,所以客戶(hù)端腳本很難做到統(tǒng)一。并且,不同公司出品的客戶(hù)端可能在hook的功能上還會(huì)有所差別(沒(méi)仔細(xì)研究其他SVN客戶(hù)端產(chǎn)品,純屬猜測(cè))。服務(wù)器雖然也有不同的操作系統(tǒng),不過(guò)定下系統(tǒng)之后,svn服務(wù)器端hook腳本的執(zhí)行環(huán)境相對(duì)單一。
- hook腳本實(shí)現(xiàn)方式不同:SVN客戶(hù)端的代碼庫(kù)是以文本形式存儲(chǔ)的源代碼,想要進(jìn)行什么操作都可以,自由度很高;上傳到服務(wù)器上的代碼都是二進(jìn)制文件,存儲(chǔ)在代碼庫(kù)的DB中,需要配合svnlook等命令來(lái)使用。
實(shí)戰(zhàn)一下
下面記錄了本次使用Python腳本做pre-commit鉤子的示例,在該示例中展示了幾種主要的功能,svnlook log, svnlook changed, svnlook cat三個(gè)命令的使用方法。注意,該示例摘自完整腳本,只是示意用法,不能直接運(yùn)行。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import os
import re
def main(argv):
# 從參數(shù)中取出來(lái)代碼庫(kù)和事務(wù)信息
(repos, txn) = argv
# svnlook log拿到的是用戶(hù)提交時(shí)填寫(xiě)的log信息,然后隨便你想做什么
message = "".join(os.popen("svnlook log '%s' -t '%s'" % (repos, txn)).readlines()).strip()
# svnlook changed拿到的是用戶(hù)提交的文件,這個(gè)列表中有文件的狀態(tài)(A,U,D之類(lèi)的)和文件名
changelist = os.popen("svnlook changed '%s' -t '%s'" % (repos, txn)).readlines()
# svnlook cat能讀出用戶(hù)提交文件的內(nèi)容
fileContent = "".join(os.popen("svnlook cat -t %s %s %s" % (txn, repos, filename)).readlines()).strip()
# 返回
if msg == '':
sys.exit(0)
else:
# 輸出返回信息
sys.stderr.write(msg)
sys.exit(1)
if __name__ == "__main__":
# sys.stderr.write(os.getcwd())
# 發(fā)現(xiàn)默認(rèn)的工作目錄竟然是跟目錄“/”,這里要換一下當(dāng)前工作目錄
os.chdir(sys.path[0])
# sys.stderr.write(os.getcwd())
main(sys.argv[1:])
有幾點(diǎn)要交代:
- 腳本返回0的話(huà),svn客戶(hù)端會(huì)提交成功;腳本返回非0,客戶(hù)端提交代碼失敗;
- 返回給客戶(hù)端的錯(cuò)誤信息,需要腳本輸出到標(biāo)準(zhǔn)錯(cuò)誤輸出;
- 如果跟執(zhí)行環(huán)境配置有關(guān)的話(huà),工作目錄要切換;
- svnlook命令有很多,可以參考5。
參考4是Github上的一個(gè)完整的示例,感謝作者,供參考。
參考
- https://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-settings.html#tsvn-dug-settings-hooks
- https://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-repository-hooks.html
- http://wordaligned.org/articles/a-subversion-pre-commit-hook
- https://github.com/lisijie/python-svn-hook/blob/master/pre-commit.py
- http://svnbook.red-bean.com/nightly/en/svn.ref.svnlook.html