1.前言
本篇将介绍如何编译安装SVN服务器端管理软件subverion和Web服务器Apache。本来在前面的系列文章已经讲过使用Nginx作为Web服务器的,所以我一直在找有关subverion集成nginx的资料,在此过程中找到了Nginx作者Igor Sysoev在回答别人类似问题的网址,网址是http://mailman.nginx.org/pipermail/nginx/2007-January/000504.html,不过按照Igor Sysoev的回答并没有成功,因此仍回到Apache与SVN集成,然后再通过Nginx反向代理到Apache的办法。本来直接安装subversion即可实现版本控制,但由于这种方式有一些问题,比如密码是明文保存到文件的,因此采用了Apache集成Nginx的方式。
2.准备
本篇主要讲述编译和配置subversion和Apache(即httpd),但由于编译这两个软件依赖于别的类库,于是总共需要下面7个文件才能完成subverion1.9.5和httpd2.4.25的编译安装,即apr、apr-util、scons、serf、sqlite-amalgamation、httpd和subversion。
我们以root的身份登录系统,将其通过wget下载到/root目录下。
subversion-1.9.5:wget http://mirrors.hust.edu.cn/apache/subversion/subversion-1.9.5.tar.gz
httpd-2.4.25:wget https://mirrors.tuna.tsinghua.edu.cn/apache//httpd/httpd-2.4.25.tar.gz
serf-1.3.9:wget https://www.apache.org/dist/serf/serf-1.3.9.tar.bz2
scons-2.5.1:wget http://prdownloads.sourceforge.net/scons/scons-2.5.1.tar.gz
sqlite-amalgamation-3190300:wget http://www.sqlite.org/2017/sqlite-amalgamation-3190300.zip
apr-1.5.2:wget http://mirrors.tuna.tsinghua.edu.cn/apache//apr/apr-1.5.2.tar.gz
apr-util-1.5.4:wget http://mirrors.tuna.tsinghua.edu.cn/apache//apr/apr-util-1.5.4.tar.gz
下载完成后的效果如图所示:
wKiom1lCs7aAGGEYAAEbG_ib1bU197.png-wh_50 

