Subversion是一个优秀的代码仓库,可是要想支持类似Github那样的用户空间内的仓库,即:想根据不同用户,使用不同的存储路径来访问,路径为:http://code.ideais.net/svn/jilili/lmiot,其中jilili为用户标识。使用Apache和mod_dav_svn默认是无法完成的,需要修改源代码。
在Subversion 1.6和1.7都测试过了。
修改思路
动态产生root_path和fs_parent_path,这样其它逻辑都不用修改。
Apache中Location配置为:/svn,Parent仓库路径为:/opt/repo/svn,不直接配置仓库路径
在程序中将Location修改为:/svn/jilili,Parent仓库为:/opt/repo/svn/jilili就大功告成了。
修改方法
root_path:在repos.c中的get_resource(…)函数中产生,是httpd.conf文件Location中指定的路径:例如
fs_parent_path:是由函数dav_svn_get_fs_parent_path(…)从httpd.conf中取出的配置。
需要修改get_resource和dav_svn_get_fs_parent_path函数。
subversion/mod_dav_svn/mod_dav_svn.c
-- line 388(1.6.x) 替换整个函数
const char *
dav_svn__get_fs_parent_path(request_rec *r)
{
dir_conf_t *conf;
const char* uri;
const char* fs_parent_path;
const char* magic_start;
const char* magic_end;
conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
fs_parent_path = conf->fs_parent_path;
/* storage space */
magic_start = ap_strchr_c(r->uri + 1, '/');
if(magic_start) {
magic_end = ap_strchr_c(magic_start + 1, '/');
if(magic_end) fs_parent_path = apr_pstrcat(r->pool, fs_parent_path, "/", apr_pstrndup(r->pool, magic_start + 1, magic_end - magic_start - 1), NULL);
}
/*
magic_start = r->uri;
magic_end = ap_strchr_c(r->uri + 1, '/');
if(magic_end) fs_parent_path = apr_pstrcat(r->pool, fs_parent_path, "/", apr_pstrndup(r->pool, magic_start + 1, magic_end - magic_start - 1), NULL);
*/
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"dav_svn__get_fs_parent_path is %s", fs_parent_path);
return fs_parent_path;
}
subversion/mod_dav_svn/repos.c
url: /svn/jilili/www.ideais.net/trunk
-- line 913 (1.6.x)
调试信息
dav_svn_split_uri(...)
-- 935
root_path = /svn/jilili
fs_path =
fs_parent_path = /opt/repo/svn
-- 950
uri = /svn/jilili/www.ideais.net/trunk
-- 965
*cleaned_uri = /svn/jilili/www.ideais.net/trunk
-- 981
relative = /www.ideais.net/trunk
-- 1051
relative = /trunk
*relative_path = /trunk
*repos_name = www.ideais.net
-- 1164
/* Debug */
return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
SVN_ERR_APMOD_MISSING_PATH_TO_FS,
r->uri);
-- line: 1636 (1.6.x)
修改代码:在方法开始变量声明之后。
get_resource(...)
void *userdata
...
/* Change root_path */
int cnt_pth;
int cnt_ch;
char *uri_cr = apr_pstrdup(r->pool, r->uri);
apr_size_t root_path_len;
cnt_pth = 0;
cnt_ch = 0;
while(*uri_cr != '\0' && cnt_pth < 3)
{
if(*uri_cr == '/') cnt_pth ++;
uri_cr++;
cnt_ch ++;
}
root_path_len = cnt_pth==3?cnt_ch-1:cnt_ch;
root_path = apr_pstrndup(r->pool, r->uri, root_path_len);
/* Debug */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"get_resource, root_path is %s", root_path);
...
repo_name = dav_svn__get_repo_name(r);
subversion/mod_dav_svn/mod_dav_svn.c
如果开启了AuthzSVNReposRelativeAccessFile authz还需要修改如下文件。
AP_MODULE_DECLARE(dav_error *)
dav_svn_get_repos_path(request_rec *r,
const char *root_path,
const char **repos_path)
{
...
/* Change root_path */
int cnt_pth;
int cnt_ch;
char *uri_cr = apr_pstrdup(r->pool, r->uri);
apr_size_t root_path_len;
cnt_pth = 0;
cnt_ch = 0;
while(*uri_cr != '\0' && cnt_pth < 2)
{
if(*uri_cr == '/') cnt_pth ++;
uri_cr++;
cnt_ch ++;
}
root_path_len = cnt_pth==2?cnt_ch-1:cnt_ch;
root_path = apr_pstrndup(r->pool, r->uri, root_path_len);
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"dav_svn_get_repos_path, root_path is %s", root_path);
...
}
