Grasp.Today

SVN-钩子祥解与配置

钩子脚本的具体写法就是操作系统中shell脚本程序的写法,请根据自己SVN所在的操作系统和shell程序进行相应的写作


所谓钩子就是与一些版本库事件触发的程序,例如新修订版本的创建,或是未版本化属性的修改。每个钩子都会被告知足够多的信息,包括那是什么事件,所操作的对象,和触发事件的用户名。通过钩子的输出或返回状态,钩子程序能让工作继续、停止或是以某种方式挂起。

默认情况下,钩子的子目录中包含各种版本库钩子模板。

$ ls repos/hooks/
post-commit.tmpl          pre-revprop-change.tmpl
post-revprop-change.tmpl start-commit.tmpl
pre-commit.tmpl          

对每种Subversion版本库支持的钩子的都有一个模板,通过查看这些脚本的内容,你能看到是什么事件触发了脚本及如何给传脚本传递数据。同时,这些模版也是如何使用这些脚本,结合Subversion支持的工具来完成有用任务的例子。要实际安装一个可用的钩子,你需要在 repos/hooks目录下安装一些与钩子同名(如 start-commit或者post-commit)的可执行程序或脚本。


提示
由于安全原因,Subversion版本库在一个空环境中执行钩子脚本—就是没有任何环境变量,甚至没有$PATH或%PATH%。由于这个原因,许多管理员会感到很困惑,它们的钩子脚本手工运行时正常,可在Subversion中却不能运行。要注意,必须在你的钩子中设置好环境变量或为你的程序指定好绝对路径。

目前Subversion有已实现了五种钩子:

start-commit.bat
它在提交事务产生前已运行,通常用来判定一个用户是否有权提交。版本库传给该程序两个参数:到版本库的路径,和要进行提交的用户名。如果程序返回一个非零值,会在事务产生前停止该提交操作。如果钩子程序要在stderr中写入数据,它将排队送至客户端。

pre-commit.bat
在事务完成提交之前运行,通常这个钩子是用来保护因为内容或位置(例如,你要求所有到一个特定分支的提交必须包括一个bug追踪的ticket号,或者是要求日志信息不为空)而不允许的提交。版本库传递两个参数到程序:版本库的路径和正在提交的事务名称,如果程序返回非零值,提交会失败,事务也会删除。如果钩子程序在stderr中写入了数据,也会传递到客户端。

Subversion的分发版本包括了一些访问控制脚本(在Subversion源文件目录树的tools/hook-scripts目录),可以用来被pre-commit调用来实现精密的写访问控制。另一个选择是使用Apache的httpd模块mod_authz_svn,可以对单个目录进行读写访问控制(见“每目录访问控制”一节)。在未来的Subversion版本中,我们计划直接在文件系统中实现访问控制列表(ACL)。

post-commit.bat
它在事务完成后运行,创建一个新的修订版本。大多数人用这个钩子来发送关于提交的描述性电子邮件,或者作为版本库的备份。版本库传给程序两个参数:到版本库的路径和被创建的新的修订版本号。退出程序会被忽略。

Subversion分发版本中包括mailer.py和commit-email.pl脚本(存于Subversion源代码树中的 tools/hook-scripts/目录中)可以用来发送描述给定提交的email(并且或只是追加到一个日志文件),这个mail包含变化的路径清单,提交的日志信息、日期和作者以及修改文件的GNU区别样式输出。

Subversion提供的另一个有用的工具是hot-backup.py脚本(在Subversion源代码树中的tools/backup/目录中)。这个脚本可以为Subversion版本库进行热备份(Berkeley DB数据库后端支持的一种特性),可以制作版本库每次提交的快照作为归档和紧急情况的备份。

pre-revprop-change.bat
因为Subversion的修订版本属性不是版本化的,对这类属性的修改(例如提交日志属性 svn:log)将会永久覆盖以前的属性值。因为数据在此可能丢失,所以Subversion提供了这种钩子(及与之对应的post-revprop- change),因此版本库管理员可用一些外部方法记录变化。作为对丢失未版本化属性数据的防范,Subversion客户端不能远程修改修订版本属性,除非为你的版本库实现这个钩子。

