安装了 VisualSVN Server 后,期望建立一个文件夹作为 web 服务器的根目录,同时作为开发人员提交代码的库。最开始我的解决办法是直接将这个文件夹作为 svn 的仓库和web服务器根目录 WWW,但这样不太好管理。后来得一个间接的办法来达到目的,建一个项目目录 A ,将其用作开发人员提交/更新代码的目录的源,再将这个目录自动同步到 web 服务器根目录下即可,为了达到这一目的,必须要写一个 svn 服务器勾子。勾子其实并不神秘,简而言之,它是程序提供的接口,提供一个“在什么事件发生时,执行何程序”的接口。勾子是一种程序,它执行于某个事件之后,而 svn 服务器程序留下了这样的接口,允许用户在执行某一个操作后,能任意地调用某个程序,这个程序即是服务器指定运行的勾子脚本。
问题发生在编写的这个勾子脚本中,我之前的脚本是这样写的:
"C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe" /command:update /path:C:\wamp\www2 /notempfile /closeonend:0
我模拟开发人员提交代码到 A 目录时,客户端显示提交文件到最后一个文件时就会卡住,不会继续往下运行。
此行,我猜测发生了下面的可能和解决办法
1.服务器端调用勾子程序的代码在等待勾子程序结束,而勾子程序一直没有退出,没有退出的原因可能在于,那句命令里面的TortoiseProc.exe 是个 GUI 程序,在同步到 WWW 目录后,会弹出一个窗口,必须要点击某个按钮后才能退出。从进程角度来讲,父进程在创建了子进程后,会有等待子进程运行完毕父进程继续执行,或者父进程在创建子进程后,不等子进程返回,继续向下执行两种行为,由于看不到 VisualSVN 的源代码,无从得知。TortoiseProc.exe确实 是一 GUI 程序,windows下GUI程序都是基于事件的,一旦有个事件没有发生,就一直阻塞。
解决办法:
a.在整个命令行前面加上 start,表示以空的 cmd 去运行勾子脚本,且是异步执行的,但此种解决办法不行,这与 VisualSVN调用勾子脚本时 CreateProcess 函数指定的参数有关,它可能与子进程(勾子脚本)的子进程(脚本里调用的其它程序)都关联了,必须等所有的后代进程退出后它才会返回,所以此种办法还是与服务器的实现关联,不能用这种办法。
b.经过查询手册,发现TortoiseProc.exe支持的 closeonend 参数的意义是,取 0 时表示这个GUI程序 update 后的窗口不关闭,取 1 时表示 update 没发生错误时关闭,等等其它的值,不再缀述,我们可以直接把这个参数的值设置为 1 即可:/closeonend:1,也即,命令行为:
"C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe" /command:update /path:C:\wamp\www2 /notempfile /closeonend:1
再试验,确实可以正常工作。
我们再看一下,这个勾子脚本的效率其实不高,因为 TortoiseProc.exe 是一个 GUI 程序,操作系统载入这个程序到进程中,会装载很多 GUI 资源,而这些资源其实不是必须的,因为我们只需要使用 TortoiseProc.exe 的 update 功能,所以就考虑使用命令行版的 TortoiseProc.exe,可以安装一个 VisualSVN 客户端,bin 目录下有一个 svn.exe,它就可以进行 update,将勾子脚本编写如下,作为最后的解决。
SET SVN="C:\Program Files (x86)\VisualSVN\bin\svn.exe"
SET DIR="C:\wamp\www2"
(call %SVN% update %DIR% --username lzh --password 874938 --non-interactive)