我的老笔记本上有个目录专门用来放感兴趣的SVN版本库,像是IronRuby、Parrot、Ruby之类。版本库的数量不少,而我以前一直都是在浏览器里手工去点击每个版本库的目录去做更新。太费事了,不爽。
于是刚才想找办法让这过程更自动化一些。不过发觉TortoiseSVN在无干预命令行批处理方面还是不太适合(毕竟它是个GUI客户端),所以跑到
SVN官网去下载了Subversion 1.4.6,安装。装好之后在命令行试了一下操作,没问题。
接下来就是如何自动化的问题了。我那些版本库不都是在同一嵌套层上的,有的深有的浅。例如说这样:
repository
+ IronRuby
* trunk
* Nemerle
+ Ruby
* Ruby_1_8
* trunk
星号标注的是要更新的目标。怎么办呢?只好递归搜索了。反正能找到带有".svn"目录的最上层目录就被认为是版本库目录,以它为标准来判断是不是要更新的目标;如果是目录但不是目标则遍历子目录来寻找目标。
于是简单的写了这样的Ruby脚本:
#!/usr/bin/ruby
def update_repo( path )
puts path
system "svn up \"#{path}\""
end
def locate_and_update( dir = "." )
entries = Dir.entries( dir ).reject do |item|
item =~ /^\.(?:\.|git|hg)?$/ # remove ".", "..", ".git", ".hg"
end
if entries.include? ".svn" # if this is a repo
update_repo dir # perform update
else # if this isn't a repo
entries.each do |e| # recursively search for repos
path = "#{dir}/#{e}"
locate_and_update path if File.directory? path
end
end
end
puts Time.now # show the time of update
locate_and_update # start from the working directory
把这个脚本放在我的repository目录里,它就能帮我更新整个目录里所有的SVN版本库。当然,递归搜索的效率不是太好——如果有任何一个目录里没有任何子目录是SVN版本库,这脚本恐怕要花上好长时间才能“知道”这点。要想快点的话可以改进上面的代码,让locate_and_update搜索一个内容是目录索引的配置文件,如果不存在的话就以深度优先搜索创建一个索引。那样就不用每次都对整个repository目录做全面搜索了。如果版本库的数量或者位置发生了改变,只要把那个索引文件删除它就应该重新生成索引,也不费事。
要完善的话还可以加点参数什么的,也可以做非交互式处理(传--non-interactive参数给svn)。不过上面的代码已经足够满足我自己的需求了,我的repository目录里全是SVN版本库,暂时没把git和Mercurial相关的东西放进来……所以懒得多写脚本了 ^ ^