这个钩子在对版本库进行这种修改时才会运行,版本库给钩子传递四个参数:到版本库的路径,要修改属性的修订版本,经过认证的用户名和属性自身的名字。

post-revprop-change.bat
我们在前面提到过,这个钩子与pre-revprop-change对应。事实上,因为多疑的原因,只有存在pre-revprop-change时这个脚本才会执行。当这两个钩子都存在时,post-revprop-change在修订版本属性被改变之后运行,通常用来发送包含新属性的email。版本库传递四个参数给该钩子:到版本库的路径,属性存在的修订版本,经过校验的产生变化的用户名,和属性自身的名字。

Subversion分发版本中包含propchange-email.pl脚本(在Subversion源代码树中的tools/hook- scripts/目录中),可以用来发送修订版本属性修改细节的email(并且或只是追加到一个日志文件)。这个email包含修订版本和发生变化的属性名,作出修改的用户和新属性值。

警告

不要尝试用钩子脚本修改事务。一个常见的例子就是在提交时自动设置svn:eol-style或svn:mime-type这类属性。这看起来是个好主意,但它会引起问题。主要的问题是客户并不知道由钩子脚本进行的修改,同时没有办法通告客户它的数据是过时的,这种矛盾会导致出人意料和不能预测的行为。

作为尝试修改事务的替代,我们通过检查pre-commit钩子的事务,在不满足要求时拒绝提交。
Subversion会试图以当前访问版本库的用户身份执行钩子。通常,对版本库的访问总是通过Apache HTTP服务器和mod_dav_svn进行,因此,执行钩子的用户就是运行Apache的用户。钩子本身需要具有操作系统级的访问许可,用户可以运行它。另外,其它被钩子直接或间接使用的文件或程序(包括Subversion版本库本身)也要被同一个用户访问。换句话说,要注意潜在的访问控制问题,它可能会让你的钩子无法按照你的目的顺利执行
原文:http://hi.baidu.com/gacmotor/blog/item/da499e2b4f65fa25d42af192.html

安装测试环境:109  CentOS4.6

安装:

SVN1.32http://subversion.tigris.org/downloads/subversion-1.3.2.tar.gz
安装:
解压:#: tar zxvf subversion-1.3.2.tar.gz
依次输入./configure , make , make install 进行编译安装完成。
开启SVN服务:svnserve -d
检测服务是否开启:netstat -ntlp如果看到3690的端口正常开放了,证明SVN启动了。

一、版本库钩子

3.1 start-commit  开始提交的通知

输入参数:传递给你钩子程序的命令行参数,顺序如下:

1.  版本库路径

2.  认证过的尝试提交的用户名

3.  Depth,mergeinfo,log-revprops

3.2 pre-commit 在提交结束之前提醒

输入参数:传递给你钩子程序的命令行参数。顺序是:

1.     版本库路径

2.     提交事务的名称

3.3 post-commit  成功提交的通知

传递给你钩子程序的命令行参数,顺序为:

1.     版本库路径

2.     提交创建的修订版本号

3.4 pre-revprop-change –修订版本属性修改的通知

这个钩子在修订版本属性修改之前,正常提交范围之外被执行,不像其它钩子,这个钩子默认是拒绝所有的属性修改,钩子必须要实际存在并且返回一个零值。 

----------------------SVN配置用户权限 -------------------------------------------

整理文档如下:

1.     建立SVN版本库目录(即你的SVN服务器里面的文件存放在哪个目录)

#mkdir -p /opt/svndata/repos1   

说明:svn mkdir  是其实是相当于#mkdir && svn add 操作。只差一步commit操作

Svn有许多操作是可以直接一步到位进行的!

2.     有了目录现在就可以创建SVN版本库

#svnadmin create /opt/svndata/repos1/

3.     编辑SVN的配置文件主要是权限这块的相关配置信息

#vi /opt/svndata/repos1/conf/svnserve.conf

[general]

anon-access = none

auth-access = write

password-db = passwd   #还可以指定到其它目录都是可以的

authz-db = authz

realm = repos1

4.     配置允许访问SVN的用户

#vi /opt/svndata/repos1/conf/passwd

[users]

test = test

5.     配置用户访问权限相关

