diff --git a/trac/versioncontrol/api.py b/trac/versioncontrol/api.py
|
a
|
b
|
|
| 27 | 27 | from trac.config import ListOption, Option |
| 28 | 28 | from trac.core import * |
| 29 | 29 | from trac.perm import PermissionError |
| 30 | | from trac.resource import IResourceManager, ResourceSystem, ResourceNotFound |
| | 30 | from trac.resource import IResourceManager, Resource, ResourceSystem, \ |
| | 31 | ResourceNotFound |
| 31 | 32 | from trac.util.text import printout, to_unicode |
| 32 | 33 | from trac.util.translation import _ |
| 33 | 34 | from trac.web.api import IRequestFilter |
| 34 | 35 | |
| 35 | 36 | |
| | 37 | def make_repo_resource(reponame): |
| | 38 | """Create a repository resource for the given reponame, or return None |
| | 39 | for the default repository. |
| | 40 | """ |
| | 41 | if reponame: |
| | 42 | return Resource('repository', reponame) |
| | 43 | |
| | 44 | |
| | 45 | def split_vc_resource(resource): |
| | 46 | """Split a versioncontrol resource into reponame and path.""" |
| | 47 | if resource.parent and resource.parent.realm == 'repository': |
| | 48 | return (resource.parent.id, resource.id) |
| | 49 | return ('', resource.id) |
| | 50 | |
| | 51 | |
| 36 | 52 | class IRepositoryConnector(Interface): |
| 37 | 53 | """Provide support for a specific version control system.""" |
| 38 | 54 | |
| … |
… |
|
| 343 | 359 | |
| 344 | 360 | # IResourceManager methods |
| 345 | 361 | |
| 346 | | # Note: with multiple repository support, the repository name becomes |
| 347 | | # part of the 'id', which becomes a `(reponame, rev or path)` pair. |
| 348 | | |
| 349 | 362 | def get_resource_realms(self): |
| 350 | 363 | yield 'changeset' |
| 351 | 364 | yield 'source' |
| | 365 | yield 'repository' |
| 352 | 366 | |
| 353 | 367 | def get_resource_description(self, resource, format=None, **kwargs): |
| 354 | | reponame, id = resource.id |
| 355 | 368 | if resource.realm == 'changeset': |
| | 369 | (reponame, id) = split_vc_resource(resource) |
| 356 | 370 | if reponame: |
| 357 | 371 | return _("Changeset %(rev)s in %(repo)s", rev=id, repo=reponame) |
| 358 | 372 | else: |
| 359 | 373 | return _("Changeset %(rev)s", rev=id) |
| 360 | 374 | elif resource.realm == 'source': |
| | 375 | (reponame, id) = split_vc_resource(resource) |
| 361 | 376 | version = in_repo = '' |
| 362 | 377 | if format == 'summary': |
| 363 | 378 | repos = resource.env.get_repository(reponame) |
| … |
… |
|
| 375 | 390 | if reponame: |
| 376 | 391 | in_repo = _(" in %(repo)s", repo=reponame) |
| 377 | 392 | return ''.join([kind, ' ', id, version, in_repo]) |
| | 393 | elif resource.realm == 'repository': |
| | 394 | return _("Repository %(repo)s", repo=resource.id) |
| 378 | 395 | |
| 379 | 396 | def get_resource_url(self, resource, href, **kwargs): |
| 380 | | if resource and resource.realm in ('source', 'changeset'): |
| 381 | | repos, id = resource.id |
| 382 | | if resource.realm == 'source': |
| 383 | | return href.source(repos, id) |
| 384 | | else: |
| 385 | | return href.changeset(id, repos) |
| | 397 | if resource.realm == 'changeset': |
| | 398 | (reponame, id) = split_vc_resource(resource) |
| | 399 | return href.changeset(id, reponame) |
| | 400 | elif resource.realm == 'source': |
| | 401 | (reponame, id) = split_vc_resource(resource) |
| | 402 | return href.source(reponame, id) |
| | 403 | elif resource.realm == 'repository': |
| | 404 | return href.source(resource.id) |
| 386 | 405 | |
| 387 | 406 | # IRepositoryProvider methods |
| 388 | 407 | |
| … |
… |
|
| 524 | 543 | """ |
| 525 | 544 | while context: |
| 526 | 545 | if context.resource.realm in ('source', 'changeset'): |
| 527 | | return context.resource.id[0] |
| | 546 | return split_vc_resource(context.resource)[0] |
| 528 | 547 | context = context.parent |
| 529 | 548 | |
| 530 | 549 | def get_all_repositories(self): |
diff --git a/trac/versioncontrol/svn_prop.py b/trac/versioncontrol/svn_prop.py
|
a
|
b
|
|
| 21 | 21 | from genshi.builder import tag |
| 22 | 22 | |
| 23 | 23 | from trac.core import * |
| 24 | | from trac.versioncontrol import NoSuchNode |
| | 24 | from trac.versioncontrol import NoSuchNode, split_vc_resource |
| 25 | 25 | from trac.versioncontrol.svn_fs import _path_within_scope |
| 26 | 26 | from trac.versioncontrol.web_ui.browser import IPropertyRenderer |
| 27 | 27 | from trac.versioncontrol.web_ui.changeset import IPropertyDiffRenderer |
| … |
… |
|
| 147 | 147 | has_eligible = name in ('svnmerge-integrated', 'svn:mergeinfo') |
| 148 | 148 | revs_label = (_('merged'), _('blocked'))[name.endswith('blocked')] |
| 149 | 149 | revs_cols = has_eligible and 2 or None |
| 150 | | (reponame, target_path) = context.resource.id |
| | 150 | (reponame, target_path) = split_vc_resource(context.resource) |
| 151 | 151 | repos = self.env.get_repository(reponame) |
| 152 | 152 | target_rev = context.resource.version |
| 153 | 153 | if has_eligible: |
| … |
… |
|
| 228 | 228 | |
| 229 | 229 | def _get_source_link(spath, context): |
| 230 | 230 | """Return a link to a merge source.""" |
| 231 | | reponame = context.resource.id[0] |
| | 231 | reponame = split_vc_resource(context.resource)[0] |
| 232 | 232 | return tag.a('/' + spath, title=_('View merge source'), |
| 233 | 233 | href=context.href.browser(reponame, spath, |
| 234 | 234 | rev=context.resource.version)) |
| … |
… |
|
| 238 | 238 | given, to the revision itself for a single revision, or a `<span>` |
| 239 | 239 | with "no revision" for none. |
| 240 | 240 | """ |
| 241 | | reponame = context.resource.id[0] |
| | 241 | reponame = split_vc_resource(context.resource)[0] |
| 242 | 242 | if not revs: |
| 243 | 243 | return tag.span(label, title=_('No revisions')) |
| 244 | 244 | elif ',' in revs or '-' in revs: |
| … |
… |
|
| 262 | 262 | # Build 3 columns table showing modifications on merge sources |
| 263 | 263 | # || source || added revs || removed revs || |
| 264 | 264 | # || source || removed || |
| 265 | | repos = self.env.get_repository(old_context.resource.id[0]) |
| | 265 | reponame = split_vc_resource(old_context.resource)[0] |
| | 266 | repos = self.env.get_repository(reponame) |
| 266 | 267 | def parse_sources(props): |
| 267 | 268 | sources = {} |
| 268 | 269 | for line in props[name].splitlines(): |
diff --git a/trac/versioncontrol/web_ui/browser.py b/trac/versioncontrol/web_ui/browser.py
|
a
|
b
|
|
| 28 | 28 | from trac.mimeview.api import Mimeview, is_binary, get_mimetype, \ |
| 29 | 29 | IHTMLPreviewAnnotator, Context |
| 30 | 30 | from trac.perm import IPermissionRequestor |
| 31 | | from trac.resource import ResourceNotFound, Resource |
| | 31 | from trac.resource import Resource, ResourceNotFound |
| 32 | 32 | from trac.util import embedded_numbers |
| 33 | 33 | from trac.util.compat import all |
| 34 | 34 | from trac.util.datefmt import http_date, utc |
| … |
… |
|
| 41 | 41 | from trac.wiki.api import IWikiSyntaxProvider, IWikiMacroProvider, parse_args |
| 42 | 42 | from trac.wiki.formatter import format_to_html, format_to_oneliner |
| 43 | 43 | from trac.versioncontrol.api import RepositoryManager, NoSuchChangeset, \ |
| 44 | | NoSuchNode |
| | 44 | NoSuchNode, make_repo_resource, \ |
| | 45 | split_vc_resource |
| 45 | 46 | from trac.versioncontrol.web_ui.util import * |
| 46 | 47 | |
| 47 | 48 | |
| … |
… |
|
| 363 | 364 | except NoSuchChangeset, e: |
| 364 | 365 | raise ResourceNotFound(e.message, _('Invalid Changeset Number')) |
| 365 | 366 | |
| 366 | | context = context('source', (reponame, path), node.created_rev) |
| | 367 | context = context(Resource('source', path, |
| | 368 | version=node.created_rev, |
| | 369 | parent=make_repo_resource(reponame))) |
| 367 | 370 | |
| 368 | 371 | # Prepare template data |
| 369 | 372 | path_links = get_path_links(req.href, reponame, path, rev, order, desc) |
| … |
… |
|
| 789 | 792 | def __init__(self, env, context): |
| 790 | 793 | self.env = env |
| 791 | 794 | self.context = context |
| 792 | | # `context`'s resource is ('source', (reponame, path), version=rev) |
| 793 | | r = context.resource |
| 794 | | self.reponame, self.path = r.id |
| | 795 | (self.reponame, self.path) = split_vc_resource(context.resource) |
| 795 | 796 | self.repos = env.get_repository(self.reponame) |
| 796 | | self.rev = r.version |
| | 797 | self.rev = context.resource.version |
| 797 | 798 | # maintain state |
| 798 | 799 | self.prev_chgset = None |
| 799 | 800 | self.chgset_data = {} |
diff --git a/trac/versioncontrol/web_ui/changeset.py b/trac/versioncontrol/web_ui/changeset.py
|
a
|
b
|
|
| 42 | 42 | unicode_urlencode, shorten_line, CRLF |
| 43 | 43 | from trac.util.translation import _, ngettext |
| 44 | 44 | from trac.versioncontrol.api import RepositoryManager, Changeset, Node, \ |
| 45 | | NoSuchChangeset |
| | 45 | NoSuchChangeset, make_repo_resource, \ |
| | 46 | split_vc_resource |
| 46 | 47 | from trac.versioncontrol.diff import get_diff_options, diff_blocks, \ |
| 47 | 48 | unified_diff |
| 48 | 49 | from trac.versioncontrol.web_ui.browser import BrowserModule |
| … |
… |
|
| 485 | 486 | # with _that_ node specific history... |
| 486 | 487 | |
| 487 | 488 | options = data['diff']['options'] |
| | 489 | repo_resource = make_repo_resource(reponame) |
| 488 | 490 | |
| 489 | 491 | def _prop_changes(old_node, new_node): |
| 490 | | old_source = Resource('source', (reponame, old_node.created_path), |
| 491 | | version=old_node.created_rev) |
| 492 | | new_source = Resource('source', (reponame, new_node.created_path), |
| 493 | | version=new_node.created_rev) |
| | 492 | old_source = Resource('source', old_node.created_path, |
| | 493 | version=old_node.created_rev, |
| | 494 | parent=repo_resource) |
| | 495 | new_source = Resource('source', new_node.created_path, |
| | 496 | version=new_node.created_rev, |
| | 497 | parent=repo_resource) |
| 494 | 498 | old_props = new_props = [] |
| 495 | 499 | if 'FILE_VIEW' in req.perm(old_source): |
| 496 | 500 | old_props = old_node.get_properties() |
| … |
… |
|
| 854 | 858 | |
| 855 | 859 | uids_seen = {} |
| 856 | 860 | def generate_changesets(reponame, repos): |
| | 861 | repo_resource = make_repo_resource(reponame) |
| 857 | 862 | for _, changesets in groupby(repos.get_changesets(start, stop), |
| 858 | 863 | key=collapse_changesets): |
| 859 | 864 | viewable_changesets = [] |
| 860 | 865 | for cset in changesets: |
| 861 | | cset_resource = Resource('changeset', |
| 862 | | (reponame, cset.rev)) |
| | 866 | cset_resource = Resource('changeset', cset.rev, |
| | 867 | parent=repo_resource) |
| 863 | 868 | if 'CHANGESET_VIEW' in req.perm(cset_resource): |
| 864 | 869 | repos_for_uid = [reponame] |
| 865 | 870 | uid = repos.get_changeset_uid(cset.rev) |
| … |
… |
|
| 885 | 890 | changesets, show_location, show_files = event[3] |
| 886 | 891 | cset, cset_resource, repos_for_uid = changesets[0] |
| 887 | 892 | message = cset.message or '' |
| 888 | | reponame = cset_resource.id[0] # first repo |
| | 893 | reponame = split_vc_resource(cset_resource)[0] |
| 889 | 894 | rev_b, rev_a = cset.rev, cset.rev |
| 890 | 895 | |
| 891 | 896 | if field == 'url': |
| … |
… |
|
| 1069 | 1074 | #cset = Resource('repository', reponame).child('changeset' , rev) |
| 1070 | 1075 | #cset = repos.resource.child('changeset' , rev) |
| 1071 | 1076 | #cset = repos.changeset_resource(rev) |
| 1072 | | cset = Resource('changeset', (reponame, rev)) |
| | 1077 | cset = Resource('changeset', rev, |
| | 1078 | parent=make_repo_resource(reponame)) |
| 1073 | 1079 | if 'CHANGESET_VIEW' in req.perm(cset): |
| 1074 | 1080 | yield (req.href.changeset(rev, reponame), |
| 1075 | 1081 | '[%s]: %s' % (rev, shorten_line(log)), |