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 exist |
|
|
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 |
|
|
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 ' |
|
|
79 |
|
|
|
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 |
|
|
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 |
|
|
|
224 |
|
|
|
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 |
|
|
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_ |
|
|
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_ |
|
|
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(" |
|
|
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 |
|
|
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 |
|
|
|
1349 |
|
|
|
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 |
|
|
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 __get |
|
|
1766 | """ | |
|
1767 | Returns an iterator of sliced repository | |
|
1768 | """ | |
|
1769 |
commit_ids = self.commit_ids[ |
|
|
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 = |
|
|
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. |
|
|
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 = |
|
|
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_ |
|
|
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_ |
|
|
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_ |
|
|
118 | return safe_str(self._remote.message(self.id)) | |
|
123 | 119 | |
|
124 | 120 | @LazyProperty |
|
125 | 121 | def committer(self): |
|
126 |
return safe_ |
|
|
122 | return safe_str(self._remote.author(self.id)) | |
|
127 | 123 | |
|
128 | 124 | @LazyProperty |
|
129 | 125 | def author(self): |
|
130 |
return safe_ |
|
|
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_ |
|
|
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_ |
|
|
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 _ |
|
|
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 = s |
|
|
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._ |
|
|
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 |
|
|
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: |
|
|
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 |
|
|
|
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 |
|
|
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 |
|
|
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': |
|
|
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 |
|
|
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 |
|
|
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_ |
|
|
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_ |
|
|
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=" |
|
|
869 |
'-c', '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_ |
|
|
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 |
|
|
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_ |
|
|
78 | value = safe_str(value) | |
|
79 | 79 | elif attr == "affected_files": |
|
80 |
value = map(safe_ |
|
|
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_ |
|
|
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_ |
|
|
108 | return safe_str(self._remote.ctx_description(self.raw_id)) | |
|
109 | 109 | |
|
110 | 110 | @LazyProperty |
|
111 | 111 | def committer(self): |
|
112 |
return safe_ |
|
|
112 | return safe_str(self.author) | |
|
113 | 113 | |
|
114 | 114 | @LazyProperty |
|
115 | 115 | def author(self): |
|
116 |
return safe_ |
|
|
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 |
|
|
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_ |
|
|
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 _ |
|
|
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._ |
|
|
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 |
|
|
230 | 226 | |
|
231 | 227 | def is_link(self, path): |
|
232 |
path = self._ |
|
|
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._ |
|
|
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._ |
|
|
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._ |
|
|
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._ |
|
|
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._ |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
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 = [( |
|
|
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 = [( |
|
|
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 |
( |
|
|
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 |
|
|
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_ |
|
|
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_ |
|
|
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_ |
|
|
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 |
|
|
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_ |
|
|
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_ |
|
|
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) |
|
|
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) |
|
|
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) |
|
|
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 |
|
|
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( |
|
|
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 |
|
|
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( |
|
|
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': |
|
|
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': |
|
|
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 |
|
|
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 |
|
|
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 |
|
|
92 |
|
|
|
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 |
|
|
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 = |
|
|
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 = |
|
|
360 |
svn_rev2 = |
|
|
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