假设你需要添加一个使用访问权限控制列表的机制来指定哪些用户对项目的哪些部分有推送权限。某些用户具有全部的访问权,其他人只对某些子目录或者特定的文件具有推送权限。要搞定这一点,所有的规则将被写入一个位于服务器的原始 Git 仓库的 acl 文件。我们让 update 挂钩检阅这些规则,审视推送的提交内容中需要修改的所有文件,然后决定执行推送的用户是否对所有这些文件都有权限。
我们首先要创建这个列表。这里使用的格式和 CVS 的 ACL 机制十分类似:它由若干行构成,第一项内容是avail 或者 unavail,接着是逗号分隔的规则生效用户列表,最后一项是规则生效的目录(空白表示开放访问)。这些项目由 | 字符隔开。
下例中,我们指定几个管理员,几个对 doc 目录具有权限的文档作者,以及一个对 lib 和 tests 目录具有权限的开发人员,相应的 ACL 文件如下:
avail|nickh,pjhyett,defunkt,tpw
avail|usinclair,cdickens,ebronte|doc
avail|schacon|lib
avail|schacon|tests
首先把这些数据读入你编写的数据结构。本例中,为保持简洁,我们暂时只实现 avail 的规则(译注:也就是省略了 unavail 部分)。下面这个方法生成一个关联数组,它的主键是用户名,值是一个该用户有写权限的所有目录组成的数组:
[code]def get_acl_access_data(acl_file)
read in ACL data
acl_file = File.read(acl_file).split(“\n”).reject { |line| line == ‘’ }
access = {}
acl_file.each do |line|
avail, users, path = line.split(‘|’)
next unless avail == ‘avail’
users.split(‘,’).each do |user|
access[user] ||=
access[user] << path
end
end
access
end[/code]
针对之前给出的 ACL 规则文件,这个 get_acl_access_data 方法返回的数据结构如下:
{"defunkt"=>[nil],
"tpw"=>[nil],
"nickh"=>[nil],
"pjhyett"=>[nil],
"schacon"=>["lib", "tests"],
"cdickens"=>["doc"],
"usinclair"=>["doc"],
"ebronte"=>["doc"]}
搞定了用户权限的数据,下面需要找出哪些位置将要被提交的内容修改,从而确保试图推送的用户对这些位置有全部的权限。
使用 git log 的 --name-only 选项(在第二章里简单的提过)我们可以轻而易举的找出一次提交里修改的文件:
[code]$ git log -1 --name-only --pretty=format:‘’ 9f585d
README
lib/test.rb[/code]
使用 get_acl_access_data 返回的 ACL 结构来一一核对每一次提交修改的文件列表,就能找出该用户是否有权限推送所有的提交内容:
[code]# 仅允许特定用户修改项目中的特定子目录
def check_directory_perms
access = get_acl_access_data(‘acl’)
检查是否有人在向他没有权限的地方推送内容
new_commits = git rev-list #{$oldrev}..#{$newrev}
.split(“\n”)
new_commits.each do |rev|
files_modified = git log -1 --name-only --pretty=format:'' #{rev}
.split(“\n”)
files_modified.each do |path|
next if path.size == 0
has_file_access = false
access[$user].each do |access_path|
if !access_path || # 用户拥有完全访问权限
(path.index(access_path) == 0) # 或者对此位置有访问权限
has_file_access = true
end
end
if !has_file_access
puts “[POLICY] You do not have access to push to #{path}”
exit 1
end
end
end
end
check_directory_perms[/code]
以上的大部分内容应该都比较容易理解。通过 git rev-list 获取推送到服务器内容的提交列表。然后,针对其中每一项,找出它试图修改的文件然后确保执行推送的用户对这些文件具有权限。一个不太容易理解的 Ruby 技巧是 path.index(access_path) ==0 这句,它的返回真值如果路径以 access_path 开头——这是为了确保 access_path 并不是只在允许的路径之一,而是所有准许全选的目录都在该目录之下。
现在你的用户没法推送带有不正确的提交信息的内容,也不能在准许他们访问范围之外的位置做出修改。
REF:http://cwiki.ossez.com/pages/viewpage.action?pageId=7045937