#vi /opt/svndata/repos1/conf/authz

[groups]

admin = test

# harry_and_sally = harry,sally

[/]

@admin = rw

[repos1:/abc/aaa]

@admin = r

版本库目录格式:
[<版本库>:/项目/目录]    #是以项目名作为第一个单位。试想肯定是以项目为单元的
@<用户组名> = <权限>
<用户名> = <权限>

其中,方框号内部分可以有多种写法:
/,表示根目录及以下。根目录是svnserve启动时指定的,我们指定为/opt/svndata。这样,/就是表示对全部版本库设置权限。
repos1:/,表示对版本库1设置权限
repos2:/abc, ,表示对版本库2中的abc项目设置权限
repos2:/abc/aaa, ,表示对版本库2中的abc项目的aaa目录设置权限

权限主体可以是用户组、用户或*,用户组在前面加@,*表示全部用户。权限可以是w、r、wr和空,空表示没有任何权限。

6.     启动svnserve -d -r /opt/svndata/  

其中:
-d表示以daemon方式(后台运行)运行
-r /opt/svndata指定根目录是/opt/svndata

7.     现在有了仓库了就可以往仓库里面提交东西了。我们是以一个项目为单位的进行提交

#mkdir -p /var/www/dotproject  项目文件目录是在这。项目名称为dotproject

#svn import -m 'project' /var/www/dotproject svn://192.168.0.109/repos1

这个时候就会让你输入用户名与密码了

8.     从版本库中checkout东西

#mkdir myproj  && cd myproj  表示全部的项目都存在这个目录下面

#svn checkout svn://192.168.1.109/repos1 dotproect  表示把repos1里面的项目搞出来。

以上操作成功!以下是操作总结

1. #mkdir -p /opt/svndata/repos1

#svnadmin create /opt/svndata/repos1/

这样的话我们的SVN仓库的名称其实就是repos1  这个非常有用。在定义权限的时候有用

2. [repos1:/abc/aaa]   其中abc表示的是项目名称。像上面就是dotproject这个名称

@admin = r      表示这个组的用户可以进行读的权限

1.     svnserve -d -r /opt/svndata/    

-r /opt/svndata指定根目录是/opt/svndata #这个也非常有用!(哦明白了这个其实跟JSP里面的根目录一个效果如果指定了WEB项目的根目录了其实后面的文件或目录都是相对于这个根目录进行访问的。这里面如果我们指定了其实仓库的根目录的话后面的文件访问其实也是依据这个根目录进行的其中的 -d 参数表示 svnserve.exe 将会作为一个服务程序运行在后台,而 -r 参数表示将 D:\svn 目录指定为代码库的根目录。这样,当客户端使用类似 svn://192.168.0.1/foo 这样内容的 URL 来访问服务器时候,其所访问到的真实代码库,其实就是 D:\svn\foo)

3. svn import -m 'project' /var/www/dotproject svn://192.168.0.109/repos1

   其中这里面的dotproject就是项目名称了!

2.     svn checkout svn://192.168.1.109/repos1 dotproect  #表示将这个仓库中的这个项目提取出来

看我测试权限:

# vi /opt/svndata/repos1/conf/authz

[groups]

admin = test

[repos1:/dotproject/]

@admin = r               #让这个用户只有读的权限

现在到项目目录下面就不可以再commit动作了

--no-auth-cache –username rory --password 8809117 

1.     我编辑/opt/svndata/repos1/hooks/ pre-commit  这个文件里面的内容如下:

#!/bin/bash

REPOS="$1"

TXN="$2" 

# Make sure that the log message contains some text.

SVNLOOK=/usr/local/bin/svnlook

$SVNLOOK log -t "$TXN" "$REPOS" | \

   grep "[a-zA-Z0-9]" > /tmp/aaa || exit 1 

# Check that the author of this commit has the rights to perform

# the commit on the files and directories being modified.

# commit-access-control.pl "$REPOS" "$TXN" commit-access-control.cfg || exit 1 

# All checks passed, so allow the commit.

exit 0         #返回0表示允许提交?

运行这段程序正常了!

然后我将其换成我自己的脚本看:(这台正常了哦哦!)

#!/bin/bash

