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