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中指定的路径:例如[HTML_REMOVED]。
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); ... }