##// END OF EJS Templates
another major code rafactor, reimplemented (almost from scratch)...
marcink -
r1038:5554aa9c beta
parent child Browse files
Show More
@@ -147,6 +147,7 b' class ReposController(BaseController):'
147
147
148 except formencode.Invalid, errors:
148 except formencode.Invalid, errors:
149 c.repo_info = repo_model.get_by_repo_name(repo_name)
149 c.repo_info = repo_model.get_by_repo_name(repo_name)
150
150 if c.repo_info.stats:
151 if c.repo_info.stats:
151 last_rev = c.repo_info.stats.stat_on_revision
152 last_rev = c.repo_info.stats.stat_on_revision
152 else:
153 else:
@@ -281,8 +282,9 b' class ReposController(BaseController):'
281 def edit(self, repo_name, format='html'):
282 def edit(self, repo_name, format='html'):
282 """GET /repos/repo_name/edit: Form to edit an existing item"""
283 """GET /repos/repo_name/edit: Form to edit an existing item"""
283 # url('edit_repo', repo_name=ID)
284 # url('edit_repo', repo_name=ID)
285 r = ScmModel().get(repo_name)[0]
286
284 repo_model = RepoModel()
287 repo_model = RepoModel()
285 r = ScmModel().get(repo_name)
286 c.repo_info = repo_model.get_by_repo_name(repo_name)
288 c.repo_info = repo_model.get_by_repo_name(repo_name)
287
289
288 if c.repo_info is None:
290 if c.repo_info is None:
@@ -45,8 +45,7 b' class BranchesController(BaseController)'
45 super(BranchesController, self).__before__()
45 super(BranchesController, self).__before__()
46
46
47 def index(self):
47 def index(self):
48 hg_model = ScmModel()
48 c.repo_info, dbrepo = ScmModel().get(c.repo_name, retval='repo')
49 c.repo_info = hg_model.get_repo(c.repo_name)
50 c.repo_branches = OrderedDict()
49 c.repo_branches = OrderedDict()
51 for name, hash_ in c.repo_info.branches.items():
50 for name, hash_ in c.repo_info.branches.items():
52 c.repo_branches[name] = c.repo_info.get_changeset(hash_)
51 c.repo_branches[name] = c.repo_info.get_changeset(hash_)
@@ -67,14 +67,14 b' class ChangelogController(BaseController'
67 else:
67 else:
68 c.size = int(session.get('changelog_size', default))
68 c.size = int(session.get('changelog_size', default))
69
69
70 changesets = ScmModel().get_repo(c.repo_name)
70 repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
71
71
72 p = int(request.params.get('page', 1))
72 p = int(request.params.get('page', 1))
73 c.total_cs = len(changesets)
73 c.total_cs = len(repo)
74 c.pagination = Page(changesets, page=p, item_count=c.total_cs,
74 c.pagination = Page(repo, page=p, item_count=c.total_cs,
75 items_per_page=c.size)
75 items_per_page=c.size)
76
76
77 self._graph(changesets, c.size, p)
77 self._graph(repo, c.size, p)
78
78
79 return render('changelog/changelog.html')
79 return render('changelog/changelog.html')
80
80
@@ -55,7 +55,6 b' class ChangesetController(BaseController'
55 super(ChangesetController, self).__before__()
55 super(ChangesetController, self).__before__()
56
56
57 def index(self, revision):
57 def index(self, revision):
58 hg_model = ScmModel()
59
58
60 def wrap_to_table(str):
59 def wrap_to_table(str):
61
60
@@ -70,7 +69,7 b' class ChangesetController(BaseController'
70 rev_range = revision.split('...')[:2]
69 rev_range = revision.split('...')[:2]
71 range_limit = 50
70 range_limit = 50
72 try:
71 try:
73 repo = hg_model.get_repo(c.repo_name)
72 repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
74 if len(rev_range) == 2:
73 if len(rev_range) == 2:
75 rev_start = rev_range[0]
74 rev_start = rev_range[0]
76 rev_end = rev_range[1]
75 rev_end = rev_range[1]
@@ -163,12 +162,11 b' class ChangesetController(BaseController'
163
162
164 def raw_changeset(self, revision):
163 def raw_changeset(self, revision):
165
164
166 hg_model = ScmModel()
167 method = request.GET.get('diff', 'show')
165 method = request.GET.get('diff', 'show')
168 try:
166 try:
169 r = hg_model.get_repo(c.repo_name)
167 repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
170 c.scm_type = r.alias
168 c.scm_type = repo.alias
171 c.changeset = r.get_changeset(revision)
169 c.changeset = repo.get_changeset(revision)
172 except RepositoryError:
170 except RepositoryError:
173 log.error(traceback.format_exc())
171 log.error(traceback.format_exc())
174 return redirect(url('home'))
172 return redirect(url('home'))
@@ -28,6 +28,7 b''
28 import logging
28 import logging
29
29
30 from pylons import url, response
30 from pylons import url, response
31 from pylons.i18n.translation import _
31
32
32 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
33 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
33 from rhodecode.lib.base import BaseController
34 from rhodecode.lib.base import BaseController
@@ -45,7 +46,7 b' class FeedController(BaseController):'
45 def __before__(self):
46 def __before__(self):
46 super(FeedController, self).__before__()
47 super(FeedController, self).__before__()
47 #common values for feeds
48 #common values for feeds
48 self.description = 'Changes on %s repository'
49 self.description = _('Changes on %s repository')
49 self.title = "%s feed"
50 self.title = "%s feed"
50 self.language = 'en-us'
51 self.language = 'en-us'
51 self.ttl = "5"
52 self.ttl = "5"
@@ -59,9 +60,9 b' class FeedController(BaseController):'
59 language=self.language,
60 language=self.language,
60 ttl=self.ttl)
61 ttl=self.ttl)
61
62
62 changesets = ScmModel().get_repo(repo_name)
63 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
63
64
64 for cs in changesets[:self.feed_nr]:
65 for cs in repo[:self.feed_nr]:
65 feed.add_item(title=cs.message,
66 feed.add_item(title=cs.message,
66 link=url('changeset_home', repo_name=repo_name,
67 link=url('changeset_home', repo_name=repo_name,
67 revision=cs.raw_id, qualified=True),
68 revision=cs.raw_id, qualified=True),
@@ -79,8 +80,8 b' class FeedController(BaseController):'
79 language=self.language,
80 language=self.language,
80 ttl=self.ttl)
81 ttl=self.ttl)
81
82
82 changesets = ScmModel().get_repo(repo_name)
83 repo, dbrepo = ScmModel().get(repo_name, retval='repo')
83 for cs in changesets[:self.feed_nr]:
84 for cs in repo[:self.feed_nr]:
84 feed.add_item(title=cs.message,
85 feed.add_item(title=cs.message,
85 link=url('changeset_home', repo_name=repo_name,
86 link=url('changeset_home', repo_name=repo_name,
86 revision=cs.raw_id, qualified=True),
87 revision=cs.raw_id, qualified=True),
@@ -57,8 +57,8 b' class FilesController(BaseController):'
57 c.cut_off_limit = self.cut_off_limit
57 c.cut_off_limit = self.cut_off_limit
58
58
59 def index(self, repo_name, revision, f_path):
59 def index(self, repo_name, revision, f_path):
60 hg_model = ScmModel()
60 c.repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
61 c.repo = hg_model.get_repo(c.repo_name)
61
62
62
63 try:
63 try:
64 #reditect to given revision from form
64 #reditect to given revision from form
@@ -116,8 +116,7 b' class FilesController(BaseController):'
116 return render('files/files.html')
116 return render('files/files.html')
117
117
118 def rawfile(self, repo_name, revision, f_path):
118 def rawfile(self, repo_name, revision, f_path):
119 hg_model = ScmModel()
119 c.repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
120 c.repo = hg_model.get_repo(c.repo_name)
121 file_node = c.repo.get_changeset(revision).get_node(f_path)
120 file_node = c.repo.get_changeset(revision).get_node(f_path)
122 response.content_type = file_node.mimetype
121 response.content_type = file_node.mimetype
123 response.content_disposition = 'attachment; filename=%s' \
122 response.content_disposition = 'attachment; filename=%s' \
@@ -125,16 +124,14 b' class FilesController(BaseController):'
125 return file_node.content
124 return file_node.content
126
125
127 def raw(self, repo_name, revision, f_path):
126 def raw(self, repo_name, revision, f_path):
128 hg_model = ScmModel()
127 c.repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
129 c.repo = hg_model.get_repo(c.repo_name)
130 file_node = c.repo.get_changeset(revision).get_node(f_path)
128 file_node = c.repo.get_changeset(revision).get_node(f_path)
131 response.content_type = 'text/plain'
129 response.content_type = 'text/plain'
132
130
133 return file_node.content
131 return file_node.content
134
132
135 def annotate(self, repo_name, revision, f_path):
133 def annotate(self, repo_name, revision, f_path):
136 hg_model = ScmModel()
134 c.repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
137 c.repo = hg_model.get_repo(c.repo_name)
138
135
139 try:
136 try:
140 c.cs = c.repo.get_changeset(revision)
137 c.cs = c.repo.get_changeset(revision)
@@ -163,9 +160,9 b' class FilesController(BaseController):'
163 ext = ext_data[1]
160 ext = ext_data[1]
164
161
165 try:
162 try:
166 repo = ScmModel().get_repo(repo_name)
163 repo, dbrepo = ScmModel().get(repo_name)
167
164
168 if repo.dbrepo.enable_downloads is False:
165 if dbrepo.enable_downloads is False:
169 return _('downloads disabled')
166 return _('downloads disabled')
170
167
171 cs = repo.get_changeset(revision)
168 cs = repo.get_changeset(revision)
@@ -185,13 +182,12 b' class FilesController(BaseController):'
185
182
186
183
187 def diff(self, repo_name, f_path):
184 def diff(self, repo_name, f_path):
188 hg_model = ScmModel()
189 diff1 = request.GET.get('diff1')
185 diff1 = request.GET.get('diff1')
190 diff2 = request.GET.get('diff2')
186 diff2 = request.GET.get('diff2')
191 c.action = request.GET.get('diff')
187 c.action = request.GET.get('diff')
192 c.no_changes = diff1 == diff2
188 c.no_changes = diff1 == diff2
193 c.f_path = f_path
189 c.f_path = f_path
194 c.repo = hg_model.get_repo(c.repo_name)
190 c.repo, dbrepo = ScmModel().get(c.repo_name, retval='repo')
195
191
196 try:
192 try:
197 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
193 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
@@ -47,7 +47,7 b' class ShortlogController(BaseController)'
47
47
48 def index(self):
48 def index(self):
49 p = int(request.params.get('page', 1))
49 p = int(request.params.get('page', 1))
50 repo = ScmModel().get_repo(c.repo_name)
50 repo, dbrepo = ScmModel().get(c.repo_name, 'repo')
51 c.repo_changesets = Page(repo, page=p, items_per_page=20)
51 c.repo_changesets = Page(repo, page=p, items_per_page=20)
52 c.shortlog_data = render('shortlog/shortlog_data.html')
52 c.shortlog_data = render('shortlog/shortlog_data.html')
53 if request.params.get('partial'):
53 if request.params.get('partial'):
@@ -64,13 +64,14 b' class SummaryController(BaseController):'
64
64
65 def index(self):
65 def index(self):
66 scm_model = ScmModel()
66 scm_model = ScmModel()
67 c.repo_info = scm_model.get_repo(c.repo_name)
67 c.repo, dbrepo = scm_model.get(c.repo_name)
68 c.dbrepo = dbrepo
68 c.following = scm_model.is_following_repo(c.repo_name,
69 c.following = scm_model.is_following_repo(c.repo_name,
69 c.rhodecode_user.user_id)
70 c.rhodecode_user.user_id)
70 def url_generator(**kw):
71 def url_generator(**kw):
71 return url('shortlog_home', repo_name=c.repo_name, **kw)
72 return url('shortlog_home', repo_name=c.repo_name, **kw)
72
73
73 c.repo_changesets = Page(c.repo_info, page=1, items_per_page=10,
74 c.repo_changesets = Page(c.repo, page=1, items_per_page=10,
74 url=url_generator)
75 url=url_generator)
75
76
76 e = request.environ
77 e = request.environ
@@ -92,16 +93,16 b' class SummaryController(BaseController):'
92 'repo_name':c.repo_name, }
93 'repo_name':c.repo_name, }
93 c.clone_repo_url = uri
94 c.clone_repo_url = uri
94 c.repo_tags = OrderedDict()
95 c.repo_tags = OrderedDict()
95 for name, hash in c.repo_info.tags.items()[:10]:
96 for name, hash in c.repo.tags.items()[:10]:
96 try:
97 try:
97 c.repo_tags[name] = c.repo_info.get_changeset(hash)
98 c.repo_tags[name] = c.repo.get_changeset(hash)
98 except ChangesetError:
99 except ChangesetError:
99 c.repo_tags[name] = EmptyChangeset(hash)
100 c.repo_tags[name] = EmptyChangeset(hash)
100
101
101 c.repo_branches = OrderedDict()
102 c.repo_branches = OrderedDict()
102 for name, hash in c.repo_info.branches.items()[:10]:
103 for name, hash in c.repo.branches.items()[:10]:
103 try:
104 try:
104 c.repo_branches[name] = c.repo_info.get_changeset(hash)
105 c.repo_branches[name] = c.repo.get_changeset(hash)
105 except ChangesetError:
106 except ChangesetError:
106 c.repo_branches[name] = EmptyChangeset(hash)
107 c.repo_branches[name] = EmptyChangeset(hash)
107
108
@@ -113,21 +114,21 b' class SummaryController(BaseController):'
113 ts_min_y = mktime(td_1y.timetuple())
114 ts_min_y = mktime(td_1y.timetuple())
114 ts_max_y = mktime(td.timetuple())
115 ts_max_y = mktime(td.timetuple())
115
116
116 if c.repo_info.dbrepo.enable_statistics:
117 if dbrepo.enable_statistics:
117 c.no_data_msg = _('No data loaded yet')
118 c.no_data_msg = _('No data loaded yet')
118 run_task(get_commits_stats, c.repo_info.name, ts_min_y, ts_max_y)
119 run_task(get_commits_stats, c.repo.name, ts_min_y, ts_max_y)
119 else:
120 else:
120 c.no_data_msg = _('Statistics update are disabled for this repository')
121 c.no_data_msg = _('Statistics update are disabled for this repository')
121 c.ts_min = ts_min_m
122 c.ts_min = ts_min_m
122 c.ts_max = ts_max_y
123 c.ts_max = ts_max_y
123
124
124 stats = self.sa.query(Statistics)\
125 stats = self.sa.query(Statistics)\
125 .filter(Statistics.repository == c.repo_info.dbrepo)\
126 .filter(Statistics.repository == dbrepo)\
126 .scalar()
127 .scalar()
127
128
128
129
129 if stats and stats.languages:
130 if stats and stats.languages:
130 c.no_data = False is c.repo_info.dbrepo.enable_statistics
131 c.no_data = False is dbrepo.enable_statistics
131 lang_stats = json.loads(stats.languages)
132 lang_stats = json.loads(stats.languages)
132 c.commit_data = stats.commit_activity
133 c.commit_data = stats.commit_activity
133 c.overview_data = stats.commit_activity_combined
134 c.overview_data = stats.commit_activity_combined
@@ -142,9 +143,9 b' class SummaryController(BaseController):'
142 c.trending_languages = json.dumps({})
143 c.trending_languages = json.dumps({})
143 c.no_data = True
144 c.no_data = True
144
145
145 c.enable_downloads = c.repo_info.dbrepo.enable_downloads
146 c.enable_downloads = dbrepo.enable_downloads
146 if c.enable_downloads:
147 if c.enable_downloads:
147 c.download_options = self._get_download_links(c.repo_info)
148 c.download_options = self._get_download_links(c.repo)
148
149
149 return render('summary/summary.html')
150 return render('summary/summary.html')
150
151
@@ -44,8 +44,7 b' class TagsController(BaseController):'
44 super(TagsController, self).__before__()
44 super(TagsController, self).__before__()
45
45
46 def index(self):
46 def index(self):
47 hg_model = ScmModel()
47 c.repo_info, dbrepo = ScmModel().get(c.repo_name, retval='repo')
48 c.repo_info = hg_model.get_repo(c.repo_name)
49 c.repo_tags = OrderedDict()
48 c.repo_tags = OrderedDict()
50 for name, hash_ in c.repo_info.tags.items():
49 for name, hash_ in c.repo_info.tags.items():
51 c.repo_tags[name] = c.repo_info.get_changeset(hash_)
50 c.repo_tags[name] = c.repo_info.get_changeset(hash_)
@@ -28,12 +28,12 b' class BaseController(WSGIController):'
28 #c.unread_journal = scm_model.get_unread_journal()
28 #c.unread_journal = scm_model.get_unread_journal()
29
29
30 if c.repo_name:
30 if c.repo_name:
31 cached_repo = scm_model.get(c.repo_name)
31 repo, dbrepo = scm_model.get(c.repo_name)
32 if cached_repo:
32 if repo:
33 c.repository_tags = cached_repo.tags
33 c.repository_tags = repo.tags
34 c.repository_branches = cached_repo.branches
34 c.repository_branches = repo.branches
35 c.repository_followers = scm_model.get_followers(cached_repo.dbrepo.repo_id)
35 c.repository_followers = scm_model.get_followers(dbrepo.repo_id)
36 c.repository_forks = scm_model.get_forks(cached_repo.dbrepo.repo_id)
36 c.repository_forks = scm_model.get_forks(dbrepo.repo_id)
37 else:
37 else:
38 c.repository_tags = {}
38 c.repository_tags = {}
39 c.repository_branches = {}
39 c.repository_branches = {}
@@ -483,12 +483,12 b' def action_parser(user_log):'
483 def get_fork_name():
483 def get_fork_name():
484 from rhodecode.model.scm import ScmModel
484 from rhodecode.model.scm import ScmModel
485 repo_name = action_params
485 repo_name = action_params
486 repo = ScmModel().get(repo_name)
486 repo, dbrepo = ScmModel().get(repo_name)
487 if repo is None:
487 if repo is None:
488 return repo_name
488 return repo_name
489 return link_to(action_params, url('summary_home',
489 return link_to(action_params, url('summary_home',
490 repo_name=repo.name,),
490 repo_name=repo.name,),
491 title=repo.dbrepo.description)
491 title=dbrepo.description)
492
492
493 map = {'user_deleted_repo':(_('User [deleted] repository'), None),
493 map = {'user_deleted_repo':(_('User [deleted] repository'), None),
494 'user_created_repo':(_('User [created] repository'), None),
494 'user_created_repo':(_('User [created] repository'), None),
@@ -87,7 +87,7 b' class RepoModel(BaseModel):'
87 if cache:
87 if cache:
88 repo = repo.options(FromCache("sql_cache_long",
88 repo = repo.options(FromCache("sql_cache_long",
89 "get_repo_full_%s" % repo_name))
89 "get_repo_full_%s" % repo_name))
90 if invalidate:
90 if invalidate and cache:
91 repo.invalidate()
91 repo.invalidate()
92
92
93 return repo.scalar()
93 return repo.scalar()
@@ -31,8 +31,6 b' import logging'
31
31
32 from mercurial import ui
32 from mercurial import ui
33
33
34 from sqlalchemy.orm import joinedload
35 from sqlalchemy.orm.session import make_transient
36 from sqlalchemy.exc import DatabaseError
34 from sqlalchemy.exc import DatabaseError
37
35
38 from beaker.cache import cache_region, region_invalidate
36 from beaker.cache import cache_region, region_invalidate
@@ -45,9 +43,11 b' from vcs.utils.lazy import LazyProperty'
45 from rhodecode import BACKENDS
43 from rhodecode import BACKENDS
46 from rhodecode.lib import helpers as h
44 from rhodecode.lib import helpers as h
47 from rhodecode.lib.auth import HasRepoPermissionAny
45 from rhodecode.lib.auth import HasRepoPermissionAny
48 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, action_logger
46 from rhodecode.lib.utils import get_repos as get_filesystem_repos, make_ui, \
47 action_logger
49 from rhodecode.model import BaseModel
48 from rhodecode.model import BaseModel
50 from rhodecode.model.user import UserModel
49 from rhodecode.model.user import UserModel
50 from rhodecode.model.repo import RepoModel
51 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
51 from rhodecode.model.db import Repository, RhodeCodeUi, CacheInvalidation, \
52 UserFollowing, UserLog
52 UserFollowing, UserLog
53 from rhodecode.model.caching_query import FromCache
53 from rhodecode.model.caching_query import FromCache
@@ -82,18 +82,19 b' class ScmModel(BaseModel):'
82
82
83 return q.ui_value
83 return q.ui_value
84
84
85 def repo_scan(self, repos_path, baseui):
85 def repo_scan(self, repos_path=None):
86 """Listing of repositories in given path. This path should not be a
86 """Listing of repositories in given path. This path should not be a
87 repository itself. Return a dictionary of repository objects
87 repository itself. Return a dictionary of repository objects
88
88
89 :param repos_path: path to directory containing repositories
89 :param repos_path: path to directory containing repositories
90 :param baseui: baseui instance to instantiate MercurialRepostitory with
91 """
90 """
92
91
93 log.info('scanning for repositories in %s', repos_path)
92 log.info('scanning for repositories in %s', repos_path)
94
93
95 if not isinstance(baseui, ui.ui):
94 if repos_path is None:
96 baseui = make_ui('db')
95 repos_path = self.repos_path
96
97 baseui = make_ui('db')
97 repos_list = {}
98 repos_list = {}
98
99
99 for name, path in get_filesystem_repos(repos_path, recursive=True):
100 for name, path in get_filesystem_repos(repos_path, recursive=True):
@@ -134,7 +135,7 b' class ScmModel(BaseModel):'
134
135
135 for r in all_repos:
136 for r in all_repos:
136
137
137 repo = self.get(r.repo_name, invalidation_list)
138 repo, dbrepo = self.get(r.repo_name, invalidation_list)
138
139
139 if repo is not None:
140 if repo is not None:
140 last_change = repo.last_change
141 last_change = repo.last_change
@@ -143,33 +144,34 b' class ScmModel(BaseModel):'
143 tmp_d = {}
144 tmp_d = {}
144 tmp_d['name'] = r.repo_name
145 tmp_d['name'] = r.repo_name
145 tmp_d['name_sort'] = tmp_d['name'].lower()
146 tmp_d['name_sort'] = tmp_d['name'].lower()
146 tmp_d['description'] = repo.dbrepo.description
147 tmp_d['description'] = dbrepo.description
147 tmp_d['description_sort'] = tmp_d['description']
148 tmp_d['description_sort'] = tmp_d['description']
148 tmp_d['last_change'] = last_change
149 tmp_d['last_change'] = last_change
149 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
150 tmp_d['last_change_sort'] = time.mktime(last_change.timetuple())
150 tmp_d['tip'] = tip.raw_id
151 tmp_d['tip'] = tip.raw_id
151 tmp_d['tip_sort'] = tip.revision
152 tmp_d['tip_sort'] = tip.revision
152 tmp_d['rev'] = tip.revision
153 tmp_d['rev'] = tip.revision
153 tmp_d['contact'] = repo.dbrepo.user.full_contact
154 tmp_d['contact'] = dbrepo.user.full_contact
154 tmp_d['contact_sort'] = tmp_d['contact']
155 tmp_d['contact_sort'] = tmp_d['contact']
155 tmp_d['owner_sort'] = tmp_d['contact']
156 tmp_d['owner_sort'] = tmp_d['contact']
156 tmp_d['repo_archives'] = list(repo._get_archives())
157 tmp_d['repo_archives'] = list(repo._get_archives())
157 tmp_d['last_msg'] = tip.message
158 tmp_d['last_msg'] = tip.message
158 tmp_d['repo'] = repo
159 tmp_d['repo'] = repo
160 tmp_d['dbrepo'] = dbrepo
159 yield tmp_d
161 yield tmp_d
160
162
161 def get_repo(self, repo_name):
163 def get(self, repo_name, invalidation_list=None, retval='all'):
162 return self.get(repo_name)
164 """Returns a tuple of Repository,DbRepository,
163
165 Get's repository from given name, creates BackendInstance and
164 def get(self, repo_name, invalidation_list=None):
165 """Get's repository from given name, creates BackendInstance and
166 propagates it's data from database with all additional information
166 propagates it's data from database with all additional information
167
167
168 :param repo_name:
168 :param repo_name:
169 :param invalidation_list: if a invalidation list is given the get
169 :param invalidation_list: if a invalidation list is given the get
170 method should not manually check if this repository needs
170 method should not manually check if this repository needs
171 invalidation and just invalidate the repositories in list
171 invalidation and just invalidate the repositories in list
172
172 :param retval: string specifing what to return one of 'repo','dbrepo',
173 'all'if repo or dbrepo is given it'll just lazy load chosen type
174 and return None as the second
173 """
175 """
174 if not HasRepoPermissionAny('repository.read', 'repository.write',
176 if not HasRepoPermissionAny('repository.read', 'repository.write',
175 'repository.admin')(repo_name, 'get repo check'):
177 'repository.admin')(repo_name, 'get repo check'):
@@ -189,58 +191,45 b' class ScmModel(BaseModel):'
189 backend = get_backend(alias)
191 backend = get_backend(alias)
190 except VCSError:
192 except VCSError:
191 log.error(traceback.format_exc())
193 log.error(traceback.format_exc())
192 log.error('Perhaps this repository is in db and not in filesystem'
194 log.error('Perhaps this repository is in db and not in '
193 'run rescan repositories with "destroy old data "'
195 'filesystem run rescan repositories with '
194 'option from admin panel')
196 '"destroy old data " option from admin panel')
195 return
197 return
196
198
197 if alias == 'hg':
199 if alias == 'hg':
198 from pylons import app_globals as g
200 repo = backend(repo_path, create=False, baseui=make_ui('db'))
199 repo = backend(repo_path, create=False, baseui=g.baseui)
200 #skip hidden web repository
201 #skip hidden web repository
201 if repo._get_hidden():
202 if repo._get_hidden():
202 return
203 return
203 else:
204 else:
204 repo = backend(repo_path, create=False)
205 repo = backend(repo_path, create=False)
205
206
206 dbrepo = self.sa.query(Repository)\
207 .options(joinedload(Repository.fork))\
208 .options(joinedload(Repository.user))\
209 .filter(Repository.repo_name == repo_name)\
210 .scalar()
211
212 self.sa.expunge_all()
213 log.debug('making transient %s', dbrepo)
214 make_transient(dbrepo)
215
216 for attr in ['user', 'forks', 'followers', 'group', 'repo_to_perm',
217 'users_group_to_perm', 'stats', 'logs']:
218 attr = getattr(dbrepo, attr, False)
219 if attr:
220 if isinstance(attr, list):
221 for a in attr:
222 log.debug('making transient %s', a)
223 make_transient(a)
224 else:
225 log.debug('making transient %s', attr)
226 make_transient(attr)
227
228 repo.dbrepo = dbrepo
229 return repo
207 return repo
230
208
231 pre_invalidate = True
209 pre_invalidate = True
210 dbinvalidate = False
211
232 if invalidation_list is not None:
212 if invalidation_list is not None:
233 pre_invalidate = repo_name in invalidation_list
213 pre_invalidate = repo_name in invalidation_list
234
214
235 if pre_invalidate:
215 if pre_invalidate:
216 #this returns object to invalidate
236 invalidate = self._should_invalidate(repo_name)
217 invalidate = self._should_invalidate(repo_name)
237
238 if invalidate:
218 if invalidate:
239 log.info('invalidating cache for repository %s', repo_name)
219 log.info('invalidating cache for repository %s', repo_name)
240 region_invalidate(_get_repo, None, repo_name)
220 #region_invalidate(_get_repo, None, repo_name)
241 self._mark_invalidated(invalidate)
221 self._mark_invalidated(invalidate)
222 dbinvalidate = True
242
223
243 return _get_repo(repo_name)
224 r, dbr = None, None
225 if retval == 'repo' or 'all':
226 r = _get_repo(repo_name)
227 if retval == 'dbrepo' or 'all':
228 dbr = RepoModel(self.sa).get_full(repo_name, cache=True,
229 invalidate=dbinvalidate)
230
231
232 return r, dbr
244
233
245
234
246
235
@@ -370,8 +359,6 b' class ScmModel(BaseModel):'
370 """
359 """
371
360
372 ret = self.sa.query(CacheInvalidation)\
361 ret = self.sa.query(CacheInvalidation)\
373 .options(FromCache('sql_cache_short',
374 'get_invalidation_%s' % repo_name))\
375 .filter(CacheInvalidation.cache_key == repo_name)\
362 .filter(CacheInvalidation.cache_key == repo_name)\
376 .filter(CacheInvalidation.cache_active == False)\
363 .filter(CacheInvalidation.cache_active == False)\
377 .scalar()
364 .scalar()
@@ -379,7 +366,8 b' class ScmModel(BaseModel):'
379 return ret
366 return ret
380
367
381 def _mark_invalidated(self, cache_key):
368 def _mark_invalidated(self, cache_key):
382 """ Marks all occurences of cache to invaldation as already invalidated
369 """ Marks all occurrences of cache to invalidation as already
370 invalidated
383
371
384 :param cache_key:
372 :param cache_key:
385 """
373 """
@@ -38,26 +38,26 b''
38 <tr class="parity${cnt%2}">
38 <tr class="parity${cnt%2}">
39 <td>
39 <td>
40 ## TYPE OF REPO
40 ## TYPE OF REPO
41 %if repo['repo'].dbrepo.repo_type =='hg':
41 %if repo['dbrepo'].repo_type =='hg':
42 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
42 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
43 %elif repo['repo'].dbrepo.repo_type =='git':
43 %elif repo['dbrepo'].repo_type =='git':
44 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
44 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
45 %else:
45 %else:
46
46
47 %endif
47 %endif
48
48
49 ## PRIVATE/PUBLIC REPO
49 ## PRIVATE/PUBLIC REPO
50 %if repo['repo'].dbrepo.private:
50 %if repo['dbrepo'].private:
51 <img alt="${_('private')}" src="/images/icons/lock.png"/>
51 <img alt="${_('private')}" src="/images/icons/lock.png"/>
52 %else:
52 %else:
53 <img alt="${_('public')}" src="/images/icons/lock_open.png"/>
53 <img alt="${_('public')}" src="/images/icons/lock_open.png"/>
54 %endif
54 %endif
55 ${h.link_to(repo['name'],h.url('edit_repo',repo_name=repo['name']))}
55 ${h.link_to(repo['name'],h.url('edit_repo',repo_name=repo['name']))}
56
56
57 %if repo['repo'].dbrepo.fork:
57 %if repo['dbrepo'].fork:
58 <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
58 <a href="${h.url('summary_home',repo_name=repo['dbrepo'].fork.repo_name)}">
59 <img class="icon" alt="${_('public')}"
59 <img class="icon" alt="${_('public')}"
60 title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}"
60 title="${_('Fork of')} ${repo['dbrepo'].fork.repo_name}"
61 src="/images/icons/arrow_divide.png"/></a>
61 src="/images/icons/arrow_divide.png"/></a>
62 %endif
62 %endif
63 </td>
63 </td>
@@ -119,24 +119,24 b''
119 %for repo in c.user_repos:
119 %for repo in c.user_repos:
120 <tr>
120 <tr>
121 <td>
121 <td>
122 %if repo['repo'].dbrepo.repo_type =='hg':
122 %if repo['dbrepo'].repo_type =='hg':
123 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
123 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
124 %elif repo['repo'].dbrepo.repo_type =='git':
124 %elif repo['dbrepo'].repo_type =='git':
125 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
125 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
126 %else:
126 %else:
127
127
128 %endif
128 %endif
129 %if repo['repo'].dbrepo.private:
129 %if repo['dbrepo'].private:
130 <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
130 <img class="icon" alt="${_('private')}" src="/images/icons/lock.png"/>
131 %else:
131 %else:
132 <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
132 <img class="icon" alt="${_('public')}" src="/images/icons/lock_open.png"/>
133 %endif
133 %endif
134
134
135 ${h.link_to(repo['repo'].name, h.url('summary_home',repo_name=repo['repo'].name),class_="repo_name")}
135 ${h.link_to(repo['repo'].name, h.url('summary_home',repo_name=repo['repo'].name),class_="repo_name")}
136 %if repo['repo'].dbrepo.fork:
136 %if repo['dbrepo'].fork:
137 <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
137 <a href="${h.url('summary_home',repo_name=repo['dbrepo'].fork.repo_name)}">
138 <img class="icon" alt="${_('public')}"
138 <img class="icon" alt="${_('public')}"
139 title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}"
139 title="${_('Fork of')} ${repo['dbrepo'].fork.repo_name}"
140 src="/images/icons/arrow_divide.png"/></a>
140 src="/images/icons/arrow_divide.png"/></a>
141 %endif
141 %endif
142 </td>
142 </td>
@@ -142,10 +142,10 b''
142 <ul class="repo_switcher">
142 <ul class="repo_switcher">
143 %for repo in c.cached_repo_list:
143 %for repo in c.cached_repo_list:
144
144
145 %if repo['repo'].dbrepo.private:
145 %if repo['dbrepo'].private:
146 <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
146 <li><img src="/images/icons/lock.png" alt="${_('Private repository')}" class="repo_switcher_type"/>${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['dbrepo'].repo_type)}</li>
147 %else:
147 %else:
148 <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['repo'].dbrepo.repo_type)}</li>
148 <li><img src="/images/icons/lock_open.png" alt="${_('Public repository')}" class="repo_switcher_type" />${h.link_to(repo['repo'].name,h.url('summary_home',repo_name=repo['repo'].name),class_="%s" % repo['dbrepo'].repo_type)}</li>
149 %endif
149 %endif
150 %endfor
150 %endfor
151 </ul>
151 </ul>
@@ -60,16 +60,16 b''
60 <td>
60 <td>
61 <div style="white-space: nowrap">
61 <div style="white-space: nowrap">
62 ## TYPE OF REPO
62 ## TYPE OF REPO
63 %if repo['repo'].dbrepo.repo_type =='hg':
63 %if repo['dbrepo'].repo_type =='hg':
64 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
64 <img class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
65 %elif repo['repo'].dbrepo.repo_type =='git':
65 %elif repo['dbrepo'].repo_type =='git':
66 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
66 <img class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
67 %else:
67 %else:
68
68
69 %endif
69 %endif
70
70
71 ##PRIVATE/PUBLIC
71 ##PRIVATE/PUBLIC
72 %if repo['repo'].dbrepo.private:
72 %if repo['dbrepo'].private:
73 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
73 <img class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
74 %else:
74 %else:
75 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
75 <img class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
@@ -78,10 +78,10 b''
78 ##NAME
78 ##NAME
79 ${h.link_to(repo['name'],
79 ${h.link_to(repo['name'],
80 h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
80 h.url('summary_home',repo_name=repo['name']),class_="repo_name")}
81 %if repo['repo'].dbrepo.fork:
81 %if repo['dbrepo'].fork:
82 <a href="${h.url('summary_home',repo_name=repo['repo'].dbrepo.fork.repo_name)}">
82 <a href="${h.url('summary_home',repo_name=repo['dbrepo'].fork.repo_name)}">
83 <img class="icon" alt="${_('fork')}"
83 <img class="icon" alt="${_('fork')}"
84 title="${_('Fork of')} ${repo['repo'].dbrepo.fork.repo_name}"
84 title="${_('Fork of')} ${repo['dbrepo'].fork.repo_name}"
85 src="/images/icons/arrow_divide.png"/></a>
85 src="/images/icons/arrow_divide.png"/></a>
86 %endif
86 %endif
87 </div>
87 </div>
@@ -31,38 +31,38 b''
31 <label>${_('Name')}:</label>
31 <label>${_('Name')}:</label>
32 </div>
32 </div>
33 <div class="input-short">
33 <div class="input-short">
34 %if c.repo_info.dbrepo.repo_type =='hg':
34 %if c.dbrepo.repo_type =='hg':
35 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
35 <img style="margin-bottom:2px" class="icon" title="${_('Mercurial repository')}" alt="${_('Mercurial repository')}" src="/images/icons/hgicon.png"/>
36 %endif
36 %endif
37 %if c.repo_info.dbrepo.repo_type =='git':
37 %if c.dbrepo.repo_type =='git':
38 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
38 <img style="margin-bottom:2px" class="icon" title="${_('Git repository')}" alt="${_('Git repository')}" src="/images/icons/giticon.png"/>
39 %endif
39 %endif
40
40
41 %if c.repo_info.dbrepo.private:
41 %if c.dbrepo.private:
42 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
42 <img style="margin-bottom:2px" class="icon" title="${_('private repository')}" alt="${_('private repository')}" src="/images/icons/lock.png"/>
43 %else:
43 %else:
44 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
44 <img style="margin-bottom:2px" class="icon" title="${_('public repository')}" alt="${_('public repository')}" src="/images/icons/lock_open.png"/>
45 %endif
45 %endif
46 <span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;">${c.repo_info.name}</span>
46 <span style="font-size: 1.6em;font-weight: bold;vertical-align: baseline;">${c.repo.name}</span>
47 %if c.rhodecode_user.username != 'default':
47 %if c.rhodecode_user.username != 'default':
48 %if c.following:
48 %if c.following:
49 <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
49 <span id="follow_toggle" class="following" title="${_('Stop following this repository')}"
50 onclick="javascript:toggleFollowingRepo(this,${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
50 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
51 </span>
51 </span>
52 %else:
52 %else:
53 <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
53 <span id="follow_toggle" class="follow" title="${_('Start following this repository')}"
54 onclick="javascript:toggleFollowingRepo(this,${c.repo_info.dbrepo.repo_id},'${str(h.get_token())}')">
54 onclick="javascript:toggleFollowingRepo(this,${c.dbrepo.repo_id},'${str(h.get_token())}')">
55 </span>
55 </span>
56 %endif
56 %endif
57 %endif:
57 %endif:
58 <br/>
58 <br/>
59 %if c.repo_info.dbrepo.fork:
59 %if c.dbrepo.fork:
60 <span style="margin-top:5px">
60 <span style="margin-top:5px">
61 <a href="${h.url('summary_home',repo_name=c.repo_info.dbrepo.fork.repo_name)}">
61 <a href="${h.url('summary_home',repo_name=c.dbrepo.fork.repo_name)}">
62 <img class="icon" alt="${_('public')}"
62 <img class="icon" alt="${_('public')}"
63 title="${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}"
63 title="${_('Fork of')} ${c.dbrepo.fork.repo_name}"
64 src="/images/icons/arrow_divide.png"/>
64 src="/images/icons/arrow_divide.png"/>
65 ${_('Fork of')} ${c.repo_info.dbrepo.fork.repo_name}
65 ${_('Fork of')} ${c.dbrepo.fork.repo_name}
66 </a>
66 </a>
67 </span>
67 </span>
68 %endif
68 %endif
@@ -75,7 +75,7 b''
75 <label>${_('Description')}:</label>
75 <label>${_('Description')}:</label>
76 </div>
76 </div>
77 <div class="input-short">
77 <div class="input-short">
78 ${c.repo_info.dbrepo.description}
78 ${c.dbrepo.description}
79 </div>
79 </div>
80 </div>
80 </div>
81
81
@@ -86,11 +86,11 b''
86 </div>
86 </div>
87 <div class="input-short">
87 <div class="input-short">
88 <div class="gravatar">
88 <div class="gravatar">
89 <img alt="gravatar" src="${h.gravatar_url(c.repo_info.dbrepo.user.email)}"/>
89 <img alt="gravatar" src="${h.gravatar_url(c.dbrepo.user.email)}"/>
90 </div>
90 </div>
91 ${_('Username')}: ${c.repo_info.dbrepo.user.username}<br/>
91 ${_('Username')}: ${c.dbrepo.user.username}<br/>
92 ${_('Name')}: ${c.repo_info.dbrepo.user.name} ${c.repo_info.dbrepo.user.lastname}<br/>
92 ${_('Name')}: ${c.dbrepo.user.name} ${c.dbrepo.user.lastname}<br/>
93 ${_('Email')}: <a href="mailto:${c.repo_info.dbrepo.user.email}">${c.repo_info.dbrepo.user.email}</a>
93 ${_('Email')}: <a href="mailto:${c.dbrepo.user.email}">${c.dbrepo.user.email}</a>
94 </div>
94 </div>
95 </div>
95 </div>
96
96
@@ -99,8 +99,8 b''
99 <label>${_('Last change')}:</label>
99 <label>${_('Last change')}:</label>
100 </div>
100 </div>
101 <div class="input-short">
101 <div class="input-short">
102 ${h.age(c.repo_info.last_change)} - ${c.repo_info.last_change}
102 ${h.age(c.repo.last_change)} - ${c.repo.last_change}
103 ${_('by')} ${h.get_changeset_safe(c.repo_info,'tip').author}
103 ${_('by')} ${h.get_changeset_safe(c.repo,'tip').author}
104
104
105 </div>
105 </div>
106 </div>
106 </div>
@@ -128,7 +128,7 b''
128 <label>${_('Download')}:</label>
128 <label>${_('Download')}:</label>
129 </div>
129 </div>
130 <div class="input-short">
130 <div class="input-short">
131 %if len(c.repo_info.revisions) == 0:
131 %if len(c.repo.revisions) == 0:
132 ${_('There are no downloads yet')}
132 ${_('There are no downloads yet')}
133 %elif c.enable_downloads is False:
133 %elif c.enable_downloads is False:
134 ${_('Downloads are disabled for this repository')}
134 ${_('Downloads are disabled for this repository')}
@@ -136,14 +136,14 b''
136 [${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
136 [${h.link_to(_('enable'),h.url('edit_repo',repo_name=c.repo_name))}]
137 %endif
137 %endif
138 %else:
138 %else:
139 ${h.select('download_options',c.repo_info.get_changeset().raw_id,c.download_options)}
139 ${h.select('download_options',c.repo.get_changeset().raw_id,c.download_options)}
140 %for cnt,archive in enumerate(c.repo_info._get_archives()):
140 %for cnt,archive in enumerate(c.repo._get_archives()):
141 %if cnt >=1:
141 %if cnt >=1:
142 |
142 |
143 %endif
143 %endif
144 <span class="tooltip" title="${_('Download %s as %s') %('tip',archive['type'])}"
144 <span class="tooltip" title="${_('Download %s as %s') %('tip',archive['type'])}"
145 id="${archive['type']+'_link'}">${h.link_to(archive['type'],
145 id="${archive['type']+'_link'}">${h.link_to(archive['type'],
146 h.url('files_archive_home',repo_name=c.repo_info.name,
146 h.url('files_archive_home',repo_name=c.repo.name,
147 fname='tip'+archive['extension']),class_="archive_icon")}</span>
147 fname='tip'+archive['extension']),class_="archive_icon")}</span>
148 %endfor
148 %endfor
149 %endif
149 %endif
@@ -155,8 +155,8 b''
155 <label>${_('Feeds')}:</label>
155 <label>${_('Feeds')}:</label>
156 </div>
156 </div>
157 <div class="input-short">
157 <div class="input-short">
158 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.repo_info.name),class_='rss_icon')}
158 ${h.link_to(_('RSS'),h.url('rss_feed_home',repo_name=c.repo.name),class_='rss_icon')}
159 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.repo_info.name),class_='atom_icon')}
159 ${h.link_to(_('Atom'),h.url('atom_feed_home',repo_name=c.repo.name),class_='atom_icon')}
160 </div>
160 </div>
161 </div>
161 </div>
162 </div>
162 </div>
@@ -250,9 +250,9 b''
250 YUE.on('download_options','change',function(e){
250 YUE.on('download_options','change',function(e){
251 var new_cs = e.target.options[e.target.selectedIndex];
251 var new_cs = e.target.options[e.target.selectedIndex];
252 var tmpl_links = {}
252 var tmpl_links = {}
253 %for cnt,archive in enumerate(c.repo_info._get_archives()):
253 %for cnt,archive in enumerate(c.repo._get_archives()):
254 tmpl_links['${archive['type']}'] = '${h.link_to(archive['type'],
254 tmpl_links['${archive['type']}'] = '${h.link_to(archive['type'],
255 h.url('files_archive_home',repo_name=c.repo_info.name,
255 h.url('files_archive_home',repo_name=c.repo.name,
256 fname='__CS__'+archive['extension']),class_="archive_icon")}';
256 fname='__CS__'+archive['extension']),class_="archive_icon")}';
257 %endfor
257 %endfor
258
258
General Comments 0
You need to be logged in to leave comments. Login now