##// END OF EJS Templates
vcs-lib: bulk of changes for python3 support
super-admin -
r5074:09a42e1d default
parent child Browse files
Show More
@@ -140,8 +140,8 b' class CurlSession(object):'
140 140 curl.perform()
141 141
142 142 status_code = curl.getinfo(pycurl.HTTP_CODE)
143
144 return CurlResponse(response_buffer, status_code)
143 content_type = curl.getinfo(pycurl.CONTENT_TYPE)
144 return CurlResponse(response_buffer, status_code, content_type)
145 145
146 146
147 147 class CurlResponse(object):
@@ -153,9 +153,13 b' class CurlResponse(object):'
153 153 `requests` as a drop in replacement for benchmarking purposes.
154 154 """
155 155
156 def __init__(self, response_buffer, status_code):
156 def __init__(self, response_buffer, status_code, content_type=''):
157 157 self._response_buffer = response_buffer
158 158 self._status_code = status_code
159 self._content_type = content_type
160
161 def __repr__(self):
162 return f'CurlResponse(code={self._status_code}, content_type={self._content_type})'
159 163
160 164 @property
161 165 def content(self):
@@ -168,6 +172,10 b' class CurlResponse(object):'
168 172 def status_code(self):
169 173 return self._status_code
170 174
175 @property
176 def content_type(self):
177 return self._content_type
178
171 179 def iter_content(self, chunk_size):
172 180 self._response_buffer.seek(0)
173 181 while 1:
@@ -25,7 +25,7 b' VCS Backends module'
25 25 import os
26 26 import logging
27 27
28 from pprint import pformat
28 from rhodecode import typing
29 29
30 30 from rhodecode.lib.vcs.conf import settings
31 31 from rhodecode.lib.vcs.exceptions import VCSError
@@ -36,7 +36,7 b' from rhodecode.lib.vcs.utils.imports imp'
36 36 log = logging.getLogger(__name__)
37 37
38 38
39 def get_vcs_instance(repo_path, *args, **kwargs):
39 def get_vcs_instance(repo_path, *args, **kwargs) -> typing.VCSRepo | None:
40 40 """
41 41 Given a path to a repository an instance of the corresponding vcs backend
42 42 repository class is created and returned. If no repository can be found
@@ -54,10 +54,10 b' def get_vcs_instance(repo_path, *args, *'
54 54 backend = get_backend(vcs_alias)
55 55
56 56 if explicit_vcs_alias:
57 # do final verification of existance of the path, this does the
57 # do final verification of existence of the path, this does the
58 58 # same as get_scm() call which we skip in explicit_vcs_alias
59 59 if not os.path.isdir(repo_path):
60 raise VCSError("Given path %s is not a directory" % repo_path)
60 raise VCSError(f"Given path {repo_path} is not a directory")
61 61 except VCSError:
62 62 log.exception(
63 63 'Perhaps this repository is in db and not in '
@@ -68,15 +68,15 b' def get_vcs_instance(repo_path, *args, *'
68 68 return backend(repo_path=repo_path, *args, **kwargs)
69 69
70 70
71 def get_backend(alias):
71 def get_backend(alias) -> typing.VCSRepoClass:
72 72 """
73 73 Returns ``Repository`` class identified by the given alias or raises
74 74 VCSError if alias is not recognized or backend class cannot be imported.
75 75 """
76 76 if alias not in settings.BACKENDS:
77 77 raise VCSError(
78 "Given alias '%s' is not recognized! Allowed aliases:\n%s" %
79 (alias, pformat(settings.BACKENDS.keys())))
78 f"Given alias '{alias}' is not recognized! "
79 f"Allowed aliases:{settings.BACKENDS.keys()}")
80 80 backend_path = settings.BACKENDS[alias]
81 81 klass = import_class(backend_path)
82 82 return klass
@@ -29,7 +29,7 b' import datetime'
29 29 import fnmatch
30 30 import itertools
31 31 import logging
32 import collections
32 import dataclasses
33 33 import warnings
34 34
35 35 from zope.cachedescriptors.property import Lazy as LazyProperty
@@ -55,10 +55,17 b' FILEMODE_DEFAULT = 0o100644'
55 55 FILEMODE_EXECUTABLE = 0o100755
56 56 EMPTY_COMMIT_ID = '0' * 40
57 57
58 _Reference = collections.namedtuple('Reference', ('type', 'name', 'commit_id'))
59 58
59 @dataclasses.dataclass
60 class Reference:
61 type: str
62 name: str
63 commit_id: str
60 64
61 class Reference(_Reference):
65 def __iter__(self):
66 yield self.type
67 yield self.name
68 yield self.commit_id
62 69
63 70 @property
64 71 def branch(self):
@@ -74,8 +81,15 b' class Reference(_Reference):'
74 81 def to_str(self):
75 82 return reference_to_unicode(self)
76 83
84 def asdict(self):
85 return dict(
86 type=self.type,
87 name=self.name,
88 commit_id=self.commit_id
89 )
77 90
78 def unicode_to_reference(raw):
91
92 def unicode_to_reference(raw: str):
79 93 """
80 94 Convert a unicode (or string) to a reference object.
81 95 If unicode evaluates to False it returns None.
@@ -220,8 +234,8 b' class MergeResponse(object):'
220 234
221 235 # Deprecations
222 236 MergeFailureReason._DEPRECATED_MISSING_COMMIT: lazy_ugettext(
223 u'This pull request cannot be merged because the target or the '
224 u'source reference is missing.'),
237 'This pull request cannot be merged because the target or the '
238 'source reference is missing.'),
225 239
226 240 }
227 241
@@ -972,6 +986,9 b' class BaseCommit(object):'
972 986 d.pop('repository', None)
973 987 return d
974 988
989 def get_remote(self):
990 return self._remote
991
975 992 def serialize(self):
976 993 return self.__json__()
977 994
@@ -1097,7 +1114,7 b' class BaseCommit(object):'
1097 1114
1098 1115 return author_email(self.author)
1099 1116
1100 def get_file_mode(self, path):
1117 def get_file_mode(self, path: bytes):
1101 1118 """
1102 1119 Returns stat mode of the file at `path`.
1103 1120 """
@@ -1115,7 +1132,13 b' class BaseCommit(object):'
1115 1132 """
1116 1133 raise NotImplementedError
1117 1134
1118 def get_file_content(self, path):
1135 def node_md5_hash(self, path):
1136 """
1137 Returns md5 hash of a node data
1138 """
1139 raise NotImplementedError
1140
1141 def get_file_content(self, path) -> bytes:
1119 1142 """
1120 1143 Returns content of the file at the given `path`.
1121 1144 """
@@ -1168,7 +1191,7 b' class BaseCommit(object):'
1168 1191 """
1169 1192 raise NotImplementedError
1170 1193
1171 def get_nodes(self, path):
1194 def get_nodes(self, path, pre_load=None):
1172 1195 """
1173 1196 Returns combined ``DirNode`` and ``FileNode`` objects list representing
1174 1197 state of commit at the given ``path``.
@@ -1194,13 +1217,13 b' class BaseCommit(object):'
1194 1217 """
1195 1218 return None
1196 1219
1197 def archive_repo(self, archive_dest_path, kind='tgz', subrepos=None,
1220 def archive_repo(self, archive_name_key, kind='tgz', subrepos=None,
1198 1221 archive_dir_name=None, write_metadata=False, mtime=None,
1199 archive_at_path='/'):
1222 archive_at_path='/', cache_config=None):
1200 1223 """
1201 1224 Creates an archive containing the contents of the repository.
1202 1225
1203 :param archive_dest_path: path to the file which to create the archive.
1226 :param archive_name_key: unique key under this archive should be generated
1204 1227 :param kind: one of following: ``"tbz2"``, ``"tgz"``, ``"zip"``.
1205 1228 :param archive_dir_name: name of root directory in archive.
1206 1229 Default is repository name and commit's short_id joined with dash:
@@ -1209,9 +1232,11 b' class BaseCommit(object):'
1209 1232 :param mtime: custom modification time for archive creation, defaults
1210 1233 to time.time() if not given.
1211 1234 :param archive_at_path: pack files at this path (default '/')
1235 :param cache_config: config spec to send to vcsserver to configure the backend to store files
1212 1236
1213 1237 :raise VCSError: If prefix has a problem.
1214 1238 """
1239 cache_config = cache_config or {}
1215 1240 allowed_kinds = [x[0] for x in settings.ARCHIVE_SPECS]
1216 1241 if kind not in allowed_kinds:
1217 1242 raise ImproperArchiveTypeError(
@@ -1223,8 +1248,8 b' class BaseCommit(object):'
1223 1248 commit_id = self.raw_id
1224 1249
1225 1250 return self.repository._remote.archive_repo(
1226 archive_dest_path, kind, mtime, archive_at_path,
1227 archive_dir_name, commit_id)
1251 archive_name_key, kind, mtime, archive_at_path,
1252 archive_dir_name, commit_id, cache_config)
1228 1253
1229 1254 def _validate_archive_prefix(self, archive_dir_name):
1230 1255 if archive_dir_name is None:
@@ -1232,11 +1257,13 b' class BaseCommit(object):'
1232 1257 repo_name=safe_str(self.repository.name),
1233 1258 short_id=self.short_id)
1234 1259 elif not isinstance(archive_dir_name, str):
1235 raise ValueError("prefix not a bytes object: %s" % repr(archive_dir_name))
1260 raise ValueError(f"archive_dir_name is not str object but: {type(archive_dir_name)}")
1236 1261 elif archive_dir_name.startswith('/'):
1237 1262 raise VCSError("Prefix cannot start with leading slash")
1238 1263 elif archive_dir_name.strip() == '':
1239 1264 raise VCSError("Prefix cannot be empty")
1265 elif not archive_dir_name.isascii():
1266 raise VCSError("Prefix cannot contain non ascii characters")
1240 1267 return archive_dir_name
1241 1268
1242 1269 @LazyProperty
@@ -1321,14 +1348,28 b' class BaseCommit(object):'
1321 1348 """
1322 1349 Similar to os.walk method. Insted of filesystem it walks through
1323 1350 commit starting at given ``topurl``. Returns generator of tuples
1324 (topnode, dirnodes, filenodes).
1351 (top_node, dirnodes, filenodes).
1325 1352 """
1326 topnode = self.get_node(topurl)
1327 if not topnode.is_dir():
1353 from rhodecode.lib.vcs.nodes import DirNode
1354
1355 if isinstance(topurl, DirNode):
1356 top_node = topurl
1357 else:
1358 top_node = self.get_node(topurl)
1359
1360 has_default_pre_load = False
1361 if isinstance(top_node, DirNode):
1362 # used to inject as we walk same defaults as given top_node
1363 default_pre_load = top_node.default_pre_load
1364 has_default_pre_load = True
1365
1366 if not top_node.is_dir():
1328 1367 return
1329 yield (topnode, topnode.dirs, topnode.files)
1330 for dirnode in topnode.dirs:
1331 for tup in self.walk(dirnode.path):
1368 yield top_node, top_node.dirs, top_node.files
1369 for dir_node in top_node.dirs:
1370 if has_default_pre_load:
1371 dir_node.default_pre_load = default_pre_load
1372 for tup in self.walk(dir_node):
1332 1373 yield tup
1333 1374
1334 1375 def get_filenodes_generator(self):
@@ -1345,15 +1386,15 b' class BaseCommit(object):'
1345 1386
1346 1387 def no_node_at_path(self, path):
1347 1388 return NodeDoesNotExistError(
1348 u"There is no file nor directory at the given path: "
1349 u"`%s` at commit %s" % (safe_unicode(path), self.short_id))
1389 f"There is no file nor directory at the given path: "
1390 f"`{safe_str(path)}` at commit {self.short_id}")
1350 1391
1351 def _fix_path(self, path):
1392 def _fix_path(self, path: str) -> str:
1352 1393 """
1353 1394 Paths are stored without trailing slash so we need to get rid off it if
1354 1395 needed.
1355 1396 """
1356 return path.rstrip('/')
1397 return safe_str(path).rstrip('/')
1357 1398
1358 1399 #
1359 1400 # Deprecated API based on changesets
@@ -1380,9 +1421,7 b' class BaseChangesetClass(type):'
1380 1421 return isinstance(instance, BaseCommit)
1381 1422
1382 1423
1383 class BaseChangeset(BaseCommit):
1384
1385 __metaclass__ = BaseChangesetClass
1424 class BaseChangeset(BaseCommit, metaclass=BaseChangesetClass):
1386 1425
1387 1426 def __new__(cls, *args, **kwargs):
1388 1427 warnings.warn(
@@ -1624,9 +1663,7 b' class BaseInMemoryChangesetClass(type):'
1624 1663 return isinstance(instance, BaseInMemoryCommit)
1625 1664
1626 1665
1627 class BaseInMemoryChangeset(BaseInMemoryCommit):
1628
1629 __metaclass__ = BaseInMemoryChangesetClass
1666 class BaseInMemoryChangeset(BaseInMemoryCommit, metaclass=BaseInMemoryChangesetClass):
1630 1667
1631 1668 def __new__(cls, *args, **kwargs):
1632 1669 warnings.warn(
@@ -1676,14 +1713,14 b' class EmptyCommit(BaseCommit):'
1676 1713 def id(self):
1677 1714 return self.raw_id
1678 1715
1679 def get_path_commit(self, path):
1716 def get_path_commit(self, path, pre_load=None):
1680 1717 return self
1681 1718
1682 def get_file_content(self, path):
1683 return u''
1719 def get_file_content(self, path) -> bytes:
1720 return b''
1684 1721
1685 1722 def get_file_content_streamed(self, path):
1686 yield self.get_file_content()
1723 yield self.get_file_content(path)
1687 1724
1688 1725 def get_file_size(self, path):
1689 1726 return 0
@@ -1695,9 +1732,7 b' class EmptyChangesetClass(type):'
1695 1732 return isinstance(instance, EmptyCommit)
1696 1733
1697 1734
1698 class EmptyChangeset(EmptyCommit):
1699
1700 __metaclass__ = EmptyChangesetClass
1735 class EmptyChangeset(EmptyCommit, metaclass=EmptyChangesetClass):
1701 1736
1702 1737 def __new__(cls, *args, **kwargs):
1703 1738 warnings.warn(
@@ -1731,7 +1766,7 b' class EmptyRepository(BaseRepository):'
1731 1766
1732 1767 def get_diff(self, *args, **kwargs):
1733 1768 from rhodecode.lib.vcs.backends.git.diff import GitDiff
1734 return GitDiff('')
1769 return GitDiff(b'')
1735 1770
1736 1771
1737 1772 class CollectionGenerator(object):
@@ -1739,8 +1774,7 b' class CollectionGenerator(object):'
1739 1774 def __init__(self, repo, commit_ids, collection_size=None, pre_load=None, translate_tag=None):
1740 1775 self.repo = repo
1741 1776 self.commit_ids = commit_ids
1742 # TODO: (oliver) this isn't currently hooked up
1743 self.collection_size = None
1777 self.collection_size = collection_size
1744 1778 self.pre_load = pre_load
1745 1779 self.translate_tag = translate_tag
1746 1780
@@ -1762,11 +1796,16 b' class CollectionGenerator(object):'
1762 1796 commit_id=commit_id, pre_load=self.pre_load,
1763 1797 translate_tag=self.translate_tag)
1764 1798
1765 def __getslice__(self, i, j):
1766 """
1767 Returns an iterator of sliced repository
1768 """
1769 commit_ids = self.commit_ids[i:j]
1799 def __getitem__(self, key):
1800 """Return either a single element by index, or a sliced collection."""
1801
1802 if isinstance(key, slice):
1803 commit_ids = self.commit_ids[key.start:key.stop]
1804
1805 else:
1806 # single item
1807 commit_ids = self.commit_ids[key]
1808
1770 1809 return self.__class__(
1771 1810 self.repo, commit_ids, pre_load=self.pre_load,
1772 1811 translate_tag=self.translate_tag)
@@ -1830,10 +1869,16 b' class Diff(object):'
1830 1869 :attr:`_header_re` and :attr:`_meta_re`.
1831 1870 """
1832 1871 _meta_re = None
1833 _header_re = None
1872 _header_re: bytes = re.compile(br"")
1834 1873
1835 def __init__(self, raw_diff):
1836 self.raw = raw_diff
1874 def __init__(self, raw_diff: bytes):
1875 if not isinstance(raw_diff, bytes):
1876 raise Exception(f'raw_diff must be bytes - got {type(raw_diff)}')
1877
1878 self.raw = memoryview(raw_diff)
1879
1880 def get_header_re(self):
1881 return self._header_re
1837 1882
1838 1883 def chunks(self):
1839 1884 """
@@ -1842,35 +1887,44 b' class Diff(object):'
1842 1887 we can detect last chunk as this was also has special rule
1843 1888 """
1844 1889
1845 diff_parts = ('\n' + self.raw).split('\ndiff --git')
1846 header = diff_parts[0]
1847
1848 if self._meta_re:
1849 match = self._meta_re.match(header)
1890 diff_parts = (b'\n' + bytes(self.raw)).split(b'\ndiff --git')
1850 1891
1851 1892 chunks = diff_parts[1:]
1852 1893 total_chunks = len(chunks)
1853 1894
1854 return (
1855 DiffChunk(chunk, self, cur_chunk == total_chunks)
1856 for cur_chunk, chunk in enumerate(chunks, start=1))
1895 def diff_iter(_chunks):
1896 for cur_chunk, chunk in enumerate(_chunks, start=1):
1897 yield DiffChunk(chunk, self, cur_chunk == total_chunks)
1898 return diff_iter(chunks)
1857 1899
1858 1900
1859 1901 class DiffChunk(object):
1860 1902
1861 def __init__(self, chunk, diff, last_chunk):
1862 self._diff = diff
1903 def __init__(self, chunk: bytes, diff_obj: Diff, is_last_chunk: bool):
1904 self.diff_obj = diff_obj
1863 1905
1864 1906 # since we split by \ndiff --git that part is lost from original diff
1865 1907 # we need to re-apply it at the end, EXCEPT ! if it's last chunk
1866 if not last_chunk:
1867 chunk += '\n'
1868
1869 match = self._diff._header_re.match(chunk)
1908 if not is_last_chunk:
1909 chunk += b'\n'
1910 header_re = self.diff_obj.get_header_re()
1911 match = header_re.match(chunk)
1870 1912 self.header = match.groupdict()
1871 1913 self.diff = chunk[match.end():]
1872 1914 self.raw = chunk
1873 1915
1916 @property
1917 def header_as_str(self):
1918 if self.header:
1919 def safe_str_on_bytes(val):
1920 if isinstance(val, bytes):
1921 return safe_str(val)
1922 return val
1923 return {safe_str(k): safe_str_on_bytes(v) for k, v in self.header.items()}
1924
1925 def __repr__(self):
1926 return f'DiffChunk({self.header_as_str})'
1927
1874 1928
1875 1929 class BasePathPermissionChecker(object):
1876 1930
@@ -1885,10 +1939,10 b' class BasePathPermissionChecker(object):'
1885 1939
1886 1940 @property
1887 1941 def has_full_access(self):
1888 raise NotImplemented()
1942 raise NotImplementedError()
1889 1943
1890 1944 def has_access(self, path):
1891 raise NotImplemented()
1945 raise NotImplementedError()
1892 1946
1893 1947
1894 1948 class AllPathPermissionChecker(BasePathPermissionChecker):
@@ -22,8 +22,6 b''
22 22 GIT commit module
23 23 """
24 24
25 import re
26 import io
27 25 import stat
28 26 import configparser
29 27 from itertools import chain
@@ -31,9 +29,7 b' from itertools import chain'
31 29 from zope.cachedescriptors.property import Lazy as LazyProperty
32 30
33 31 from rhodecode.lib.datelib import utcdate_fromtimestamp
34 from rhodecode.lib.utils import safe_unicode, safe_str
35 from rhodecode.lib.utils2 import safe_int
36 from rhodecode.lib.vcs.conf import settings
32 from rhodecode.lib.str_utils import safe_bytes, safe_str
37 33 from rhodecode.lib.vcs.backends import base
38 34 from rhodecode.lib.vcs.exceptions import CommitError, NodeDoesNotExistError
39 35 from rhodecode.lib.vcs.nodes import (
@@ -92,7 +88,7 b' class GitCommit(base.BaseCommit):'
92 88 for attr, value in result.items():
93 89 if attr in ["author", "message"]:
94 90 if value:
95 value = safe_unicode(value)
91 value = safe_str(value)
96 92 elif attr == "date":
97 93 value = utcdate_fromtimestamp(*value)
98 94 elif attr == "parents":
@@ -119,15 +115,15 b' class GitCommit(base.BaseCommit):'
119 115
120 116 @LazyProperty
121 117 def message(self):
122 return safe_unicode(self._remote.message(self.id))
118 return safe_str(self._remote.message(self.id))
123 119
124 120 @LazyProperty
125 121 def committer(self):
126 return safe_unicode(self._remote.author(self.id))
122 return safe_str(self._remote.author(self.id))
127 123
128 124 @LazyProperty
129 125 def author(self):
130 return safe_unicode(self._remote.author(self.id))
126 return safe_str(self._remote.author(self.id))
131 127
132 128 @LazyProperty
133 129 def date(self):
@@ -143,7 +139,7 b' class GitCommit(base.BaseCommit):'
143 139
144 140 @LazyProperty
145 141 def tags(self):
146 tags = [safe_unicode(name) for name,
142 tags = [safe_str(name) for name,
147 143 commit_id in self.repository.tags.items()
148 144 if commit_id == self.raw_id]
149 145 return tags
@@ -159,7 +155,7 b' class GitCommit(base.BaseCommit):'
159 155 def _set_branch(self, branches):
160 156 if branches:
161 157 # actually commit can have multiple branches in git
162 return safe_unicode(branches[0])
158 return safe_str(branches[0])
163 159
164 160 @LazyProperty
165 161 def branch(self):
@@ -167,6 +163,7 b' class GitCommit(base.BaseCommit):'
167 163 return self._set_branch(branches)
168 164
169 165 def _get_tree_id_for_path(self, path):
166
170 167 path = safe_str(path)
171 168 if path in self._paths:
172 169 return self._paths[path]
@@ -202,11 +199,10 b' class GitCommit(base.BaseCommit):'
202 199 return NodeKind.SUBMODULE
203 200 return None
204 201
205 def _get_filectx(self, path):
202 def _assert_is_path(self, path):
206 203 path = self._fix_path(path)
207 204 if self._get_kind(path) != NodeKind.FILE:
208 raise CommitError(
209 "File does not exist for commit %s at '%s'" % (self.raw_id, path))
205 raise CommitError(f"File does not exist for commit {self.raw_id} at '{path}'")
210 206 return path
211 207
212 208 def _get_file_nodes(self):
@@ -231,17 +227,19 b' class GitCommit(base.BaseCommit):'
231 227
232 228 def _make_commits(self, commit_ids):
233 229 def commit_maker(_commit_id):
234 return self.repository.get_commit(commit_id=commit_id)
230 return self.repository.get_commit(commit_id=_commit_id)
235 231
236 232 return [commit_maker(commit_id) for commit_id in commit_ids]
237 233
238 def get_file_mode(self, path):
234 def get_file_mode(self, path: bytes):
239 235 """
240 236 Returns stat mode of the file at the given `path`.
241 237 """
242 path = safe_str(path)
238 path = self._assert_is_path(path)
239
243 240 # ensure path is traversed
244 241 self._get_tree_id_for_path(path)
242
245 243 return self._stat_modes[path]
246 244
247 245 def is_link(self, path):
@@ -251,6 +249,10 b' class GitCommit(base.BaseCommit):'
251 249 tree_id, _ = self._get_tree_id_for_path(path)
252 250 return self._remote.is_binary(tree_id)
253 251
252 def node_md5_hash(self, path):
253 path = self._assert_is_path(path)
254 return self._remote.md5_hash(self.raw_id, path)
255
254 256 def get_file_content(self, path):
255 257 """
256 258 Returns content of the file at given `path`.
@@ -276,7 +278,7 b' class GitCommit(base.BaseCommit):'
276 278 which file at given `path` has been modified.
277 279 """
278 280
279 path = self._get_filectx(path)
281 path = self._assert_is_path(path)
280 282 hist = self._remote.node_history(self.raw_id, path, limit)
281 283 return [
282 284 self.repository.get_commit(commit_id=commit_id, pre_load=pre_load)
@@ -296,11 +298,11 b' class GitCommit(base.BaseCommit):'
296 298 lambda: self.repository.get_commit(commit_id=commit_id, pre_load=pre_load),
297 299 content)
298 300
299 def get_nodes(self, path):
301 def get_nodes(self, path, pre_load=None):
300 302
301 303 if self._get_kind(path) != NodeKind.DIR:
302 304 raise CommitError(
303 "Directory does not exist for commit %s at '%s'" % (self.raw_id, path))
305 f"Directory does not exist for commit {self.raw_id} at '{path}'")
304 306 path = self._fix_path(path)
305 307
306 308 tree_id, _ = self._get_tree_id_for_path(path)
@@ -325,12 +327,11 b' class GitCommit(base.BaseCommit):'
325 327 self._stat_modes[obj_path] = stat_
326 328
327 329 if type_ == 'tree':
328 dirnodes.append(DirNode(obj_path, commit=self))
330 dirnodes.append(DirNode(safe_bytes(obj_path), commit=self))
329 331 elif type_ == 'blob':
330 filenodes.append(FileNode(obj_path, commit=self, mode=stat_))
332 filenodes.append(FileNode(safe_bytes(obj_path), commit=self, mode=stat_, pre_load=pre_load))
331 333 else:
332 raise CommitError(
333 "Requested object should be Tree or Blob, is %s", type_)
334 raise CommitError(f"Requested object should be Tree or Blob, is {type_}")
334 335
335 336 nodes = dirnodes + filenodes
336 337 for node in nodes:
@@ -346,8 +347,8 b' class GitCommit(base.BaseCommit):'
346 347 tree_id, type_ = self._get_tree_id_for_path(path)
347 348 except CommitError:
348 349 raise NodeDoesNotExistError(
349 "Cannot find one of parents' directories for a given "
350 "path: %s" % path)
350 f"Cannot find one of parents' directories for a given "
351 f"path: {path}")
351 352
352 353 if type_ in ['link', 'commit']:
353 354 url = self._get_submodule_url(path)
@@ -357,9 +358,9 b' class GitCommit(base.BaseCommit):'
357 358 if path == '':
358 359 node = RootNode(commit=self)
359 360 else:
360 node = DirNode(path, commit=self)
361 node = DirNode(safe_bytes(path), commit=self)
361 362 elif type_ == 'blob':
362 node = FileNode(path, commit=self, pre_load=pre_load)
363 node = FileNode(safe_bytes(path), commit=self, pre_load=pre_load)
363 364 self._stat_modes[path] = node.mode
364 365 else:
365 366 raise self.no_node_at_path(path)
@@ -378,7 +379,7 b' class GitCommit(base.BaseCommit):'
378 379 file_id = pointer_spec.get('oid_hash')
379 380 if self._remote.in_largefiles_store(file_id):
380 381 lf_path = self._remote.store_path(file_id)
381 return LargeFileNode(lf_path, commit=self, org_path=path)
382 return LargeFileNode(safe_bytes(lf_path), commit=self, org_path=path)
382 383
383 384 @LazyProperty
384 385 def affected_files(self):
@@ -393,7 +394,6 b' class GitCommit(base.BaseCommit):'
393 394 added = set()
394 395 modified = set()
395 396 deleted = set()
396 _r = self._remote
397 397
398 398 parents = self.parents
399 399 if not self.parents:
@@ -403,14 +403,11 b' class GitCommit(base.BaseCommit):'
403 403 oid = None
404 404 else:
405 405 oid = parent.raw_id
406 changes = _r.tree_changes(oid, self.raw_id)
407 for (oldpath, newpath), (_, _), (_, _) in changes:
408 if newpath and oldpath:
409 modified.add(newpath)
410 elif newpath and not oldpath:
411 added.add(newpath)
412 elif not newpath and oldpath:
413 deleted.add(oldpath)
406 _added, _modified, _deleted = self._remote.tree_changes(oid, self.raw_id)
407 added = added | set(_added)
408 modified = modified | set(_modified)
409 deleted = deleted | set(_deleted)
410
414 411 return added, modified, deleted
415 412
416 413 def _get_paths_for_status(self, status):
@@ -29,7 +29,7 b' from rhodecode.lib.vcs.backends import b'
29 29
30 30 class GitDiff(base.Diff):
31 31
32 _header_re = re.compile(r"""
32 _header_re = re.compile(br"""
33 33 #^diff[ ]--git
34 34 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
35 35 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
@@ -23,7 +23,7 b' GIT inmemory module'
23 23 """
24 24
25 25 from rhodecode.lib.datelib import date_to_timestamp_plus_offset
26 from rhodecode.lib.utils import safe_str
26 from rhodecode.lib.str_utils import safe_str, get_default_encodings
27 27 from rhodecode.lib.vcs.backends import base
28 28
29 29
@@ -50,23 +50,23 b' class GitInMemoryCommit(base.BaseInMemor'
50 50 if branch is None:
51 51 branch = self.repository.DEFAULT_BRANCH_NAME
52 52
53 ENCODING = "UTF-8"
54
55 53 commit_tree = None
56 54 if self.parents[0]:
57 55 commit_tree = self.parents[0]._commit['tree']
58 56
57 encoding = get_default_encodings()[0]
59 58 updated = []
60 59 for node in self.added + self.changed:
61
62 if node.is_binary:
63 60 content = node.content
64 else:
65 content = node.content.encode(ENCODING)
61 # TODO: left for reference pre py3 migration, probably need to be removed
62 # if node.is_binary:
63 # content = node.content
64 # else:
65 # content = node.content.encode(ENCODING)
66 66
67 67 updated.append({
68 68 'path': node.path,
69 'node_path': node.name.encode(ENCODING),
69 'node_path': node.name,
70 70 'content': content,
71 71 'mode': node.mode,
72 72 })
@@ -75,7 +75,6 b' class GitInMemoryCommit(base.BaseInMemor'
75 75
76 76 date, tz = date_to_timestamp_plus_offset(date)
77 77
78 # TODO: johbo: Make kwargs explicit and check if this is needed.
79 78 author_time = kwargs.pop('author_time', date)
80 79 author_tz = kwargs.pop('author_timezone', tz)
81 80
@@ -83,11 +82,13 b' class GitInMemoryCommit(base.BaseInMemor'
83 82 'parents': [p._commit['id'] for p in self.parents if p],
84 83 'author': safe_str(author),
85 84 'committer': safe_str(author),
86 'encoding': ENCODING,
85 'encoding': encoding,
87 86 'message': safe_str(message),
87
88 88 'commit_time': int(date),
89 'commit_timezone': tz,
90
89 91 'author_time': int(author_time),
90 'commit_timezone': tz,
91 92 'author_timezone': author_tz,
92 93 }
93 94
@@ -31,7 +31,7 b' from zope.cachedescriptors.property impo'
31 31 from collections import OrderedDict
32 32 from rhodecode.lib.datelib import (
33 33 utcdate_fromtimestamp, makedate, date_astimestamp)
34 from rhodecode.lib.utils import safe_unicode, safe_str
34 from rhodecode.lib.hash_utils import safe_str
35 35 from rhodecode.lib.utils2 import CachedProperty
36 36 from rhodecode.lib.vcs import connection, path as vcspath
37 37 from rhodecode.lib.vcs.backends.base import (
@@ -107,7 +107,7 b' class GitRepository(BaseRepository):'
107 107 :param opts: env options to pass into Subprocess command
108 108 """
109 109 if not isinstance(cmd, list):
110 raise ValueError('cmd must be a list, got %s instead' % type(cmd))
110 raise ValueError(f'cmd must be a list, got {type(cmd)} instead')
111 111
112 112 skip_stderr_log = opts.pop('skip_stderr_log', False)
113 113 out, err = self._remote.run_git_command(cmd, **opts)
@@ -310,7 +310,7 b' class GitRepository(BaseRepository):'
310 310 @LazyProperty
311 311 def description(self):
312 312 description = self._remote.get_description()
313 return safe_unicode(description or self.DEFAULT_DESCRIPTION)
313 return safe_str(description or self.DEFAULT_DESCRIPTION)
314 314
315 315 def _get_refs_entries(self, prefix='', reverse=False, strip_prefix=True):
316 316 if self.is_empty():
@@ -322,7 +322,7 b' class GitRepository(BaseRepository):'
322 322 ref_name = ref
323 323 if strip_prefix:
324 324 ref_name = ref[len(prefix):]
325 result.append((safe_unicode(ref_name), sha))
325 result.append((safe_str(ref_name), sha))
326 326
327 327 def get_name(entry):
328 328 return entry[0]
@@ -561,10 +561,12 b' class GitRepository(BaseRepository):'
561 561 ``self.EMPTY_COMMIT`` - in this case, patch showing all
562 562 the changes since empty state of the repository until ``commit2``
563 563 :param commit2: Until which commits changes should be shown.
564 :param path:
564 565 :param ignore_whitespace: If set to ``True``, would not show whitespace
565 566 changes. Defaults to ``False``.
566 567 :param context: How many lines before/after changed lines should be
567 568 shown. Defaults to ``3``.
569 :param path1:
568 570 """
569 571 self._validate_diff_commits(commit1, commit2)
570 572 if path1 is not None and path1 != path:
@@ -579,6 +581,7 b' class GitRepository(BaseRepository):'
579 581 commit1.raw_id, commit2.raw_id, file_filter=file_filter,
580 582 opt_ignorews=ignore_whitespace,
581 583 context=context)
584
582 585 return GitDiff(diff)
583 586
584 587 def strip(self, commit_id, branch_name):
@@ -865,8 +868,8 b' class GitRepository(BaseRepository):'
865 868
866 869 # N.B.(skreft): the --no-ff option is used to enforce the creation of a
867 870 # commit message. We also specify the user who is doing the merge.
868 cmd = ['-c', 'user.name="%s"' % safe_str(user_name),
869 '-c', 'user.email=%s' % safe_str(user_email),
871 cmd = ['-c', f'user.name="{user_name}"',
872 '-c', f'user.email={user_email}',
870 873 'merge', '--no-ff', '-m', safe_str(merge_message)]
871 874
872 875 merge_cmd = cmd + heads
@@ -27,15 +27,14 b' import os'
27 27 from zope.cachedescriptors.property import Lazy as LazyProperty
28 28
29 29 from rhodecode.lib.datelib import utcdate_fromtimestamp
30 from rhodecode.lib.utils import safe_str, safe_unicode
30 from rhodecode.lib.str_utils import safe_bytes, safe_str
31 31 from rhodecode.lib.vcs import path as vcspath
32 32 from rhodecode.lib.vcs.backends import base
33 from rhodecode.lib.vcs.backends.hg.diff import MercurialDiff
34 33 from rhodecode.lib.vcs.exceptions import CommitError
35 34 from rhodecode.lib.vcs.nodes import (
36 35 AddedFileNodesGenerator, ChangedFileNodesGenerator, DirNode, FileNode,
37 36 NodeKind, RemovedFileNodesGenerator, RootNode, SubModuleNode,
38 LargeFileNode, LARGEFILE_PREFIX)
37 LargeFileNode)
39 38 from rhodecode.lib.vcs.utils.paths import get_dirs_for_path
40 39
41 40
@@ -62,6 +61,7 b' class MercurialCommit(base.BaseCommit):'
62 61
63 62 # caches
64 63 self.nodes = {}
64 self._stat_modes = {} # stat info for paths
65 65
66 66 def _set_bulk_properties(self, pre_load):
67 67 if not pre_load:
@@ -75,9 +75,9 b' class MercurialCommit(base.BaseCommit):'
75 75
76 76 for attr, value in result.items():
77 77 if attr in ["author", "branch", "message"]:
78 value = safe_unicode(value)
78 value = safe_str(value)
79 79 elif attr == "affected_files":
80 value = map(safe_unicode, value)
80 value = list(map(safe_str, value))
81 81 elif attr == "date":
82 82 value = utcdate_fromtimestamp(*value)
83 83 elif attr in ["children", "parents"]:
@@ -94,7 +94,7 b' class MercurialCommit(base.BaseCommit):'
94 94
95 95 @LazyProperty
96 96 def branch(self):
97 return safe_unicode(self._remote.ctx_branch(self.raw_id))
97 return safe_str(self._remote.ctx_branch(self.raw_id))
98 98
99 99 @LazyProperty
100 100 def bookmarks(self):
@@ -105,15 +105,15 b' class MercurialCommit(base.BaseCommit):'
105 105
106 106 @LazyProperty
107 107 def message(self):
108 return safe_unicode(self._remote.ctx_description(self.raw_id))
108 return safe_str(self._remote.ctx_description(self.raw_id))
109 109
110 110 @LazyProperty
111 111 def committer(self):
112 return safe_unicode(self.author)
112 return safe_str(self.author)
113 113
114 114 @LazyProperty
115 115 def author(self):
116 return safe_unicode(self._remote.ctx_user(self.raw_id))
116 return safe_str(self._remote.ctx_user(self.raw_id))
117 117
118 118 @LazyProperty
119 119 def date(self):
@@ -132,9 +132,10 b' class MercurialCommit(base.BaseCommit):'
132 132
133 133 @LazyProperty
134 134 def _dir_paths(self):
135 p = list(set(get_dirs_for_path(*self._file_paths)))
136 p.insert(0, '')
137 return p
135 dir_paths = ['']
136 dir_paths.extend(list(set(get_dirs_for_path(*self._file_paths))))
137
138 return dir_paths
138 139
139 140 @LazyProperty
140 141 def _paths(self):
@@ -143,7 +144,7 b' class MercurialCommit(base.BaseCommit):'
143 144 @LazyProperty
144 145 def id(self):
145 146 if self.last:
146 return u'tip'
147 return 'tip'
147 148 return self.short_id
148 149
149 150 @LazyProperty
@@ -174,7 +175,7 b' class MercurialCommit(base.BaseCommit):'
174 175 phase_id = self._remote.ctx_phase(self.raw_id)
175 176 phase_text = self._get_phase_text(phase_id)
176 177
177 return safe_unicode(phase_text)
178 return safe_str(phase_text)
178 179
179 180 @LazyProperty
180 181 def obsolete(self):
@@ -194,13 +195,6 b' class MercurialCommit(base.BaseCommit):'
194 195 children = self._remote.ctx_children(self.raw_id)
195 196 return self._make_commits(children)
196 197
197 def _fix_path(self, path):
198 """
199 Mercurial keeps filenodes as str so we need to encode from unicode
200 to str.
201 """
202 return safe_str(super(MercurialCommit, self)._fix_path(path))
203
204 198 def _get_kind(self, path):
205 199 path = self._fix_path(path)
206 200 if path in self._file_paths:
@@ -208,43 +202,52 b' class MercurialCommit(base.BaseCommit):'
208 202 elif path in self._dir_paths:
209 203 return NodeKind.DIR
210 204 else:
211 raise CommitError(
212 "Node does not exist at the given path '%s'" % (path, ))
205 raise CommitError(f"Node does not exist at the given path '{path}'")
213 206
214 def _get_filectx(self, path):
207 def _assert_is_path(self, path) -> str:
215 208 path = self._fix_path(path)
216 209 if self._get_kind(path) != NodeKind.FILE:
217 raise CommitError(
218 "File does not exist for idx %s at '%s'" % (self.raw_id, path))
210 raise CommitError(f"File does not exist for commit {self.raw_id} at '{path}'")
211
219 212 return path
220 213
221 def get_file_mode(self, path):
214 def get_file_mode(self, path: bytes):
222 215 """
223 216 Returns stat mode of the file at the given ``path``.
224 217 """
225 path = self._get_filectx(path)
226 if 'x' in self._remote.fctx_flags(self.raw_id, path):
218 path = self._assert_is_path(path)
219
220 if path not in self._stat_modes:
221 self._stat_modes[path] = self._remote.fctx_flags(self.raw_id, path)
222
223 if 'x' in self._stat_modes[path]:
227 224 return base.FILEMODE_EXECUTABLE
228 else:
229 225 return base.FILEMODE_DEFAULT
230 226
231 227 def is_link(self, path):
232 path = self._get_filectx(path)
233 return 'l' in self._remote.fctx_flags(self.raw_id, path)
228 path = self._assert_is_path(path)
229 if path not in self._stat_modes:
230 self._stat_modes[path] = self._remote.fctx_flags(self.raw_id, path)
231
232 return 'l' in self._stat_modes[path]
234 233
235 234 def is_node_binary(self, path):
236 path = self._get_filectx(path)
235 path = self._assert_is_path(path)
237 236 return self._remote.is_binary(self.raw_id, path)
238 237
238 def node_md5_hash(self, path):
239 path = self._assert_is_path(path)
240 return self._remote.md5_hash(self.raw_id, path)
241
239 242 def get_file_content(self, path):
240 243 """
241 244 Returns content of the file at given ``path``.
242 245 """
243 path = self._get_filectx(path)
246 path = self._assert_is_path(path)
244 247 return self._remote.fctx_node_data(self.raw_id, path)
245 248
246 249 def get_file_content_streamed(self, path):
247 path = self._get_filectx(path)
250 path = self._assert_is_path(path)
248 251 stream_method = getattr(self._remote, 'stream:fctx_node_data')
249 252 return stream_method(self.raw_id, path)
250 253
@@ -252,7 +255,7 b' class MercurialCommit(base.BaseCommit):'
252 255 """
253 256 Returns size of the file at given ``path``.
254 257 """
255 path = self._get_filectx(path)
258 path = self._assert_is_path(path)
256 259 return self._remote.fctx_size(self.raw_id, path)
257 260
258 261 def get_path_history(self, path, limit=None, pre_load=None):
@@ -260,7 +263,7 b' class MercurialCommit(base.BaseCommit):'
260 263 Returns history of file as reversed list of `MercurialCommit` objects
261 264 for which file at given ``path`` has been modified.
262 265 """
263 path = self._get_filectx(path)
266 path = self._assert_is_path(path)
264 267 hist = self._remote.node_history(self.raw_id, path, limit)
265 268 return [
266 269 self.repository.get_commit(commit_id=commit_id, pre_load=pre_load)
@@ -279,7 +282,7 b' class MercurialCommit(base.BaseCommit):'
279 282 lambda: self.repository.get_commit(commit_id=commit_id, pre_load=pre_load),
280 283 content)
281 284
282 def get_nodes(self, path):
285 def get_nodes(self, path, pre_load=None):
283 286 """
284 287 Returns combined ``DirNode`` and ``FileNode`` objects list representing
285 288 state of commit at the given ``path``. If node at the given ``path``
@@ -292,14 +295,14 b' class MercurialCommit(base.BaseCommit):'
292 295 path = self._fix_path(path)
293 296
294 297 filenodes = [
295 FileNode(f, commit=self) for f in self._file_paths
298 FileNode(safe_bytes(f), commit=self, pre_load=pre_load) for f in self._file_paths
296 299 if os.path.dirname(f) == path]
297 300 # TODO: johbo: Check if this can be done in a more obvious way
298 301 dirs = path == '' and '' or [
299 302 d for d in self._dir_paths
300 303 if d and vcspath.dirname(d) == path]
301 304 dirnodes = [
302 DirNode(d, commit=self) for d in dirs
305 DirNode(safe_bytes(d), commit=self) for d in dirs
303 306 if os.path.dirname(d) == path]
304 307
305 308 alias = self.repository.alias
@@ -326,12 +329,12 b' class MercurialCommit(base.BaseCommit):'
326 329
327 330 if path not in self.nodes:
328 331 if path in self._file_paths:
329 node = FileNode(path, commit=self, pre_load=pre_load)
332 node = FileNode(safe_bytes(path), commit=self, pre_load=pre_load)
330 333 elif path in self._dir_paths:
331 334 if path == '':
332 335 node = RootNode(commit=self)
333 336 else:
334 node = DirNode(path, commit=self)
337 node = DirNode(safe_bytes(path), commit=self)
335 338 else:
336 339 raise self.no_node_at_path(path)
337 340
@@ -347,11 +350,11 b' class MercurialCommit(base.BaseCommit):'
347 350
348 351 if self._remote.in_largefiles_store(file_id):
349 352 lf_path = self._remote.store_path(file_id)
350 return LargeFileNode(lf_path, commit=self, org_path=path)
353 return LargeFileNode(safe_bytes(lf_path), commit=self, org_path=path)
351 354 elif self._remote.in_user_cache(file_id):
352 355 lf_path = self._remote.store_path(file_id)
353 356 self._remote.link(file_id, path)
354 return LargeFileNode(lf_path, commit=self, org_path=path)
357 return LargeFileNode(safe_bytes(lf_path), commit=self, org_path=path)
355 358
356 359 @LazyProperty
357 360 def _submodules(self):
@@ -29,7 +29,7 b' from rhodecode.lib.vcs.backends import b'
29 29
30 30 class MercurialDiff(base.Diff):
31 31
32 _header_re = re.compile(r"""
32 _header_re = re.compile(br"""
33 33 #^diff[ ]--git
34 34 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
35 35 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
@@ -23,7 +23,7 b' HG inmemory module'
23 23 """
24 24
25 25 from rhodecode.lib.datelib import date_to_timestamp_plus_offset
26 from rhodecode.lib.utils import safe_str
26 from rhodecode.lib.str_utils import safe_str
27 27 from rhodecode.lib.vcs.backends.base import BaseInMemoryCommit
28 28 from rhodecode.lib.vcs.exceptions import RepositoryError
29 29
@@ -65,14 +65,14 b' class MercurialInMemoryCommit(BaseInMemo'
65 65
66 66 parent_ids = [p.raw_id if p else None for p in self.parents]
67 67
68 ENCODING = "UTF-8"
69
70 68 updated = []
71 69 for node in self.added + self.changed:
72 if node.is_binary:
73 70 content = node.content
74 else:
75 content = node.content.encode(ENCODING)
71 # TODO: left for reference pre py3 migration, probably need to be removed
72 # if node.is_binary:
73 # content = node.content
74 # else:
75 # content = node.content.encode(ENCODING)
76 76 updated.append({
77 77 'path': node.path,
78 78 'content': content,
@@ -25,14 +25,16 b' import os'
25 25 import logging
26 26 import binascii
27 27 import configparser
28 import urllib.request, urllib.parse, urllib.error
28 import urllib.request
29 import urllib.parse
30 import urllib.error
29 31
30 32 from zope.cachedescriptors.property import Lazy as LazyProperty
31 33
32 34 from collections import OrderedDict
33 35 from rhodecode.lib.datelib import (
34 36 date_to_timestamp_plus_offset, utcdate_fromtimestamp, makedate)
35 from rhodecode.lib.utils import safe_unicode, safe_str
37 from rhodecode.lib.str_utils import safe_str
36 38 from rhodecode.lib.utils2 import CachedProperty
37 39 from rhodecode.lib.vcs import connection, exceptions
38 40 from rhodecode.lib.vcs.backends.base import (
@@ -135,7 +137,7 b' class MercurialRepository(BaseRepository'
135 137 def get_name(ctx):
136 138 return ctx[0]
137 139
138 _branches = [(safe_unicode(n), hexlify(h),) for n, h in
140 _branches = [(n, h,) for n, h in
139 141 self._remote.branches(active, closed).items()]
140 142
141 143 return OrderedDict(sorted(_branches, key=get_name, reverse=False))
@@ -154,7 +156,7 b' class MercurialRepository(BaseRepository'
154 156 def get_name(ctx):
155 157 return ctx[0]
156 158
157 _tags = [(safe_unicode(n), hexlify(h),) for n, h in
159 _tags = [(n, h,) for n, h in
158 160 self._remote.tags().items()]
159 161
160 162 return OrderedDict(sorted(_tags, key=get_name, reverse=True))
@@ -230,7 +232,7 b' class MercurialRepository(BaseRepository'
230 232 return ctx[0]
231 233
232 234 _bookmarks = [
233 (safe_unicode(n), hexlify(h)) for n, h in
235 (n, h) for n, h in
234 236 self._remote.bookmarks().items()]
235 237
236 238 return OrderedDict(sorted(_bookmarks, key=get_name))
@@ -365,8 +367,7 b' class MercurialRepository(BaseRepository'
365 367 """
366 368 if create and os.path.exists(self.path):
367 369 raise RepositoryError(
368 "Cannot create repository at %s, location already exist"
369 % self.path)
370 f"Cannot create repository at {self.path}, location already exist")
370 371
371 372 if src_url:
372 373 url = str(self._get_url(src_url))
@@ -379,6 +380,7 b' class MercurialRepository(BaseRepository'
379 380
380 381 if create:
381 382 os.makedirs(self.path, mode=0o755)
383
382 384 self._remote.localrepository(create)
383 385
384 386 @LazyProperty
@@ -389,14 +391,14 b' class MercurialRepository(BaseRepository'
389 391 def description(self):
390 392 description = self._remote.get_config_value(
391 393 'web', 'description', untrusted=True)
392 return safe_unicode(description or self.DEFAULT_DESCRIPTION)
394 return safe_str(description or self.DEFAULT_DESCRIPTION)
393 395
394 396 @LazyProperty
395 397 def contact(self):
396 398 contact = (
397 399 self._remote.get_config_value("web", "contact") or
398 400 self._remote.get_config_value("ui", "username"))
399 return safe_unicode(contact or self.DEFAULT_CONTACT)
401 return safe_str(contact or self.DEFAULT_CONTACT)
400 402
401 403 @LazyProperty
402 404 def last_change(self):
@@ -425,7 +427,6 b' class MercurialRepository(BaseRepository'
425 427 to filesystem
426 428 (``file:///``) schema.
427 429 """
428 url = url.encode('utf8')
429 430 if url != 'default' and '://' not in url:
430 431 url = "file:" + urllib.request.pathname2url(url)
431 432 return url
@@ -467,10 +468,7 b' class MercurialRepository(BaseRepository'
467 468 else:
468 469 commit_id = "tip"
469 470
470 #TODO: decide if we pass bytes or str into lookup ?
471 # if isinstance(commit_id, unicode):
472 # commit_id = safe_str(commit_id)
473
471 # case here is no cached version, do an actual lookup instead
474 472 try:
475 473 raw_id, idx = self._remote.lookup(commit_id, both=True)
476 474 except CommitDoesNotExistError:
@@ -1009,5 +1007,9 b' class MercurialRepository(BaseRepository'
1009 1007 class MercurialIndexBasedCollectionGenerator(CollectionGenerator):
1010 1008
1011 1009 def _commit_factory(self, commit_id):
1010 if isinstance(commit_id, int):
1012 1011 return self.repo.get_commit(
1013 1012 commit_idx=commit_id, pre_load=self.pre_load)
1013 else:
1014 return self.repo.get_commit(
1015 commit_id=commit_id, pre_load=self.pre_load)
@@ -26,10 +26,10 b' SVN commit module'
26 26 import dateutil.parser
27 27 from zope.cachedescriptors.property import Lazy as LazyProperty
28 28
29 from rhodecode.lib.utils import safe_str, safe_unicode
29 from rhodecode.lib.str_utils import safe_bytes, safe_str
30 30 from rhodecode.lib.vcs import nodes, path as vcspath
31 31 from rhodecode.lib.vcs.backends import base
32 from rhodecode.lib.vcs.exceptions import CommitError, NodeDoesNotExistError
32 from rhodecode.lib.vcs.exceptions import CommitError
33 33
34 34
35 35 _SVN_PROP_TRUE = '*'
@@ -63,7 +63,7 b' class SubversionCommit(base.BaseCommit):'
63 63
64 64 @property
65 65 def author(self):
66 return safe_unicode(self._properties.get('svn:author'))
66 return safe_str(self._properties.get('svn:author'))
67 67
68 68 @property
69 69 def date(self):
@@ -71,7 +71,7 b' class SubversionCommit(base.BaseCommit):'
71 71
72 72 @property
73 73 def message(self):
74 return safe_unicode(self._properties.get('svn:log'))
74 return safe_str(self._properties.get('svn:log'))
75 75
76 76 @LazyProperty
77 77 def _properties(self):
@@ -93,7 +93,7 b' class SubversionCommit(base.BaseCommit):'
93 93 return [child]
94 94 return []
95 95
96 def get_file_mode(self, path):
96 def get_file_mode(self, path: bytes):
97 97 # Note: Subversion flags files which are executable with a special
98 98 # property `svn:executable` which is set to the value ``"*"``.
99 99 if self._get_file_property(path, 'svn:executable') == _SVN_PROP_TRUE:
@@ -105,13 +105,17 b' class SubversionCommit(base.BaseCommit):'
105 105 # Note: Subversion has a flag for special files, the content of the
106 106 # file contains the type of that file.
107 107 if self._get_file_property(path, 'svn:special') == _SVN_PROP_TRUE:
108 return self.get_file_content(path).startswith('link')
108 return self.get_file_content(path).startswith(b'link')
109 109 return False
110 110
111 111 def is_node_binary(self, path):
112 112 path = self._fix_path(path)
113 113 return self._remote.is_binary(self._svn_rev, safe_str(path))
114 114
115 def node_md5_hash(self, path):
116 path = self._fix_path(path)
117 return self._remote.md5_hash(self._svn_rev, safe_str(path))
118
115 119 def _get_file_property(self, path, name):
116 120 file_properties = self._remote.node_properties(
117 121 safe_str(path), self._svn_rev)
@@ -119,16 +123,17 b' class SubversionCommit(base.BaseCommit):'
119 123
120 124 def get_file_content(self, path):
121 125 path = self._fix_path(path)
122 return self._remote.get_file_content(safe_str(path), self._svn_rev)
126 return self._remote.get_file_content(self._svn_rev, safe_str(path))
123 127
124 128 def get_file_content_streamed(self, path):
125 129 path = self._fix_path(path)
130
126 131 stream_method = getattr(self._remote, 'stream:get_file_content')
127 return stream_method(safe_str(path), self._svn_rev)
132 return stream_method(self._svn_rev, safe_str(path))
128 133
129 134 def get_file_size(self, path):
130 135 path = self._fix_path(path)
131 return self._remote.get_file_size(safe_str(path), self._svn_rev)
136 return self._remote.get_file_size(self._svn_rev, safe_str(path))
132 137
133 138 def get_path_history(self, path, limit=None, pre_load=None):
134 139 path = safe_str(self._fix_path(path))
@@ -156,34 +161,32 b' class SubversionCommit(base.BaseCommit):'
156 161 if path == '':
157 162 node = nodes.RootNode(commit=self)
158 163 else:
159 node_type = self._remote.get_node_type(
160 safe_str(path), self._svn_rev)
164 node_type = self._remote.get_node_type(self._svn_rev, safe_str(path))
161 165 if node_type == 'dir':
162 node = nodes.DirNode(path, commit=self)
166 node = nodes.DirNode(safe_bytes(path), commit=self)
163 167 elif node_type == 'file':
164 node = nodes.FileNode(path, commit=self, pre_load=pre_load)
168 node = nodes.FileNode(safe_bytes(path), commit=self, pre_load=pre_load)
165 169 else:
166 170 raise self.no_node_at_path(path)
167 171
168 172 self.nodes[path] = node
169 173 return self.nodes[path]
170 174
171 def get_nodes(self, path):
175 def get_nodes(self, path, pre_load=None):
172 176 if self._get_kind(path) != nodes.NodeKind.DIR:
173 177 raise CommitError(
174 "Directory does not exist for commit %s at "
175 " '%s'" % (self.raw_id, path))
178 f"Directory does not exist for commit {self.raw_id} at '{path}'")
176 179 path = safe_str(self._fix_path(path))
177 180
178 181 path_nodes = []
179 for name, kind in self._remote.get_nodes(path, revision=self._svn_rev):
182 for name, kind in self._remote.get_nodes(self._svn_rev, path):
180 183 node_path = vcspath.join(path, name)
181 184 if kind == 'dir':
182 node = nodes.DirNode(node_path, commit=self)
185 node = nodes.DirNode(safe_bytes(node_path), commit=self)
183 186 elif kind == 'file':
184 node = nodes.FileNode(node_path, commit=self)
187 node = nodes.FileNode(safe_bytes(node_path), commit=self, pre_load=pre_load)
185 188 else:
186 raise ValueError("Node kind %s not supported." % (kind, ))
189 raise ValueError(f"Node kind {kind} not supported.")
187 190 self.nodes[node_path] = node
188 191 path_nodes.append(node)
189 192
@@ -191,7 +194,7 b' class SubversionCommit(base.BaseCommit):'
191 194
192 195 def _get_kind(self, path):
193 196 path = self._fix_path(path)
194 kind = self._remote.get_node_type(path, self._svn_rev)
197 kind = self._remote.get_node_type(self._svn_rev, path)
195 198 if kind == 'file':
196 199 return nodes.NodeKind.FILE
197 200 elif kind == 'dir':
@@ -29,11 +29,11 b' from rhodecode.lib.vcs.backends import b'
29 29
30 30 class SubversionDiff(base.Diff):
31 31
32 _meta_re = re.compile(r"""
32 _meta_re = re.compile(br"""
33 33 (?:^(?P<svn_bin_patch>Cannot[ ]display:[ ]file[ ]marked[ ]as[ ]a[ ]binary[ ]type.)(?:\n|$))?
34 34 """, re.VERBOSE | re.MULTILINE)
35 35
36 _header_re = re.compile(r"""
36 _header_re = re.compile(br"""
37 37 #^diff[ ]--git
38 38 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
39 39 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
@@ -24,7 +24,7 b' SVN inmemory module'
24 24 """
25 25
26 26 from rhodecode.lib.datelib import date_astimestamp
27 from rhodecode.lib.utils import safe_str
27 from rhodecode.lib.str_utils import safe_str, safe_bytes
28 28 from rhodecode.lib.vcs.backends import base
29 29
30 30
@@ -42,8 +42,8 b' class SubversionInMemoryCommit(base.Base'
42 42 updated = []
43 43 for node in self.added:
44 44 node_data = {
45 'path': node.path,
46 'content': safe_str(node.content),
45 'path': safe_bytes(node.path),
46 'content': node.content,
47 47 'mode': node.mode,
48 48 }
49 49 if node.is_binary:
@@ -53,15 +53,15 b' class SubversionInMemoryCommit(base.Base'
53 53 updated.append(node_data)
54 54 for node in self.changed:
55 55 updated.append({
56 'path': node.path,
57 'content': safe_str(node.content),
56 'path': safe_bytes(node.path),
57 'content': node.content,
58 58 'mode': node.mode,
59 59 })
60 60
61 61 removed = []
62 62 for node in self.removed:
63 63 removed.append({
64 'path': node.path,
64 'path': safe_bytes(node.path),
65 65 })
66 66
67 67 timestamp = date_astimestamp(date) if date else None
@@ -24,13 +24,15 b' SVN repository module'
24 24
25 25 import logging
26 26 import os
27 import urllib.request, urllib.parse, urllib.error
27 import urllib.request
28 import urllib.parse
29 import urllib.error
28 30
29 31 from zope.cachedescriptors.property import Lazy as LazyProperty
30 32
31 33 from collections import OrderedDict
32 34 from rhodecode.lib.datelib import date_astimestamp
33 from rhodecode.lib.utils import safe_str, safe_unicode
35 from rhodecode.lib.str_utils import safe_str
34 36 from rhodecode.lib.utils2 import CachedProperty
35 37 from rhodecode.lib.vcs import connection, path as vcspath
36 38 from rhodecode.lib.vcs.backends import base
@@ -88,8 +90,8 b' class SubversionRepository(base.BaseRepo'
88 90 def _init_repo(self, create, src_url):
89 91 if create and os.path.exists(self.path):
90 92 raise RepositoryError(
91 "Cannot create repository at %s, location already exist"
92 % self.path)
93 f"Cannot create repository at {self.path}, location already exist"
94 )
93 95
94 96 if create:
95 97 self._remote.create_repository(settings.SVN_COMPATIBLE_VERSION)
@@ -116,7 +118,7 b' class SubversionRepository(base.BaseRepo'
116 118 :param opts: env options to pass into Subprocess command
117 119 """
118 120 if not isinstance(cmd, list):
119 raise ValueError('cmd must be a list, got %s instead' % type(cmd))
121 raise ValueError(f'cmd must be a list, got {type(cmd)} instead')
120 122
121 123 skip_stderr_log = opts.pop('skip_stderr_log', False)
122 124 out, err = self._remote.run_svn_command(cmd, **opts)
@@ -165,10 +167,7 b' class SubversionRepository(base.BaseRepo'
165 167 directories = (tip.get_node(pattern), )
166 168 except NodeDoesNotExistError:
167 169 continue
168 found_items.update(
169 (safe_unicode(n.path),
170 self.commit_ids[-1])
171 for n in directories)
170 found_items.update((safe_str(n.path), self.commit_ids[-1]) for n in directories)
172 171
173 172 def get_name(item):
174 173 return item[0]
@@ -329,7 +328,7 b' class SubversionRepository(base.BaseRepo'
329 328
330 329 # TODO: johbo: Reconsider impact of DEFAULT_BRANCH_NAME here
331 330 if branch_name not in [None, self.DEFAULT_BRANCH_NAME]:
332 svn_rev = long(self.commit_ids[-1])
331 svn_rev = int(self.commit_ids[-1])
333 332 commit_ids = self._remote.node_history(
334 333 path=branch_name, revision=svn_rev, limit=None)
335 334 commit_ids = [str(i) for i in reversed(commit_ids)]
@@ -356,8 +355,8 b' class SubversionRepository(base.BaseRepo'
356 355 self, commit1, commit2, path=None, ignore_whitespace=False,
357 356 context=3, path1=None):
358 357 self._validate_diff_commits(commit1, commit2)
359 svn_rev1 = long(commit1.raw_id)
360 svn_rev2 = long(commit2.raw_id)
358 svn_rev1 = int(commit1.raw_id)
359 svn_rev2 = int(commit2.raw_id)
361 360 diff = self._remote.diff(
362 361 svn_rev1, svn_rev2, path1=path1, path2=path,
363 362 ignore_whitespace=ignore_whitespace, context=context)
General Comments 0
You need to be logged in to leave comments. Login now