/bin/echo "a" >> /tmp/aaa.out      成功记录日志

# exit 1 

#REPOS="$1"

#TXN="$2" 

# Make sure that the log message contains some text.

#SVNLOOK=/usr/local/bin/svnlook

#$SVNLOOK log -t "$TXN" "$REPOS" | \

#   grep "[a-zA-Z0-9]" > /tmp/aaa || exit 1 

# Check that the author of this commit has the rights to perform

# the commit on the files and directories being modified.

# commit-access-control.pl "$REPOS" "$TXN" commit-access-control.cfg || exit 1 

# All checks passed, so allow the commit.

exit 0

 -rwxr-xr-x  1 root root  494 Nov  1 13:21 pre-commit

 OK我们现在来写一个成功svn-commit之后要触发的一个钩子

#!/bin/bash

REPOS="$1"

TXN="$2"

/bin/echo "eeeee" >> /tmp/dddddsvn.out   成功!

 OK!现在换一个python脚本来试试

我想让SVN在提交之后执行一段python程序

#!/usr/bin/env python   #这一段的意义就是当将这个python程序置成可执行时候。它会去哪寻找python。如果没有这段的话将其设置成可执行的时候就不会跑起来

if __name__ == '__main__':

   import sys,string

   try:

     logfile = open('/tmp/python.out','a+')  #简单写个日志记录一下

     logfile.write("this is a python hook")

     logfile.close()

   except:

     exit(1)

   sys.exit(0)

 然后在post-commit里面的代码如下:

#!/bin/bash

REPOS="$1"

TXN="$2"

/usr/bin/python /opt/svndata/repos1/hooks/so.py  #直接调用这段python程序

 OK!现在来编写SVNUPDATE这块的代码。

实现原理:当用户提交commit动作发生都让另外一处project马上从仓库中进行代码checkout一份出来! 

说明:post-commit会接受两个参数

REPOS="$1"      /opt/svndata/repos1  表示svn仓库的绝对路径值

TXN="$2"         表示最新的一个版本号。最后一个版本号

来看看update的相关参数项

对它的描述如下:

Svn update会把版本库的修改带到工作拷贝(工作拷贝的理解其实就是一个工作区)中。如果没有给定修订的版本它就会把当前的工作拷贝更新到HEAD最新版本。否则就是它会把工作拷贝更新到指定的修订版本即—revision后面所带的参数值。为了保持同步svn update也会删除所有在工作拷贝发现的无效锁定。 

正式的代码如下:

#vi /opt/svndata/repos1/hooks/post-commit

#!/bin/bash

/usr/local/bin/svn  update /home/myproject/dotproect/ --username test --password test

if [ $? == 0 ]

then

        echo "ok" >> /tmp/z.out

fi

    测试发现当我修改一个文件然后再commit提交的时候另外一个项目位置是可以。 

现在正式搭建SVN的环境。包括用户权限相关的内容!

--------------------------搭建puppet与svn环境--------------------------------

环境:108

项目名称:puppet

项目代码目录:mkdir -p /var/www/puppet  (将/etc/puppet下面的东西先cp过来)

代码仓库名称:repos1

仓库的目录:mkdir -p /opt/svndata/repos1

到时会在/etc/ 下面进行一次一次checkout将项目直接checkout到etc目录下面

#svn checkout svn://192.168.0.109/repos1 puppet   #表示将这个项目直接checkout下来(可以先在一个目录进行测试下看看)

具体步骤如下:

整理文档如下:

9.     建立SVN版本库目录(即你的SVN服务器里面的文件存放在哪个目录)

#mkdir -p /opt/svndata/repos1   

说明:svn mkdir  是其实是相当于#mkdir && svn add 操作。只差一步commit操作

Svn有许多操作是可以直接一步到位进行的!

10.  有了目录现在就可以创建SVN版本库

#svnadmin create /opt/svndata/repos1/

11.  编辑SVN的配置文件主要是权限这块的相关配置信息

#vi /opt/svndata/repos1/conf/svnserve.conf

[general]

anon-access = none

auth-access = write

password-db = passwd   #还可以指定到其它目录都是可以的

authz-db = authz

realm = repos1

12.  配置允许访问SVN的用户

