Show More
@@ -35,6 +35,7 b' import urllib' | |||
|
35 | 35 | import urlobject |
|
36 | 36 | import uuid |
|
37 | 37 | import getpass |
|
38 | from functools import update_wrapper, partial | |
|
38 | 39 | |
|
39 | 40 | import pygments.lexers |
|
40 | 41 | import sqlalchemy |
@@ -1027,3 +1028,43 b' def parse_byte_string(size_str):' | |||
|
1027 | 1028 | _parts = match.groups() |
|
1028 | 1029 | num, type_ = _parts |
|
1029 | 1030 | return long(num) * {'mb': 1024*1024, 'kb': 1024}[type_.lower()] |
|
1031 | ||
|
1032 | ||
|
1033 | class CachedProperty(object): | |
|
1034 | """ | |
|
1035 | Lazy Attributes. With option to invalidate the cache by running a method | |
|
1036 | ||
|
1037 | class Foo(): | |
|
1038 | ||
|
1039 | @CachedProperty | |
|
1040 | def heavy_func(): | |
|
1041 | return 'super-calculation' | |
|
1042 | ||
|
1043 | foo = Foo() | |
|
1044 | foo.heavy_func() # first computions | |
|
1045 | foo.heavy_func() # fetch from cache | |
|
1046 | foo._invalidate_prop_cache('heavy_func') | |
|
1047 | # at this point calling foo.heavy_func() will be re-computed | |
|
1048 | """ | |
|
1049 | ||
|
1050 | def __init__(self, func, func_name=None): | |
|
1051 | ||
|
1052 | if func_name is None: | |
|
1053 | func_name = func.__name__ | |
|
1054 | self.data = (func, func_name) | |
|
1055 | update_wrapper(self, func) | |
|
1056 | ||
|
1057 | def __get__(self, inst, class_): | |
|
1058 | if inst is None: | |
|
1059 | return self | |
|
1060 | ||
|
1061 | func, func_name = self.data | |
|
1062 | value = func(inst) | |
|
1063 | inst.__dict__[func_name] = value | |
|
1064 | if '_invalidate_prop_cache' not in inst.__dict__: | |
|
1065 | inst.__dict__['_invalidate_prop_cache'] = partial( | |
|
1066 | self._invalidate_prop_cache, inst) | |
|
1067 | return value | |
|
1068 | ||
|
1069 | def _invalidate_prop_cache(self, inst, name): | |
|
1070 | inst.__dict__.pop(name, None) |
@@ -33,12 +33,12 b' import collections' | |||
|
33 | 33 | import warnings |
|
34 | 34 | |
|
35 | 35 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
36 | from zope.cachedescriptors.property import CachedProperty | |
|
37 | 36 | |
|
38 | 37 | from pyramid import compat |
|
39 | 38 | |
|
39 | import rhodecode | |
|
40 | 40 | from rhodecode.translation import lazy_ugettext |
|
41 | from rhodecode.lib.utils2 import safe_str, safe_unicode | |
|
41 | from rhodecode.lib.utils2 import safe_str, safe_unicode, CachedProperty | |
|
42 | 42 | from rhodecode.lib.vcs import connection |
|
43 | 43 | from rhodecode.lib.vcs.utils import author_name, author_email |
|
44 | 44 | from rhodecode.lib.vcs.conf import settings |
@@ -264,7 +264,9 b' class BaseRepository(object):' | |||
|
264 | 264 | EMPTY_COMMIT_ID = '0' * 40 |
|
265 | 265 | |
|
266 | 266 | path = None |
|
267 | _commit_ids_ver = 0 | |
|
267 | ||
|
268 | _is_empty = None | |
|
269 | _commit_ids = {} | |
|
268 | 270 | |
|
269 | 271 | def __init__(self, repo_path, config=None, create=False, **kwargs): |
|
270 | 272 | """ |
@@ -386,8 +388,23 b' class BaseRepository(object):' | |||
|
386 | 388 | commit = self.get_commit(commit_id) |
|
387 | 389 | return commit.size |
|
388 | 390 | |
|
391 | def _check_for_empty(self): | |
|
392 | no_commits = len(self._commit_ids) == 0 | |
|
393 | if no_commits: | |
|
394 | # check on remote to be sure | |
|
395 | return self._remote.is_empty() | |
|
396 | else: | |
|
397 | return False | |
|
398 | ||
|
389 | 399 | def is_empty(self): |
|
390 | return self._remote.is_empty() | |
|
400 | if rhodecode.is_test: | |
|
401 | return self._check_for_empty() | |
|
402 | ||
|
403 | if self._is_empty is None: | |
|
404 | # cache empty for production, but not tests | |
|
405 | self._is_empty = self._check_for_empty() | |
|
406 | ||
|
407 | return self._is_empty | |
|
391 | 408 | |
|
392 | 409 | @staticmethod |
|
393 | 410 | def check_url(url, config): |
@@ -408,14 +425,15 b' class BaseRepository(object):' | |||
|
408 | 425 | # COMMITS |
|
409 | 426 | # ========================================================================== |
|
410 | 427 | |
|
411 |
@CachedProperty |
|
|
428 | @CachedProperty | |
|
412 | 429 | def commit_ids(self): |
|
413 | 430 | raise NotImplementedError |
|
414 | 431 | |
|
415 | 432 | def append_commit_id(self, commit_id): |
|
416 | 433 | if commit_id not in self.commit_ids: |
|
417 | 434 | self._rebuild_cache(self.commit_ids + [commit_id]) |
|
418 | self._commit_ids_ver = time.time() | |
|
435 | # clear cache | |
|
436 | self._invalidate_prop_cache('commit_ids') | |
|
419 | 437 | |
|
420 | 438 | def get_commit(self, commit_id=None, commit_idx=None, pre_load=None, translate_tag=None): |
|
421 | 439 | """ |
@@ -46,12 +46,6 b' class GitCommit(base.BaseCommit):' | |||
|
46 | 46 | """ |
|
47 | 47 | Represents state of the repository at single commit id. |
|
48 | 48 | """ |
|
49 | _author_property = 'author' | |
|
50 | _committer_property = 'committer' | |
|
51 | _date_property = 'commit_time' | |
|
52 | _date_tz_property = 'commit_timezone' | |
|
53 | _message_property = 'message' | |
|
54 | _parents_property = 'parents' | |
|
55 | 49 | |
|
56 | 50 | _filter_pre_load = [ |
|
57 | 51 | # done through a more complex tree walk on parents |
@@ -124,23 +118,19 b' class GitCommit(base.BaseCommit):' | |||
|
124 | 118 | |
|
125 | 119 | @LazyProperty |
|
126 | 120 | def message(self): |
|
127 | return safe_unicode( | |
|
128 | self._remote.commit_attribute(self.id, self._message_property)) | |
|
121 | return safe_unicode(self._remote.message(self.id)) | |
|
129 | 122 | |
|
130 | 123 | @LazyProperty |
|
131 | 124 | def committer(self): |
|
132 | return safe_unicode( | |
|
133 | self._remote.commit_attribute(self.id, self._committer_property)) | |
|
125 | return safe_unicode(self._remote.author(self.id)) | |
|
134 | 126 | |
|
135 | 127 | @LazyProperty |
|
136 | 128 | def author(self): |
|
137 | return safe_unicode( | |
|
138 | self._remote.commit_attribute(self.id, self._author_property)) | |
|
129 | return safe_unicode(self._remote.author(self.id)) | |
|
139 | 130 | |
|
140 | 131 | @LazyProperty |
|
141 | 132 | def date(self): |
|
142 |
unix_ts, tz = self._remote. |
|
|
143 | self.raw_id, self._date_property, self._date_tz_property) | |
|
133 | unix_ts, tz = self._remote.date(self.raw_id) | |
|
144 | 134 | return utcdate_fromtimestamp(unix_ts, tz) |
|
145 | 135 | |
|
146 | 136 | @LazyProperty |
@@ -158,13 +148,23 b' class GitCommit(base.BaseCommit):' | |||
|
158 | 148 | return tags |
|
159 | 149 | |
|
160 | 150 | @LazyProperty |
|
161 | def branch(self): | |
|
151 | def commit_branches(self): | |
|
152 | branches = [] | |
|
162 | 153 | for name, commit_id in self.repository.branches.iteritems(): |
|
163 | 154 | if commit_id == self.raw_id: |
|
164 |
|
|
|
155 | branches.append(name) | |
|
156 | return branches | |
|
157 | ||
|
158 | @LazyProperty | |
|
159 | def branch(self): | |
|
160 | # actually commit can have multiple branches | |
|
161 | branches = self.commit_branches | |
|
162 | if branches: | |
|
163 | return branches[0] | |
|
164 | ||
|
165 | 165 | return None |
|
166 | 166 | |
|
167 | def _get_id_for_path(self, path): | |
|
167 | def _get_tree_id_for_path(self, path): | |
|
168 | 168 | path = safe_str(path) |
|
169 | 169 | if path in self._paths: |
|
170 | 170 | return self._paths[path] |
@@ -177,56 +177,26 b' class GitCommit(base.BaseCommit):' | |||
|
177 | 177 | self._paths[''] = data |
|
178 | 178 | return data |
|
179 | 179 | |
|
180 | parts = path.split('/') | |
|
181 | dirs, name = parts[:-1], parts[-1] | |
|
182 | cur_dir = '' | |
|
183 | ||
|
184 | # initially extract things from root dir | |
|
185 | tree_items = self._remote.tree_items(tree_id) | |
|
186 | self._process_tree_items(tree_items, cur_dir) | |
|
180 | tree_id, tree_type, tree_mode = \ | |
|
181 | self._remote.tree_and_type_for_path(self.raw_id, path) | |
|
182 | if tree_id is None: | |
|
183 | raise self.no_node_at_path(path) | |
|
187 | 184 | |
|
188 | for dir in dirs: | |
|
189 | if cur_dir: | |
|
190 | cur_dir = '/'.join((cur_dir, dir)) | |
|
191 | else: | |
|
192 | cur_dir = dir | |
|
193 | dir_id = None | |
|
194 | for item, stat_, id_, type_ in tree_items: | |
|
195 | if item == dir: | |
|
196 | dir_id = id_ | |
|
197 | break | |
|
198 | if dir_id: | |
|
199 | if type_ != "tree": | |
|
200 | raise CommitError('%s is not a directory' % cur_dir) | |
|
201 | # update tree | |
|
202 | tree_items = self._remote.tree_items(dir_id) | |
|
203 | else: | |
|
204 | raise CommitError('%s have not been found' % cur_dir) | |
|
205 | ||
|
206 | # cache all items from the given traversed tree | |
|
207 | self._process_tree_items(tree_items, cur_dir) | |
|
185 | self._paths[path] = [tree_id, tree_type] | |
|
186 | self._stat_modes[path] = tree_mode | |
|
208 | 187 | |
|
209 | 188 | if path not in self._paths: |
|
210 | 189 | raise self.no_node_at_path(path) |
|
211 | 190 | |
|
212 | 191 | return self._paths[path] |
|
213 | 192 | |
|
214 | def _process_tree_items(self, items, cur_dir): | |
|
215 | for item, stat_, id_, type_ in items: | |
|
216 | if cur_dir: | |
|
217 | name = '/'.join((cur_dir, item)) | |
|
218 | else: | |
|
219 | name = item | |
|
220 | self._paths[name] = [id_, type_] | |
|
221 | self._stat_modes[name] = stat_ | |
|
222 | ||
|
223 | 193 | def _get_kind(self, path): |
|
224 |
|
|
|
194 | tree_id, type_ = self._get_tree_id_for_path(path) | |
|
225 | 195 | if type_ == 'blob': |
|
226 | 196 | return NodeKind.FILE |
|
227 | 197 | elif type_ == 'tree': |
|
228 | 198 | return NodeKind.DIR |
|
229 | elif type == 'link': | |
|
199 | elif type_ == 'link': | |
|
230 | 200 | return NodeKind.SUBMODULE |
|
231 | 201 | return None |
|
232 | 202 | |
@@ -245,8 +215,7 b' class GitCommit(base.BaseCommit):' | |||
|
245 | 215 | """ |
|
246 | 216 | Returns list of parent commits. |
|
247 | 217 | """ |
|
248 |
parent_ids = self._remote. |
|
|
249 | self.id, self._parents_property) | |
|
218 | parent_ids = self._remote.parents(self.id) | |
|
250 | 219 | return self._make_commits(parent_ids) |
|
251 | 220 | |
|
252 | 221 | @LazyProperty |
@@ -266,11 +235,11 b' class GitCommit(base.BaseCommit):' | |||
|
266 | 235 | child_ids.extend(found_ids) |
|
267 | 236 | return self._make_commits(child_ids) |
|
268 | 237 | |
|
269 |
def _make_commits(self, commit_ids |
|
|
270 | return [ | |
|
271 |
self.repository.get_commit(commit_id=commit_id |
|
|
272 | translate_tag=False) | |
|
273 |
|
|
|
238 | def _make_commits(self, commit_ids): | |
|
239 | def commit_maker(_commit_id): | |
|
240 | return self.repository.get_commit(commit_id=commit_id) | |
|
241 | ||
|
242 | return [commit_maker(commit_id) for commit_id in commit_ids] | |
|
274 | 243 | |
|
275 | 244 | def get_file_mode(self, path): |
|
276 | 245 | """ |
@@ -278,7 +247,7 b' class GitCommit(base.BaseCommit):' | |||
|
278 | 247 | """ |
|
279 | 248 | path = safe_str(path) |
|
280 | 249 | # ensure path is traversed |
|
281 | self._get_id_for_path(path) | |
|
250 | self._get_tree_id_for_path(path) | |
|
282 | 251 | return self._stat_modes[path] |
|
283 | 252 | |
|
284 | 253 | def is_link(self, path): |
@@ -288,15 +257,15 b' class GitCommit(base.BaseCommit):' | |||
|
288 | 257 | """ |
|
289 | 258 | Returns content of the file at given `path`. |
|
290 | 259 | """ |
|
291 |
id |
|
|
292 |
return self._remote.blob_as_pretty_string(id |
|
|
260 | tree_id, _ = self._get_tree_id_for_path(path) | |
|
261 | return self._remote.blob_as_pretty_string(tree_id) | |
|
293 | 262 | |
|
294 | 263 | def get_file_size(self, path): |
|
295 | 264 | """ |
|
296 | 265 | Returns size of the file at given `path`. |
|
297 | 266 | """ |
|
298 |
id |
|
|
299 |
return self._remote.blob_raw_length(id |
|
|
267 | tree_id, _ = self._get_tree_id_for_path(path) | |
|
268 | return self._remote.blob_raw_length(tree_id) | |
|
300 | 269 | |
|
301 | 270 | def get_path_history(self, path, limit=None, pre_load=None): |
|
302 | 271 | """ |
@@ -350,20 +319,23 b' class GitCommit(base.BaseCommit):' | |||
|
350 | 319 | line) |
|
351 | 320 | |
|
352 | 321 | def get_nodes(self, path): |
|
322 | ||
|
353 | 323 | if self._get_kind(path) != NodeKind.DIR: |
|
354 | 324 | raise CommitError( |
|
355 | 325 | "Directory does not exist for commit %s at '%s'" % (self.raw_id, path)) |
|
356 | 326 | path = self._fix_path(path) |
|
357 | id_, _ = self._get_id_for_path(path) | |
|
358 |
tree_id = self._ |
|
|
327 | ||
|
328 | tree_id, _ = self._get_tree_id_for_path(path) | |
|
329 | ||
|
359 | 330 | dirnodes = [] |
|
360 | 331 | filenodes = [] |
|
361 | alias = self.repository.alias | |
|
332 | ||
|
333 | # extracted tree ID gives us our files... | |
|
362 | 334 | for name, stat_, id_, type_ in self._remote.tree_items(tree_id): |
|
363 | 335 | if type_ == 'link': |
|
364 | 336 | url = self._get_submodule_url('/'.join((path, name))) |
|
365 | 337 | dirnodes.append(SubModuleNode( |
|
366 | name, url=url, commit=id_, alias=alias)) | |
|
338 | name, url=url, commit=id_, alias=self.repository.alias)) | |
|
367 | 339 | continue |
|
368 | 340 | |
|
369 | 341 | if path != '': |
@@ -394,7 +366,7 b' class GitCommit(base.BaseCommit):' | |||
|
394 | 366 | path = self._fix_path(path) |
|
395 | 367 | if path not in self.nodes: |
|
396 | 368 | try: |
|
397 |
id |
|
|
369 | tree_id, type_ = self._get_tree_id_for_path(path) | |
|
398 | 370 | except CommitError: |
|
399 | 371 | raise NodeDoesNotExistError( |
|
400 | 372 | "Cannot find one of parents' directories for a given " |
@@ -402,7 +374,7 b' class GitCommit(base.BaseCommit):' | |||
|
402 | 374 | |
|
403 | 375 | if type_ == 'link': |
|
404 | 376 | url = self._get_submodule_url(path) |
|
405 |
node = SubModuleNode(path, url=url, commit=id |
|
|
377 | node = SubModuleNode(path, url=url, commit=tree_id, | |
|
406 | 378 | alias=self.repository.alias) |
|
407 | 379 | elif type_ == 'tree': |
|
408 | 380 | if path == '': |
@@ -411,16 +383,18 b' class GitCommit(base.BaseCommit):' | |||
|
411 | 383 | node = DirNode(path, commit=self) |
|
412 | 384 | elif type_ == 'blob': |
|
413 | 385 | node = FileNode(path, commit=self, pre_load=pre_load) |
|
386 | self._stat_modes[path] = node.mode | |
|
414 | 387 | else: |
|
415 | 388 | raise self.no_node_at_path(path) |
|
416 | 389 | |
|
417 | 390 | # cache node |
|
418 | 391 | self.nodes[path] = node |
|
392 | ||
|
419 | 393 | return self.nodes[path] |
|
420 | 394 | |
|
421 | 395 | def get_largefile_node(self, path): |
|
422 |
id |
|
|
423 |
pointer_spec = self._remote.is_large_file(id |
|
|
396 | tree_id, _ = self._get_tree_id_for_path(path) | |
|
397 | pointer_spec = self._remote.is_large_file(tree_id) | |
|
424 | 398 | |
|
425 | 399 | if pointer_spec: |
|
426 | 400 | # content of that file regular FileNode is the hash of largefile |
@@ -25,15 +25,14 b' GIT repository module' | |||
|
25 | 25 | import logging |
|
26 | 26 | import os |
|
27 | 27 | import re |
|
28 | import time | |
|
29 | 28 | |
|
30 | 29 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
31 | from zope.cachedescriptors.property import CachedProperty | |
|
32 | 30 | |
|
33 | 31 | from rhodecode.lib.compat import OrderedDict |
|
34 | 32 | from rhodecode.lib.datelib import ( |
|
35 | 33 | utcdate_fromtimestamp, makedate, date_astimestamp) |
|
36 | 34 | from rhodecode.lib.utils import safe_unicode, safe_str |
|
35 | from rhodecode.lib.utils2 import CachedProperty | |
|
37 | 36 | from rhodecode.lib.vcs import connection, path as vcspath |
|
38 | 37 | from rhodecode.lib.vcs.backends.base import ( |
|
39 | 38 | BaseRepository, CollectionGenerator, Config, MergeResponse, |
@@ -71,9 +70,6 b' class GitRepository(BaseRepository):' | |||
|
71 | 70 | # caches |
|
72 | 71 | self._commit_ids = {} |
|
73 | 72 | |
|
74 | # dependent that trigger re-computation of commit_ids | |
|
75 | self._commit_ids_ver = 0 | |
|
76 | ||
|
77 | 73 | @LazyProperty |
|
78 | 74 | def _remote(self): |
|
79 | 75 | return connection.Git(self.path, self.config, with_wire=self.with_wire) |
@@ -86,7 +82,7 b' class GitRepository(BaseRepository):' | |||
|
86 | 82 | def head(self): |
|
87 | 83 | return self._remote.head() |
|
88 | 84 | |
|
89 |
@CachedProperty |
|
|
85 | @CachedProperty | |
|
90 | 86 | def commit_ids(self): |
|
91 | 87 | """ |
|
92 | 88 | Returns list of commit ids, in ascending order. Being lazy |
@@ -190,12 +186,16 b' class GitRepository(BaseRepository):' | |||
|
190 | 186 | except OSError as err: |
|
191 | 187 | raise RepositoryError(err) |
|
192 | 188 | |
|
193 |
def _get_all_commit_ids(self |
|
|
189 | def _get_all_commit_ids(self): | |
|
190 | return self._remote.get_all_commit_ids() | |
|
191 | ||
|
192 | def _get_commit_ids(self, filters=None): | |
|
194 | 193 | # we must check if this repo is not empty, since later command |
|
195 | 194 | # fails if it is. And it's cheaper to ask than throw the subprocess |
|
196 | 195 | # errors |
|
197 | 196 | |
|
198 | 197 | head = self._remote.head(show_exc=False) |
|
198 | ||
|
199 | 199 | if not head: |
|
200 | 200 | return [] |
|
201 | 201 | |
@@ -208,7 +208,7 b' class GitRepository(BaseRepository):' | |||
|
208 | 208 | if filters.get('until'): |
|
209 | 209 | extra_filter.append('--until=%s' % (filters['until'])) |
|
210 | 210 | if filters.get('branch_name'): |
|
211 |
rev_filter = [ |
|
|
211 | rev_filter = [] | |
|
212 | 212 | extra_filter.append(filters['branch_name']) |
|
213 | 213 | rev_filter.extend(extra_filter) |
|
214 | 214 | |
@@ -233,6 +233,8 b' class GitRepository(BaseRepository):' | |||
|
233 | 233 | |
|
234 | 234 | if commit_id_or_idx in (None, '', 'tip', 'HEAD', 'head', -1): |
|
235 | 235 | return self.commit_ids[-1] |
|
236 | commit_missing_err = "Commit {} does not exist for `{}`".format( | |
|
237 | *map(safe_str, [commit_id_or_idx, self.name])) | |
|
236 | 238 | |
|
237 | 239 | is_bstr = isinstance(commit_id_or_idx, (str, unicode)) |
|
238 | 240 | if ((is_bstr and commit_id_or_idx.isdigit() and len(commit_id_or_idx) < 12) |
@@ -240,30 +242,15 b' class GitRepository(BaseRepository):' | |||
|
240 | 242 | try: |
|
241 | 243 | commit_id_or_idx = self.commit_ids[int(commit_id_or_idx)] |
|
242 | 244 | except Exception: |
|
243 | msg = "Commit {} does not exist for `{}`".format(commit_id_or_idx, self.name) | |
|
244 | raise CommitDoesNotExistError(msg) | |
|
245 | raise CommitDoesNotExistError(commit_missing_err) | |
|
245 | 246 | |
|
246 | 247 | elif is_bstr: |
|
247 | # check full path ref, eg. refs/heads/master | |
|
248 | ref_id = self._refs.get(commit_id_or_idx) | |
|
249 | if ref_id: | |
|
250 | return ref_id | |
|
251 | ||
|
252 | # check branch name | |
|
253 | branch_ids = self.branches.values() | |
|
254 | ref_id = self._refs.get('refs/heads/%s' % commit_id_or_idx) | |
|
255 | if ref_id: | |
|
256 | return ref_id | |
|
257 | ||
|
258 | # check tag name | |
|
259 | ref_id = self._refs.get('refs/tags/%s' % commit_id_or_idx) | |
|
260 | if ref_id: | |
|
261 | return ref_id | |
|
262 | ||
|
263 | if (not SHA_PATTERN.match(commit_id_or_idx) or | |
|
264 | commit_id_or_idx not in self.commit_ids): | |
|
265 | msg = "Commit {} does not exist for `{}`".format(commit_id_or_idx, self.name) | |
|
266 | raise CommitDoesNotExistError(msg) | |
|
248 | # Need to call remote to translate id for tagging scenario | |
|
249 | try: | |
|
250 | remote_data = self._remote.get_object(commit_id_or_idx) | |
|
251 | commit_id_or_idx = remote_data["commit_id"] | |
|
252 | except (CommitDoesNotExistError,): | |
|
253 | raise CommitDoesNotExistError(commit_missing_err) | |
|
267 | 254 | |
|
268 | 255 | # Ensure we return full id |
|
269 | 256 | if not SHA_PATTERN.match(str(commit_id_or_idx)): |
@@ -327,32 +314,31 b' class GitRepository(BaseRepository):' | |||
|
327 | 314 | def _get_branches(self): |
|
328 | 315 | return self._get_refs_entries(prefix='refs/heads/', strip_prefix=True) |
|
329 | 316 | |
|
330 |
@ |
|
|
317 | @CachedProperty | |
|
331 | 318 | def branches(self): |
|
332 | 319 | return self._get_branches() |
|
333 | 320 | |
|
334 |
@ |
|
|
321 | @CachedProperty | |
|
335 | 322 | def branches_closed(self): |
|
336 | 323 | return {} |
|
337 | 324 | |
|
338 |
@ |
|
|
325 | @CachedProperty | |
|
339 | 326 | def bookmarks(self): |
|
340 | 327 | return {} |
|
341 | 328 | |
|
342 |
@ |
|
|
329 | @CachedProperty | |
|
343 | 330 | def branches_all(self): |
|
344 | 331 | all_branches = {} |
|
345 | 332 | all_branches.update(self.branches) |
|
346 | 333 | all_branches.update(self.branches_closed) |
|
347 | 334 | return all_branches |
|
348 | 335 | |
|
349 |
@ |
|
|
336 | @CachedProperty | |
|
350 | 337 | def tags(self): |
|
351 | 338 | return self._get_tags() |
|
352 | 339 | |
|
353 | 340 | def _get_tags(self): |
|
354 | return self._get_refs_entries( | |
|
355 | prefix='refs/tags/', strip_prefix=True, reverse=True) | |
|
341 | return self._get_refs_entries(prefix='refs/tags/', strip_prefix=True, reverse=True) | |
|
356 | 342 | |
|
357 | 343 | def tag(self, name, user, commit_id=None, message=None, date=None, |
|
358 | 344 | **kwargs): |
@@ -368,15 +354,17 b' class GitRepository(BaseRepository):' | |||
|
368 | 354 | |
|
369 | 355 | :raises TagAlreadyExistError: if tag with same name already exists |
|
370 | 356 | """ |
|
357 | print self._refs | |
|
371 | 358 | if name in self.tags: |
|
372 | 359 | raise TagAlreadyExistError("Tag %s already exists" % name) |
|
373 | 360 | commit = self.get_commit(commit_id=commit_id) |
|
374 | message = message or "Added tag %s for commit %s" % ( | |
|
375 | name, commit.raw_id) | |
|
376 |
self._remote.set_refs('refs/tags/%s' % name, commit._ |
|
|
361 | message = message or "Added tag %s for commit %s" % (name, commit.raw_id) | |
|
362 | ||
|
363 | self._remote.set_refs('refs/tags/%s' % name, commit.raw_id) | |
|
377 | 364 | |
|
378 | self._refs = self._get_refs() | |
|
379 | self.tags = self._get_tags() | |
|
365 | self._invalidate_prop_cache('tags') | |
|
366 | self._invalidate_prop_cache('_refs') | |
|
367 | ||
|
380 | 368 | return commit |
|
381 | 369 | |
|
382 | 370 | def remove_tag(self, name, user, message=None, date=None): |
@@ -392,19 +380,15 b' class GitRepository(BaseRepository):' | |||
|
392 | 380 | """ |
|
393 | 381 | if name not in self.tags: |
|
394 | 382 | raise TagDoesNotExistError("Tag %s does not exist" % name) |
|
395 | tagpath = vcspath.join( | |
|
396 |
|
|
|
397 | try: | |
|
398 | os.remove(tagpath) | |
|
399 | self._refs = self._get_refs() | |
|
400 | self.tags = self._get_tags() | |
|
401 | except OSError as e: | |
|
402 | raise RepositoryError(e.strerror) | |
|
383 | ||
|
384 | self._remote.tag_remove(name) | |
|
385 | self._invalidate_prop_cache('tags') | |
|
386 | self._invalidate_prop_cache('_refs') | |
|
403 | 387 | |
|
404 | 388 | def _get_refs(self): |
|
405 | 389 | return self._remote.get_refs() |
|
406 | 390 | |
|
407 |
@ |
|
|
391 | @CachedProperty | |
|
408 | 392 | def _refs(self): |
|
409 | 393 | return self._get_refs() |
|
410 | 394 | |
@@ -455,18 +439,13 b' class GitRepository(BaseRepository):' | |||
|
455 | 439 | else: |
|
456 | 440 | commit_id = "tip" |
|
457 | 441 | |
|
442 | if translate_tag: | |
|
458 | 443 | commit_id = self._lookup_commit(commit_id) |
|
459 | remote_idx = None | |
|
460 | if translate_tag: | |
|
461 | # Need to call remote to translate id for tagging scenario | |
|
462 | remote_data = self._remote.get_object(commit_id) | |
|
463 | commit_id = remote_data["commit_id"] | |
|
464 | remote_idx = remote_data["idx"] | |
|
465 | 444 | |
|
466 | 445 | try: |
|
467 | 446 | idx = self._commit_ids[commit_id] |
|
468 | 447 | except KeyError: |
|
469 |
idx = |
|
|
448 | idx = -1 | |
|
470 | 449 | |
|
471 | 450 | return GitCommit(self, commit_id, idx, pre_load=pre_load) |
|
472 | 451 | |
@@ -539,14 +518,8 b' class GitRepository(BaseRepository):' | |||
|
539 | 518 | 'start': start_pos, |
|
540 | 519 | 'end': end_pos, |
|
541 | 520 | } |
|
542 |
commit_ids = self._get_ |
|
|
521 | commit_ids = self._get_commit_ids(filters=revfilters) | |
|
543 | 522 | |
|
544 | # pure python stuff, it's slow due to walker walking whole repo | |
|
545 | # def get_revs(walker): | |
|
546 | # for walker_entry in walker: | |
|
547 | # yield walker_entry.commit.id | |
|
548 | # revfilters = {} | |
|
549 | # commit_ids = list(reversed(list(get_revs(self._repo.get_walker(**revfilters))))) | |
|
550 | 523 | else: |
|
551 | 524 | commit_ids = self.commit_ids |
|
552 | 525 | |
@@ -613,8 +586,11 b' class GitRepository(BaseRepository):' | |||
|
613 | 586 | commit = commit.parents[0] |
|
614 | 587 | self._remote.set_refs('refs/heads/%s' % branch_name, commit.raw_id) |
|
615 | 588 | |
|
616 | self._commit_ids_ver = time.time() | |
|
617 | # we updated _commit_ids_ver so accessing self.commit_ids will re-compute it | |
|
589 | # clear cached properties | |
|
590 | self._invalidate_prop_cache('commit_ids') | |
|
591 | self._invalidate_prop_cache('_refs') | |
|
592 | self._invalidate_prop_cache('branches') | |
|
593 | ||
|
618 | 594 | return len(self.commit_ids) |
|
619 | 595 | |
|
620 | 596 | def get_common_ancestor(self, commit_id1, commit_id2, repo2): |
@@ -697,9 +673,11 b' class GitRepository(BaseRepository):' | |||
|
697 | 673 | |
|
698 | 674 | def set_refs(self, ref_name, commit_id): |
|
699 | 675 | self._remote.set_refs(ref_name, commit_id) |
|
676 | self._invalidate_prop_cache('_refs') | |
|
700 | 677 | |
|
701 | 678 | def remove_ref(self, ref_name): |
|
702 | 679 | self._remote.remove_ref(ref_name) |
|
680 | self._invalidate_prop_cache('_refs') | |
|
703 | 681 | |
|
704 | 682 | def _update_server_info(self): |
|
705 | 683 | """ |
@@ -744,6 +722,12 b' class GitRepository(BaseRepository):' | |||
|
744 | 722 | cmd.append(branch_name) |
|
745 | 723 | self.run_git_command(cmd, fail_on_stderr=False) |
|
746 | 724 | |
|
725 | def _create_branch(self, branch_name, commit_id): | |
|
726 | """ | |
|
727 | creates a branch in a GIT repo | |
|
728 | """ | |
|
729 | self._remote.create_branch(branch_name, commit_id) | |
|
730 | ||
|
747 | 731 | def _identify(self): |
|
748 | 732 | """ |
|
749 | 733 | Return the current state of the working directory. |
@@ -299,9 +299,10 b' class MercurialCommit(base.BaseCommit):' | |||
|
299 | 299 | loc = vals[0] |
|
300 | 300 | commit = vals[1] |
|
301 | 301 | dirnodes.append(SubModuleNode(k, url=loc, commit=commit, alias=alias)) |
|
302 | ||
|
302 | 303 | nodes = dirnodes + filenodes |
|
303 | # cache nodes | |
|
304 | 304 | for node in nodes: |
|
305 | if node.path not in self.nodes: | |
|
305 | 306 | self.nodes[node.path] = node |
|
306 | 307 | nodes.sort() |
|
307 | 308 |
@@ -24,16 +24,15 b' HG repository module' | |||
|
24 | 24 | import os |
|
25 | 25 | import logging |
|
26 | 26 | import binascii |
|
27 | import time | |
|
28 | 27 | import urllib |
|
29 | 28 | |
|
30 | 29 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
31 | from zope.cachedescriptors.property import CachedProperty | |
|
32 | 30 | |
|
33 | 31 | from rhodecode.lib.compat import OrderedDict |
|
34 | 32 | from rhodecode.lib.datelib import ( |
|
35 | 33 | date_to_timestamp_plus_offset, utcdate_fromtimestamp, makedate) |
|
36 | 34 | from rhodecode.lib.utils import safe_unicode, safe_str |
|
35 | from rhodecode.lib.utils2 import CachedProperty | |
|
37 | 36 | from rhodecode.lib.vcs import connection, exceptions |
|
38 | 37 | from rhodecode.lib.vcs.backends.base import ( |
|
39 | 38 | BaseRepository, CollectionGenerator, Config, MergeResponse, |
@@ -87,14 +86,11 b' class MercurialRepository(BaseRepository' | |||
|
87 | 86 | # caches |
|
88 | 87 | self._commit_ids = {} |
|
89 | 88 | |
|
90 | # dependent that trigger re-computation of commit_ids | |
|
91 | self._commit_ids_ver = 0 | |
|
92 | ||
|
93 | 89 | @LazyProperty |
|
94 | 90 | def _remote(self): |
|
95 | 91 | return connection.Hg(self.path, self.config, with_wire=self.with_wire) |
|
96 | 92 | |
|
97 |
@CachedProperty |
|
|
93 | @CachedProperty | |
|
98 | 94 | def commit_ids(self): |
|
99 | 95 | """ |
|
100 | 96 | Returns list of commit ids, in ascending order. Being lazy |
@@ -108,15 +104,15 b' class MercurialRepository(BaseRepository' | |||
|
108 | 104 | self._commit_ids = dict((commit_id, index) |
|
109 | 105 | for index, commit_id in enumerate(commit_ids)) |
|
110 | 106 | |
|
111 |
@ |
|
|
107 | @CachedProperty | |
|
112 | 108 | def branches(self): |
|
113 | 109 | return self._get_branches() |
|
114 | 110 | |
|
115 |
@ |
|
|
111 | @CachedProperty | |
|
116 | 112 | def branches_closed(self): |
|
117 | 113 | return self._get_branches(active=False, closed=True) |
|
118 | 114 | |
|
119 |
@ |
|
|
115 | @CachedProperty | |
|
120 | 116 | def branches_all(self): |
|
121 | 117 | all_branches = {} |
|
122 | 118 | all_branches.update(self.branches) |
@@ -143,7 +139,7 b' class MercurialRepository(BaseRepository' | |||
|
143 | 139 | |
|
144 | 140 | return OrderedDict(sorted(_branches, key=get_name, reverse=False)) |
|
145 | 141 | |
|
146 |
@ |
|
|
142 | @CachedProperty | |
|
147 | 143 | def tags(self): |
|
148 | 144 | """ |
|
149 | 145 | Gets tags for this repository |
@@ -276,8 +272,9 b' class MercurialRepository(BaseRepository' | |||
|
276 | 272 | self._remote.strip(commit_id, update=False, backup="none") |
|
277 | 273 | |
|
278 | 274 | self._remote.invalidate_vcs_cache() |
|
279 | self._commit_ids_ver = time.time() | |
|
280 | # we updated _commit_ids_ver so accessing self.commit_ids will re-compute it | |
|
275 | # clear cache | |
|
276 | self._invalidate_prop_cache('commit_ids') | |
|
277 | ||
|
281 | 278 | return len(self.commit_ids) |
|
282 | 279 | |
|
283 | 280 | def verify(self): |
@@ -27,11 +27,11 b' import os' | |||
|
27 | 27 | import urllib |
|
28 | 28 | |
|
29 | 29 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
30 | from zope.cachedescriptors.property import CachedProperty | |
|
31 | 30 | |
|
32 | 31 | from rhodecode.lib.compat import OrderedDict |
|
33 | 32 | from rhodecode.lib.datelib import date_astimestamp |
|
34 | 33 | from rhodecode.lib.utils import safe_str, safe_unicode |
|
34 | from rhodecode.lib.utils2 import CachedProperty | |
|
35 | 35 | from rhodecode.lib.vcs import connection, path as vcspath |
|
36 | 36 | from rhodecode.lib.vcs.backends import base |
|
37 | 37 | from rhodecode.lib.vcs.backends.svn.commit import ( |
@@ -76,8 +76,9 b' class SubversionRepository(base.BaseRepo' | |||
|
76 | 76 | |
|
77 | 77 | self._init_repo(create, src_url) |
|
78 | 78 | |
|
79 | # dependent that trigger re-computation of commit_ids | |
|
80 |
self._commit_ids |
|
|
79 | # caches | |
|
80 | self._commit_ids = {} | |
|
81 | ||
|
81 | 82 | |
|
82 | 83 | @LazyProperty |
|
83 | 84 | def _remote(self): |
@@ -97,7 +98,7 b' class SubversionRepository(base.BaseRepo' | |||
|
97 | 98 | else: |
|
98 | 99 | self._check_path() |
|
99 | 100 | |
|
100 |
@CachedProperty |
|
|
101 | @CachedProperty | |
|
101 | 102 | def commit_ids(self): |
|
102 | 103 | head = self._remote.lookup(None) |
|
103 | 104 | return [str(r) for r in xrange(1, head + 1)] |
@@ -46,6 +46,7 b' class TestGitRepository(object):' | |||
|
46 | 46 | @pytest.fixture(autouse=True) |
|
47 | 47 | def prepare(self, request, baseapp): |
|
48 | 48 | self.repo = GitRepository(TEST_GIT_REPO, bare=True) |
|
49 | self.repo.count() | |
|
49 | 50 | |
|
50 | 51 | def get_clone_repo(self, tmp_path_factory): |
|
51 | 52 | """ |
@@ -1242,7 +1243,7 b' class TestGetSubmoduleUrl(object):' | |||
|
1242 | 1243 | commit = GitCommit(repository=repository, raw_id='abcdef12', idx=1) |
|
1243 | 1244 | submodule_url = 'https://code.rhodecode.com/dulwich' |
|
1244 | 1245 | get_id_patch = mock.patch.object( |
|
1245 | commit, '_get_id_for_path', return_value=(1, 'link')) | |
|
1246 | commit, '_get_tree_id_for_path', return_value=(1, 'link')) | |
|
1246 | 1247 | get_submodule_patch = mock.patch.object( |
|
1247 | 1248 | commit, '_get_submodule_url', return_value=submodule_url) |
|
1248 | 1249 | |
@@ -1262,7 +1263,7 b' class TestGetSubmoduleUrl(object):' | |||
|
1262 | 1263 | commit = GitCommit(repository=repository, raw_id='abcdef12', idx=1) |
|
1263 | 1264 | submodule_url = 'https://code.rhodecode.com/dulwich' |
|
1264 | 1265 | get_id_patch = mock.patch.object( |
|
1265 | commit, '_get_id_for_path', return_value=(1, 'tree')) | |
|
1266 | commit, '_get_tree_id_for_path', return_value=(1, 'tree')) | |
|
1266 | 1267 | get_submodule_patch = mock.patch.object( |
|
1267 | 1268 | commit, '_get_submodule_url', return_value=submodule_url) |
|
1268 | 1269 |
General Comments 0
You need to be logged in to leave comments.
Login now