3.编译安装
3.1预备
考虑到在编译过程中需要一些依赖库支持,通过下面的命令来安装:
yum install zlib zlib-devel openssl openssl-devel –y
另外由于serf需要用scons来编译,而编译scons又需要python支持,因此需要安装python:
yum install python –y
3.2编译安装apr
cd /root
tar zxvf /root/apr-1.5.2.tar.gz
cd /root/apr-1.5.2/
./configure --prefix=/usr/local/apr
make && make install
说明:apr-util依赖于apr,因此优先于apr-util编译。参数中--prefix=/usr/local/apr表示编译后的安装目录为/usr/local/apr。
3.3编译安装apr-util
cd /root/
tar zxvf /root/apr-util-1.5.4.tar.gz
cd /root/apr-util-1.5.4/
./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr
make && make install
说明:参数中--prefix=/usr/local/apr-util表示编译后的安装目录为/usr/local/apr-util,同时通过--with-apr=/usr/local/apr参数指定了它的依赖项apr的目录为/usr/local/apr。
3.4编译安装scons
cd /root/
tar zxvf ./scons-2.5.1.tar.gz
cd /root/scons-2.5.1/
python setup.py install --prefix=/usr/local/scons
说明:serf必须使用scons来编译,因此优先于serf编译。参数中--prefix=/usr/local/apr表示编译后的安装目录为/usr/local/apr。
3.5编译安装serf
cd /root/
tar xf ./serf-1.3.9.tar.bz2
cd /root/serf-1.3.9
/usr/local/scons/bin/scons prefix=/usr/local/serf APR=/usr/local/apr APU=/usr/local/apr-util
/usr/local/scons/bin/scons install
说明:参数中- prefix=/usr/local/serf表示编译后的安装目录为/usr/local/serf。
3.6编译安装Apache(httpd)
cd /root
tar zxvf /root/httpd-2.4.25.tar.gz
cd /root/httpd-2.4.25
./configure --prefix=/usr/local/httpd-2.4.25  --enable-dav --enable-so  --enable-ssl --enable-cgi  --enable-rewrite  --with-zlib --with-pcre --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util --enable-modules=most --enable-mpms-shared=all --with-mpm=event --enable-proxy --enable-proxy-fcgi --enable-dav --enable-dav-fs --enable-maintainer-mode
make && make install
说明:因subverion编译时会将生成的mod_dav_svn.so及mod_authz_svn.so拷贝到/usr/local/httpd-2.4.25/modules目录,并且在/usr/local/httpd-2.4.25/conf/httpd.conf设置为自动加载。参数中--prefix=/usr/local/httpd-2.4.25表示编译后的安装目录为/usr/local/httpd-2.4.25。
3.7安装subverion
由于编译subversion需要sqlite支持,所以将下载的sqlite-amalgamation-3190300.zip解压后将文件夹重命名为sqlite-amalgamation并拷贝到/root/subversion-1.9.5/目录下。
cd /root
tar zxvf ./subversion-1.9.5.tar.gz
unzip /root/sqlite-amalgamation-3190300.zip
mv /root/sqlite-amalgamation-3190300 /root/subversion-1.9.5/sqlite-amalgamation
cd /root/subversion-1.9.5
./configure --prefix=/usr/local/svn --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util --with-serf=/usr/local --enable-mod-activation --with-apache-libexecdir=/usr/local/httpd-2.4.25/modules --with-apxs=/usr/local/httpd-2.4.25/bin/apxs  --without-berkeley-db
make && make install
支持已经完成了subversion和apache的编译和安装,这里都是通过—prefix参数将编译后的安装目录设置到了/usr/local目录下。
4.配置
4.1用户配置
在本实例中subversion的进程和Apache的进程将会以svn来运行,因此需要创建svn用户账号。
useradd svn -s /sbin/nologin –M
4.2环境变量配置
为便于每次运行命令时需要输入冗长的路径信息(或切换到其所在目录),在本处将本系列文章截止到目前的应用程序都添加环境变量中,类似Windows中设置path环境变量,在CentOS7中是在/etc/profile中配置,截止目前在文件末尾添加的内容:
export JAVA_HOME=/usr/local/jdk1.8.0_131
export JRE_HOME=/usr/local/jdk1.8.0_131
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin:/usr/local/apache-tomcat-8.5.15/bin:/usr/local/httpd-2.4.25/bin:/usr/local/svn/bin:/usr/local/php/bin
即将svn、tomcat、php、Java和Apache的可执行文件的路径都添加到PATH环境变量中,以后执行这些命令时可以直接执行了。
最后,通过source /etc/profile使我们的配置生效。
4.3SVN配置
由于将svn的可执行文件路径添加到/etc/profile中的PATH变量中了,因此可直接执行svn安装目录下的bin子目录中的文件;比如查看版本svn --version。但是第一次执行svn --version命令的时候会报错:
svn: error while loading shared libraries: libserf-1.so.1: cannot open shared object file: No such file or directory
解决办法就是在/etc/ld.so.conf.d/目录下手动创建serf-1.3.9.conf文件,文件内容是libserf-1.so.1文件所在的目录,在本虚拟机中libserf-1.so.1在/usr/local/lib下,因此serf-1.3.9.conf文件内容如下:
/usr/local/lib
将文件保存并退出后再通过如下命令查看加载情况:
/sbin/ldconfig –v
4.3.1创建svn版本库
mkdir -p /var/svn
cd /var/svn
svnadmin create phpproject
svnadmin create javaproject
svnadmin create dotnetproject
即创建/var/svn目录,此目录为svn的根目录,并在此目录下依次创建了phpproject、javaproject和dotnetproject三个版本库。
因为我们最终是要让subversion支持多个版本库,因此关于svn账号、授权的信息不能放在某个单独的库下,因此我们直接放在/var/svn这个svn的版本库根目录下,主要是三个文件:
authz:用于存放版本库的授权信息。
passwd:用于存放账号和密码。
svnserve.conf:用于svnserve形式启动的配置文件。
我们从phpproject版本库中拷贝出这三个文件,然后基于它们修改作为多版本库的控制文件:
cp /var/svn/phpproject/conf/authz  /var/svn/authz
cp /var/svn/phpproject/conf/passwd  /var/svn/passwd
cp /var/svn/phpproject/conf/svnserve.conf  /var/svn/svnserve.conf
4.3.2创建svn账号
为安全起见,将用户密码作处理后保存到文件中,这就需要使用Apache自带的htpasswd工具,它可以生成passwd文件,其中用户名为明文,用户密码为md5哈希值。
htpasswd -c /var/svn/passwd jerry #once only
htpasswd /var/svn/passwd harry
htpasswd /var/svn/passwd root
htpasswd /var/svn/passwd admin
htpasswd /var/svn/passwd haley
注意:htpasswd位于/usr/local/httpd-2.4.25/bin,即我们编译安装Apache时指定的目录,因为将/usr/local/httpd-2.4.25/bin添加到/etc/profile中了,所以可以直接htpasswd,如果指定的目录不存在passwd文件,就需要带上”-c”参数,表示创建文件,但是之后就不需要了。如果每次都带上,反而只有最后一次的执行结果。
最终生成的文件内容如下:
wKioL1lCs86iOIHWAACWYgof_P0413.png-wh_50 
4.3.3编辑svnserve.conf文件
可以通过vim /var/svn/svnserve.conf来编辑,最终文件内容如下:
[general]
anon-access = read
auth-access = write
password-db = passwd
authz-db = authz
[sasl]

