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);
    ...
}

编译Subversion

[ 编辑 | 历史 ]
最近由“jilili”在“2019-08-09 20:41:37”修改