#vi /opt/svndata/repos1/conf/passwd

[users]

test = test

13.  配置用户访问权限相关

#vi /opt/svndata/repos1/conf/authz

[groups]

admin = test

# harry_and_sally = harry,sally

[/]

@admin = rw

[repos1:/abc/aaa]

@admin = r

版本库目录格式:
[<版本库>:/项目/目录]    #是以项目名作为第一个单位。试想肯定是以项目为单元的
@<用户组名> = <权限>
<用户名> = <权限>

其中,方框号内部分可以有多种写法:
/,表示根目录及以下。根目录是svnserve启动时指定的,我们指定为/opt/svndata。这样,/就是表示对全部版本库设置权限。
repos1:/,表示对版本库1设置权限
repos2:/abc, ,表示对版本库2中的abc项目设置权限
repos2:/abc/aaa, ,表示对版本库2中的abc项目的aaa目录设置权限

权限主体可以是用户组、用户或*,用户组在前面加@,*表示全部用户。权限可以是w、r、wr和空,空表示没有任何权限。

14.  启动svnserve -d -r /opt/svndata/  

其中:
-d表示以daemon方式(后台运行)运行
-r /opt/svndata指定根目录是/opt/svndata

15.  现在有了仓库了就可以往仓库里面提交东西了。我们是以一个项目为单位的进行提交

#mkdir -p /var/www/puppet    项目文件目录是在这。项目名称为dotproject

#svn import -m 'project' /var/www/puppet  svn://192.168.0.109/repos1

这个时候就会让你输入用户名与密码了(注意passwz里面不要有前缀空格)

16.  从版本库中checkout东西

(先:#rm –rf /puppet/)将puppet目录先删除掉。再执行这一条命令。我觉得这太绕了!!!这样的话就会有这个目录而且这里面的文件均进来了!

#svn checkout svn://192.168.0.109/repos1 puppet  表示把repos1里面的项目搞出来。

17.  编写这个SVN的钩子

#!/bin/bash

/usr/local/bin/svn  update /home/myproject/dotproect/ --username test --password test

if [ $? == 0 ]

then

echo "ok" >> /tmp/z.out

fi

----------------然后就可以在WINDOWS平台连接过来。进行操作然后直接SVN提交。 

--------------------------高级应用篇-----------------------------------------

1.     如何精确地进行用户权限划分

示例:对于modules目录里面的划分非常强烈。比如apache/  mysql/目录其中mysql用户只能管理mysql里面的东西。Apache用户只能管理apache里面东西

WIN平台要想让TV不记密码可以将:

C:\Documents and Settings\Administrator\Application Data\Subversion\auth里面的全部文件给删除掉即可!

Authz文件配置如下:

[groups]

admin = test

db = mysql

www = apache

[repos1:/]

test = rw

[repos1:/modules/mysql]

mysql = rw

*=

[repos1:/modules/apache]            原来上面的写法说第一节表示项目名称是错了。

apache = rw

*=

这样一写我就可以控制某个目录某个用户的访问权限了!将来puppet本身的配置文件管理是可以这样进行细分的! 

2.     如果将一个目录删除掉了如何同步呢?

假设你使用Windows的客户端TortoiseSVN,你可以这样操作:
1。在工作目录下,选中要删除的文件和目录.
2。右键,点击菜单TortoiseSVN -> Delete,这时会看到那些文件已经没了
3。然后执行commit,会看到在提交对话框中出现了那些删除文件
提交后,这些文件和目录就被删除了
其它开发者update一下,他们工作目录的那些文件也相应地被删除

优点:在操作时看不到多余的文件,版本号保留了

缺点:库大小还是没有变 

使用命令操作如下:

#svn delete test        将这个文件或目录给删除掉

#svn commit -m 'delete test' 将其提交一下 

现在换到客户端进行删除文件

按照上面的说法进行操作成功将文件删除掉!

------------------------到此!成功配置完成SVN+PUPPET---------------------------

(全文完.)

原文地址:http://blog.chinaunix.net/uid-25525723-id-360264.html

 

 

 

 

posted @ 2013-06-25 12:24  gaohj  阅读(23287)  评论(0编辑  收藏  举报