4.3.4编辑配置SVN授权文件
执行命令vim /var/svn/authz来编辑,最终文件内容如下:
[aliases]
# joe = /C=XZ/ST=Dessert/L=Snake City/O=Snake Oil, Ltd./OU=Research Institute/CN=Joe Average

[groups]
# harry_and_sally = harry,sally
# harry_sally_and_joe = harry,sally,&joe
developers = jerry,haley
administrators = root,admin

[/]
@administrators=rw
haley = r
jerry = rw
* = r

[javaproject:/]
@administrators = r
@developers = rw

[phpproject:/]
root = rw
haley = rw
jerry = r

[dotnetproject:/]
@administrators = rw
jerry = rw
说明:在上面的文件中前面带”@”的是用户组,例如dotnetproject这个版本库administrators组有读写权限,而jerry这个用户也有读写权限,而其它用户则没有权限。

4.3.5强制开发每次提交代码必须填写注释
默认情况下每次提交代码时填写注释是可选的,但在多人团队中如果大家每次提交不填写注释则容易造成事后不知道提交代码是为了修复bug还是增加新功能了,因此有必要强制一下,这里就以要求每次提交时注释不得少于5个字符为例。
在我们通过svnadmin create版本库时,每个版本库下都有个hooks目录,里面有不少钩子的示例。将已创建的任一项目下的hooks子目录下的pre-commit.tmpl拷贝一份并命名为pre-commit,根据文件名望文生义就知道这个文件是在提交代码到svn版本库之前执行的钩子程序。
现在来编辑pre-commit:
vim /var/svn/pre-commit
文件的最终结果为如下:
REPOS="$1"
TXN="$2"

# Make sure that the log message contains some text.
SVNLOOK=/usr/local/svn/bin/svnlook
#$SVNLOOK log -t "$TXN" "$REPOS" | \
#   grep "[a-zA-Z0-9]" > /dev/null || exit 1
LOGMSG=`$SVNLOOK log -t "$TXN" "$REPOS" | grep "[\w\u4e00-\u9fa5]" | wc -c`
if [ "$LOGMSG" -lt 5 ];
then
  echo -e "Comment cann't be empty! you must input more than 5 chars as comment!" 1>&2
  exit 1
fi
set -e
# 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
然后给pre-commit添加可执行权限
chmod 755 /var/svn/pre-commit

