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