Setting svn:keywords in many files simultaneously
因為同事「發現」了 Visual SourceSafe 的 keyword expansion 的功能,很開心地要用在「檔頭註解」[1]裡,於是我就推薦他使用 Id、Date、Revision 與 Author 這四個 keyword,因為這四個 keyword 在 VSS、CVS 與 Subversion 裡都可以用,且用法一樣。既然終於要正式用了,那我寫的那些程式早已經在用的「檔頭註解」,也要跟著對應過去才行。在剛開始的時候,Subversion (SVN) 只可以使用 Id、LastChangedDate、LastChangedRevision/Rev 與 LastChangedBy 等,所以我也都是用這幾個一直到現在。不過既然後來較通用的 Id、Date、Revision 與 Author 也可以用了[2],就趁此機會換回來。
理論上,我自己在 SVN 這邊用的時候,這些 keywords 可以被 SVN 端的值,然後 commit 進 VSS 的時候,又會被 VSS 代換成 VSS 端的值。對於使用 VSS 拿到我的程式的人來說,看到的是 VSS 端的值,對於使用 SVN 拿到我的程式的人來說,則看到的是 SVN 端的值。要用 VSS 就看到 VSS 的,要用 SVN 的就看到 SVN 的,互不干擾,很理想。而且,反正現在還沒人用 SVN[3],所以不會影響到他們。
不過,要整個換掉 svn:keywords 還是有些小麻煩,除了要修改 ~/.subversion/svn-config 讓以後新增的檔案都能預設使用新的 svn:keywords 以外,已經在 repository 裡的檔案,也得修改屬性,更改「檔頭註解」才行。
我第一個想法是,配合之前想作的 svn property line editor 功能,弄個 svn-set-prop.sh,除了整個取代掉原先的 property value 之外,還可以有 line-append、line-insert 的功能。前者會把新值加在舊值後面,而不是整個蓋掉,後者更強,以行為單位,若新值裡的行在舊值裡找不到,才會 append 進去。搭配最基本應該要有的 recursive 機能,這兩個功能蠻重要的,我已經碰過好幾次需要這種功能的情境了,不過我一直都還是在做苦工,這程式不太好寫。規劃的基本功能如下:
SHELL> svn-set-prop.sh --help Usage: svn-set-prop.sh [ <option> ... ] <prop-name> <prop-value> <url> Set Subversion property named <prop-name> to <prop-value> for files in <url> repository recursively. Options: -a,--append Append <prop-value> instead of replacing it. -i,--insert Insert line <prop-value> into property <prop-name> instead of replacing the whole property value in a line-oriented manner. That is, if line <prop-value> already exist in property <prop-name>, then it will not change. Otherwise, line value <prop-value> will be append to the property. Setting this option enables --append. -n,--name <pattern> File name pattern for search files to set properties. Format of <pattern> follows normal shell glob pattern. This option can be specified more than once. -e,--exist-only Update property value only if it exist. -p,--preview Preview file list before really affecting them. (Currently, --preview cannot filter out files that will not be affected if --insert or --exist-only are specified.) -h,--help Show this help message. Version: r616 (2006-01-26)
簡單弄了一下,結果看起來似乎沒有想像中的麻煩。除了 --preview 暫時偷懶,幾乎所有功能都很容易就搞定。不過,最後結果還是卡住了,我找不到簡單的方法 (不必動用暫存檔案) 快速地判斷某個檔案或目錄,是不是已經在 SVN 的控管之下。雖然最後沒有完成,但因為 --append 與 --insert 的功能很重要,所以我還是把半成品放進 ADE 了。
svn-set-prop.sh 還有一個很重要的功能就是 find like filtering,至少要能夠做到依據 file name pattern 決定是否要動手。既然嘗試寫作 svn-set-prop.sh 不成,轉念一想,已經有 wcfind.sh 對 working copy 作 find like filtering 了,何不也來個工具,直接對 repository 作 find like filtering?或是乾脆整合 wcfind.sh 的功能,讓它可以吃 <repo-url> 或 <wc-path> 都可以。於是我有了 svn-find.pl,準備把合適的 find 指令全放進來。寫著寫著,才又突然發覺,直接對 repository 動刀顯然不是個好主意。別說無法反悔讓人擔憂,若是我程式寫的不好,豈不變成找到一百個檔案,就多了一百個 commit 了嗎?這確實不是個好主意。
所以根本上來說,還是只能對 working copy 動刀才行。於是,靠著 wcfind.sh 與 in-place sed,簡單地解決了我的問題:
SHELL> wcfind.sh <wc-path> -type f \ -name 'Makefile' \ -or -name '*.h' -or -name '*.c' \ -or -name '*.hpp' -or -name '*.cpp' \ | sort \ | xargs -n 1 -t \ svn ps svn:keywords 'Id Date Revision Author' \ ; SHELL> wcfind.sh <wc-path> -type f \ -name 'Makefile' \ -or -name '*.h' -or -name '*.c' \ -or -name '*.hpp' -or -name '*.cpp' \ | sort \ | xargs -n 1 -t \ sed -i '' \ -e 's/$LastChangedDate/$Date/g' \ -e 's/$LastChangedRevision/$Revision/g' \ -e 's/$LastChangedBy/$Author/g' \ -e 's/$HeadURL/$URL/g' \ ;
如果 Subversion 對 pipe 進來的 property value 的感冒能夠治好的話,那 svn-set-prop.sh 的 --append 與 --insert 功能,我就可以另外弄成 str-list-append.sh 與 str-set-insert.sh[4],這樣各個功能便能夠更 atomic,更符合 UNIX 的精神,未來將會更為方便相互組合應用。
- 指程式檔案前面那塊註解,裡面放一些版權宣告、撰寫人、時等資訊的地方,而不是指 header files。 ↩
- 見 subversion: Issue 1287。又,多人關注的 subversion: Issue 890 似乎在最近的 1.3.0 release 還是沒有進去,滿心期待中。 ↩
- 早已經是飛機大砲的時代了,還要拿著石斧拼命,唉!下一次求職的時候,如果是使用 VSS 的公司,我絕對不考慮。 ↩
- 模仿一下 STL 的命名。 ↩



One Comment
發現用這個方法抓有哪些檔案要處理,會更好:
但是這個方法有一個缺點就是,沒辦法揪出那些應設
svn:keywords卻仍未設的檔案了。不過,應設仍未設的問題,可以另外處理。Post a Comment