因為同事「發現」了 Visual SourceSafe 的 keyword expansion 的功能,很開心地要用在「檔頭註解」[1]裡,於是我就推薦他使用 IdDateRevisionAuthor 這四個 keyword,因為這四個 keyword 在 VSS、CVS 與 Subversion 裡都可以用,且用法一樣。既然終於要正式用了,那我寫的那些程式早已經在用的「檔頭註解」,也要跟著對應過去才行。在剛開始的時候,Subversion (SVN) 只可以使用 IdLastChangedDateLastChangedRevision/RevLastChangedBy 等,所以我也都是用這幾個一直到現在。不過既然後來較通用的 IdDateRevisionAuthor 也可以用了[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-appendline-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.shstr-set-insert.sh[4],這樣各個功能便能夠更 atomic,更符合 UNIX 的精神,未來將會更為方便相互組合應用。


  1. 指程式檔案前面那塊註解,裡面放一些版權宣告、撰寫人、時等資訊的地方,而不是指 header files。
  2. subversion: Issue 1287。又,多人關注的 subversion: Issue 890 似乎在最近的 1.3.0 release 還是沒有進去,滿心期待中。
  3. 早已經是飛機大砲的時代了,還要拿著石斧拼命,唉!下一次求職的時候,如果是使用 VSS 的公司,我絕對不考慮。
  4. 模仿一下 STL 的命名。