diff --git a/trac/versioncontrol/admin.py b/trac/versioncontrol/admin.py
|
a
|
b
|
|
| 187 | 187 | # Modify repository |
| 188 | 188 | changed = False |
| 189 | 189 | changes = {} |
| 190 | | for field in ['alias', 'dir', 'type']: |
| | 190 | for field in db_provider.repository_attrs: |
| 191 | 191 | value = req.args.get(field) |
| 192 | 192 | if value is not None and value != info.get(field): |
| 193 | 193 | changes[field] = value |
diff --git a/trac/versioncontrol/api.py b/trac/versioncontrol/api.py
|
a
|
b
|
|
| 95 | 95 | |
| 96 | 96 | implements(IRepositoryProvider, IAdminCommandProvider) |
| 97 | 97 | |
| | 98 | repository_attrs = ('alias', 'dir', 'type', 'url') |
| | 99 | |
| 98 | 100 | # IRepositoryProvider methods |
| 99 | 101 | |
| 100 | 102 | def get_repositories(self): |
| … |
… |
|
| 102 | 104 | db = self.env.get_db_cnx() |
| 103 | 105 | cursor = db.cursor() |
| 104 | 106 | cursor.execute("SELECT id,name,value FROM repository " |
| 105 | | "WHERE name IN ('dir', 'alias', 'type')") |
| | 107 | "WHERE name IN (%s)" % ",".join( |
| | 108 | "'%s'" % each for each in self.repository_attrs)) |
| 106 | 109 | reponames = {} |
| 107 | 110 | for (id, name, value) in cursor: |
| 108 | 111 | if value is not None: |
| 109 | 112 | reponames.setdefault(id, {})[name] = value |
| 110 | | |
| 111 | | for reponame, info in reponames.iteritems(): |
| 112 | | yield (reponame, info) |
| | 113 | return reponames.iteritems() |
| 113 | 114 | |
| 114 | 115 | # IAdminCommandProvider methods |
| 115 | 116 | |
| … |
… |
|
| 229 | 230 | db = self.env.get_db_cnx() |
| 230 | 231 | cursor = db.cursor() |
| 231 | 232 | for (k, v) in changes.iteritems(): |
| | 233 | if k not in self.repository_attrs: |
| | 234 | continue |
| 232 | 235 | cursor.execute("UPDATE repository SET value=%s " |
| 233 | 236 | "WHERE id=%s AND name=%s", (v, reponame, k)) |
| | 237 | cursor.execute("SELECT value FROM repository " |
| | 238 | "WHERE id=%s AND name=%s", (reponame, k)) |
| | 239 | if not cursor.fetchone(): |
| | 240 | cursor.execute("INSERT INTO repository VALUES (%s, %s, %s)", |
| | 241 | (reponame, k, v)) |
| 234 | 242 | db.commit() |
| 235 | 243 | RepositoryManager(self.env).reload_repositories() |
| 236 | 244 | |
| … |
… |
|
| 257 | 265 | This means that if you want to use Trac without the source browser, |
| 258 | 266 | simply remove that entry from the [trac] section.""") |
| 259 | 267 | |
| | 268 | repository_url = Option('trac', 'repository_url', '', |
| | 269 | """Base URL of the default repository. (''since 0.12'')""") |
| | 270 | |
| 260 | 271 | repository_sync_per_request = ListOption('trac', |
| 261 | 272 | 'repository_sync_per_request', '(default)', |
| 262 | 273 | doc="""List of repositories that should be synchronized on every page |
| … |
… |
|
| 364 | 375 | name, detail = option[:dotindex], option[dotindex+1:] |
| 365 | 376 | if name in reponames: |
| 366 | 377 | reponames[name][detail] = repositories.get(option) |
| 367 | | else: # alias? |
| | 378 | elif detail == 'alias': |
| 368 | 379 | alias = repositories.get(option) |
| 369 | 380 | if alias in reponames: |
| 370 | 381 | reponames[option] = {'alias': alias} |
| 371 | 382 | # eventually add pre-0.12 default repository |
| 372 | 383 | if '' not in reponames and self.repository_dir: |
| 373 | | reponames[''] = {'dir': self.repository_dir} |
| | 384 | reponames[''] = {'dir': self.repository_dir, |
| | 385 | 'url': self.repository_url} |
| 374 | 386 | |
| 375 | 387 | for reponame, info in reponames.iteritems(): |
| 376 | 388 | yield (reponame, info) |
| … |
… |
|
| 461 | 473 | been truncated, if needed. |
| 462 | 474 | """ |
| 463 | 475 | matches = [] |
| 464 | | path = path and path.strip('/')+'/' or '/' |
| | 476 | path = path and path.strip('/') + '/' or '/' |
| 465 | 477 | for reponame in self.get_all_repositories().keys(): |
| 466 | | stripped_reponame = reponame.strip('/')+'/' |
| | 478 | stripped_reponame = reponame.strip('/') + '/' |
| 467 | 479 | if path.startswith(stripped_reponame): |
| 468 | 480 | matches.append((len(stripped_reponame), reponame)) |
| 469 | 481 | if matches: |
| … |
… |
|
| 472 | 484 | path = path[length:] |
| 473 | 485 | else: |
| 474 | 486 | reponame = '' |
| 475 | | return (reponame, self.get_repository(reponame, authname), path or '/') |
| | 487 | return (reponame, self.get_repository(reponame, authname), |
| | 488 | path.rstrip('/') or '/') |
| 476 | 489 | |
| 477 | 490 | def get_default_repository(self, context): |
| 478 | 491 | """Recover the appropriate repository from the current context. |
| … |
… |
|
| 681 | 694 | """ |
| 682 | 695 | return [] |
| 683 | 696 | |
| | 697 | def get_path_url(self, path, rev): |
| | 698 | """Return the repository URL for the given path and revision. |
| | 699 | |
| | 700 | The returned URL can be `None`, meaning that no URL has been specified |
| | 701 | for the repository, an absolute URL, or a scheme-relative URL starting |
| | 702 | with `//`, in which case the scheme of the request should be prepended. |
| | 703 | """ |
| | 704 | return None |
| | 705 | |
| 684 | 706 | def get_changeset(self, rev): |
| 685 | 707 | """Retrieve a Changeset corresponding to the given revision `rev`.""" |
| 686 | 708 | raise NotImplementedError |
diff --git a/trac/versioncontrol/cache.py b/trac/versioncontrol/cache.py
|
a
|
b
|
|
| 70 | 70 | def get_quickjump_entries(self, rev): |
| 71 | 71 | return self.repos.get_quickjump_entries(self.normalize_rev(rev)) |
| 72 | 72 | |
| | 73 | def get_path_url(self, path, rev): |
| | 74 | return self.repos.get_path_url(path, rev) |
| | 75 | |
| 73 | 76 | def get_changeset(self, rev): |
| 74 | 77 | return CachedChangeset(self.repos, self.normalize_rev(rev), |
| 75 | 78 | self.env, self.authz) |
diff --git a/trac/versioncontrol/svn_fs.py b/trac/versioncontrol/svn_fs.py
|
a
|
b
|
|
| 280 | 280 | self.env.systeminfo.append(('Subversion', self._version)) |
| 281 | 281 | fs_repos = SubversionRepository(dir, None, self.log, |
| 282 | 282 | {'tags': self.tags, |
| 283 | | 'branches': self.branches}) |
| | 283 | 'branches': self.branches, |
| | 284 | 'url': options.get('url')}) |
| 284 | 285 | if type == 'direct-svnfs': |
| 285 | 286 | repos = fs_repos |
| 286 | 287 | else: |
| … |
… |
|
| 422 | 423 | for n in self._get_tags_or_branches('tags'): |
| 423 | 424 | yield 'tags', n.path, n.created_path, n.created_rev |
| 424 | 425 | |
| | 426 | def get_path_url(self, path, rev): |
| | 427 | url = self.options.get('url', '').rstrip('/') |
| | 428 | if url: |
| | 429 | if not path or path == '/': |
| | 430 | return url |
| | 431 | return url + '/' + path.lstrip('/') |
| | 432 | |
| 425 | 433 | def get_changeset(self, rev): |
| 426 | 434 | rev = self.normalize_rev(rev) |
| 427 | 435 | return SubversionChangeset(rev, self.authz, self.scope, |
diff --git a/trac/versioncontrol/templates/admin_repositories.html b/trac/versioncontrol/templates/admin_repositories.html
|
a
|
b
|
|
| 57 | 57 | <div class="field"> |
| 58 | 58 | <label>Directory:<br/><input type="text" name="dir" size="48" value="$info.dir" readonly="$readonly"/></label> |
| 59 | 59 | </div> |
| | 60 | <div class="field"> |
| | 61 | <label>URL:<br/><input type="text" name="url" size="48" value="$info.url" readonly="$readonly"/></label> |
| | 62 | </div> |
| 60 | 63 | </py:otherwise> |
| 61 | 64 | </py:choose> |
| 62 | 65 | <div class="buttons"> |
diff --git a/trac/versioncontrol/web_ui/browser.py b/trac/versioncontrol/web_ui/browser.py
|
a
|
b
|
|
| 408 | 408 | |
| 409 | 409 | # Links for contextual navigation |
| 410 | 410 | if node: |
| | 411 | path_url = repos.get_path_url(path, rev) |
| | 412 | if path_url: |
| | 413 | if path_url.startswith('//'): |
| | 414 | path_url = req.scheme + ':' + path_url |
| | 415 | add_ctxtnav(req, _('Repository URL'), href=path_url) |
| 411 | 416 | add_ctxtnav(req, tag.a(_('Last Change'), |
| 412 | 417 | href=req.href.changeset(node.rev, reponame, |
| 413 | 418 | node.created_path))) |