然后将pre-commit文件拷贝到其它几个版本库的hooks目录:
cp /var/svn/pre-commit /var/svn/phpproject/hooks
cp /var/svn/pre-commit /var/svn/javaproject/hooks
cp /var/svn/pre-commit /var/svn/dotnetproject/hooks
注意:以后每次新建一个版本库,都要将这个pre-commit拷贝到它的hooks目录下。
到这里我们可以通过命令行来启动svn服务器了,命令如下:
svnserve --config-file /var/svn/svnserve.conf -d -r /var/svn
即以/var/svn/svnserve.conf作为配置文件,svn版本库的根目录为/var/svn,然后就可以在命令下以svn命令来操作版本库了。
4.4subverion与apache集成
直接使用svn协议来操作也是可以的,不过目前比较流行的还是subverion与apache集成,然后借助一个web的svn管理工具,这样svn管理起来就方便很多了。在这一节就将如何讲subverion与apache集成。
因为在当前服务器上已经安装nginx作为web server,并且使用了80端口,所以只好让apache使用8000端口了。这里提一下,网上到处是svn与apache集成的介绍,很少有svn与nginx集成的介绍。我找了一些英文资料,发现在nginx网站上也有人在2007年问过这个问题,而nginx的作者、俄罗斯的Igor Sysoev也回答过这个问题,网址是:http://mailman.nginx.org/pipermail/nginx/2007-January/000504.html,按照作者的说法是可能通过配置支持的,但我没试过,有感兴趣的可以试一下。
4.4.1httpd.conf的修改
在apache的配置文件httpd.conf需要修改的地方有:
修改监听端口,由80修改为8000;
更改apache运行时所使用的user和group,均由daemon修改为svn;
include一个关于svn配置的文件,文件名为httpd-svn.conf,位于/usr/local/httpd-2.4.25/conf/extra/。注:这个文件默认没有,是稍后将创建的。
同时,为便于按日跟踪apache日志,利用了/usr/local/httpd-2.4.25/bin/目录下的rotatelogs来切割日志文件,这样一来ErrorLog和CustomLog的配置就变为:
ErrorLog "|/usr/local/httpd-2.4.25/bin/rotatelogs /usr/local/httpd-2.4.25/logs/error_log.%Y%m%d 86400 480"
CustomLog "|/usr/local/httpd-2.4.25/bin/rotatelogs /usr/local/httpd-2.4.25/logs/access_log.%Y%m%d 86400 480" common
上述命令中86400表示以天为单位分割,86400是一天的总秒数,而480表示按照东八时区的时间来分割(与UTC相隔8小时,480分钟)。
同时,由于编译时参数的制定,启用了多个mpm模块,仅保留一个将其余的注释掉,否则启动时会报错。修改前后的对比如下图:
wKioL1lCs-uwxzTHAABqs1aJidk214.png-wh_50 
上图中有红色框的都是修改后的内容,而下方的就是修改前的内容。
4.4.2在Apache中增加svn的相关配
首先在/usr/local/httpd-2.4.25/conf/extra/目录创建前文提到的httpd-svn.conf文件:
vim /usr/local/httpd-2.4.25/conf/extra/httpd-svn.conf
文件内容如下:
<Location /svn>
  DAV svn
  #support more repositories
  SVNParentPath /var/svn

  #list all repositories
  #SVNListParentPath on
  AuthType Basic
  AuthName "Please input Username and Password"
  AuthUserFile /var/svn/passwd
  AuthzSVNAccessFile /var/svn/authz
  Require valid-user
</Location>
在这里使用的是多版本库的配置,使用了SVNParentPath设置,并且有关用户账号、授权信息都是指向svn版本库的根目录下的文件。
4.4.3权限设置
因为设置了Apache以svn/svn这个user/group来运行,因此需要让svn账号有读写/var/svn目录下的权限,可执行命令:
chown –R svn:svn /var/svn

5.检验配置
在https://tortoisesvn.net/downloads.html下载与操作系统对应的TortoiseSVN客户端,就可以checkin和checkout代码了。
如下图是checkout时的界面:
wKiom1lCtADijuFDAACJ3bBcjtE475.png-wh_50 
下图是提交时注释达不到设置要求时的错误界面:
wKioL1lCtBPgRUmQAADDibNf2YE230.png-wh_50 

下图是在浏览器中打开svn版本库的界面:
 wKioL1lCtCSCmUsJAACmm1EzC6M735.png-wh_50

6.总结
从业十几年来,本人使用过VSS/TFS/StarTeam/SVN/Git作为源代码版本控工具,目前来说价格比较低廉甚至免费而又实用方便的就是SVN和Git了。本篇就是讲述了如何编译安装subversion和httpd(即Apache),并使之集成的。


声明:本文首发于本人个人微信订阅号:zhoujinqiaoIT,其后会同时在本人的CSDN、51CTO及oschina三处博客发布,本人会负责在此四处答疑。