1# -*-python-*-
2#
3# Copyright (C) 1999-2020 The ViewCVS Group. All Rights Reserved.
4#
5# By using this file, you agree to the terms and conditions set forth in
6# the LICENSE.html file which can be found at the top level of the ViewVC
7# distribution or at http://viewvc.org/license-1.html.
8#
9# For more information, visit http://viewvc.org/
10#
11# -----------------------------------------------------------------------
12
13"Version Control lib driver for Subversion repositories"
14
15import os
16import os.path
17import re
18import urllib.parse
19
20_re_url = re.compile('^(http|https|file|svn|svn\+[^:]+)://')
21
22def _canonicalize_path(path):
23  import svn.core
24  return svn.core.svn_path_canonicalize(path).decode('utf-8', 'surrogateescpe')
25
26def canonicalize_rootpath(rootpath):
27  # Try to canonicalize the rootpath using Subversion semantics.
28  rootpath = _canonicalize_path(rootpath)
29
30  # ViewVC's support for local repositories is more complete and more
31  # performant than its support for remote ones, so if we're on a
32  # Unix-y system and we have a file:/// URL, convert it to a local
33  # path instead.
34  if os.name == 'posix':
35    rootpath_lower = rootpath.lower()
36    if rootpath_lower in ['file://localhost',
37                          'file://localhost/',
38                          'file://',
39                          'file:///'
40                          ]:
41      return '/'
42    if rootpath_lower.startswith('file://localhost/'):
43      rootpath = os.path.normpath(urllib.parse.unquote(rootpath[16:]))
44    elif rootpath_lower.startswith('file:///'):
45      rootpath = os.path.normpath(urllib.parse.unquote(rootpath[7:]))
46
47  # Ensure that we have an absolute path (or URL), and return.
48  if not re.search(_re_url, rootpath):
49    assert os.path.isabs(rootpath)
50  return rootpath
51
52
53def expand_root_parent(parent_path):
54  roots = {}
55  if re.search(_re_url, parent_path):
56    pass
57  else:
58    # Any subdirectories of PARENT_PATH which themselves have a child
59    # "format" are returned as roots.
60    assert os.path.isabs(parent_path)
61    subpaths = os.listdir(parent_path)
62    for rootname in subpaths:
63      rootpath = os.path.join(parent_path, rootname)
64      if os.path.exists(os.path.join(rootpath, "format")):
65        roots[rootname] = canonicalize_rootpath(rootpath)
66  return roots
67
68
69def find_root_in_parent(parent_path, rootname):
70  """Search PARENT_PATH for a root named ROOTNAME, returning the
71  canonicalized ROOTPATH of the root if found; return None if no such
72  root is found."""
73
74  if not re.search(_re_url, parent_path):
75    assert os.path.isabs(parent_path)
76    rootpath = os.path.join(parent_path, rootname)
77    format_path = os.path.join(rootpath, "format")
78    if os.path.exists(format_path):
79      return canonicalize_rootpath(rootpath)
80  return None
81
82
83def SubversionRepository(name, rootpath, authorizer, utilities, config_dir,
84                         encoding='utf-8'):
85  rootpath = canonicalize_rootpath(rootpath)
86  if re.search(_re_url, rootpath):
87    from . import svn_ra
88    return svn_ra.RemoteSubversionRepository(name, rootpath, authorizer,
89                                             utilities, config_dir, encoding)
90  else:
91    from . import svn_repos
92    return svn_repos.LocalSubversionRepository(name, rootpath, authorizer,
93                                               utilities, config_dir, encoding)
94