schemes.py
131 lines
| 4.0 KiB
| text/x-python
|
PythonLexer
/ hgext / schemes.py
Alexander Solovyov
|
r9964 | # Copyright 2009, Alexander Solovyov <piranha@piranha.org.ua> | ||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
Matt Mackall
|
r10263 | # GNU General Public License version 2 or any later version. | ||
Alexander Solovyov
|
r9964 | |||
"""extend schemes with shortcuts to repository swarms | ||||
This extension allows you to specify shortcuts for parent URLs with a | ||||
lot of repositories to act like a scheme, for example:: | ||||
[schemes] | ||||
py = http://code.python.org/hg/ | ||||
After that you can use it like:: | ||||
hg clone py://trunk/ | ||||
Additionally there is support for some more complex schemas, for | ||||
example used by Google Code:: | ||||
[schemes] | ||||
gcode = http://{1}.googlecode.com/hg/ | ||||
The syntax is taken from Mercurial templates, and you have unlimited | ||||
number of variables, starting with ``{1}`` and continuing with | ||||
``{2}``, ``{3}`` and so on. This variables will receive parts of URL | ||||
supplied, split by ``/``. Anything not specified as ``{part}`` will be | ||||
just appended to an URL. | ||||
For convenience, the extension adds these schemes by default:: | ||||
[schemes] | ||||
py = http://hg.python.org/ | ||||
bb = https://bitbucket.org/ | ||||
bb+ssh = ssh://hg@bitbucket.org/ | ||||
gcode = https://{1}.googlecode.com/hg/ | ||||
Benjamin Pollack
|
r10777 | kiln = https://{1}.kilnhg.com/Repo/ | ||
Alexander Solovyov
|
r9964 | |||
Martin Geisler
|
r9965 | You can override a predefined scheme by defining a new scheme with the | ||
same name. | ||||
Alexander Solovyov
|
r9964 | """ | ||
timeless
|
r28379 | from __future__ import absolute_import | ||
Alexander Solovyov
|
r9964 | |||
timeless
|
r28379 | import os | ||
import re | ||||
from mercurial import ( | ||||
cmdutil, | ||||
error, | ||||
extensions, | ||||
hg, | ||||
templater, | ||||
util, | ||||
) | ||||
Brodie Rao
|
r13822 | from mercurial.i18n import _ | ||
Alexander Solovyov
|
r9964 | |||
Jason R. Coombs
|
r27982 | cmdtable = {} | ||
command = cmdutil.command(cmdtable) | ||||
Augie Fackler
|
r25186 | # Note for extension authors: ONLY specify testedwith = 'internal' for | ||
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | ||||
# be specifying the version(s) of Mercurial they are tested with, or | ||||
# leave the attribute unspecified. | ||||
Augie Fackler
|
r16743 | testedwith = 'internal' | ||
Alexander Solovyov
|
r9964 | |||
class ShortRepository(object): | ||||
def __init__(self, url, scheme, templater): | ||||
self.scheme = scheme | ||||
self.templater = templater | ||||
self.url = url | ||||
try: | ||||
self.parts = max(map(int, re.findall(r'\{(\d+)\}', self.url))) | ||||
except ValueError: | ||||
self.parts = 0 | ||||
def __repr__(self): | ||||
return '<ShortRepository: %s>' % self.scheme | ||||
def instance(self, ui, url, create): | ||||
Jason R. Coombs
|
r27981 | url = self.resolve(url) | ||
return hg._peerlookup(url).instance(ui, url, create) | ||||
def resolve(self, url): | ||||
Mads Kiilerich
|
r17425 | # Should this use the util.url class, or is manual parsing better? | ||
Mads Kiilerich
|
r18910 | try: | ||
url = url.split('://', 1)[1] | ||||
except IndexError: | ||||
Pierre-Yves David
|
r26587 | raise error.Abort(_("no '://' in scheme url '%s'") % url) | ||
Alexander Solovyov
|
r9964 | parts = url.split('/', self.parts) | ||
if len(parts) > self.parts: | ||||
tail = parts[-1] | ||||
parts = parts[:-1] | ||||
else: | ||||
tail = '' | ||||
Matt Mackall
|
r10282 | context = dict((str(i + 1), v) for i, v in enumerate(parts)) | ||
Jason R. Coombs
|
r27981 | return ''.join(self.templater.process(self.url, context)) + tail | ||
Alexander Solovyov
|
r9964 | |||
Matt Mackall
|
r13827 | def hasdriveletter(orig, path): | ||
Patrick Mezard
|
r15609 | if path: | ||
for scheme in schemes: | ||||
if path.startswith(scheme + ':'): | ||||
return False | ||||
Brodie Rao
|
r13822 | return orig(path) | ||
Alexander Solovyov
|
r9964 | schemes = { | ||
'py': 'http://hg.python.org/', | ||||
'bb': 'https://bitbucket.org/', | ||||
'bb+ssh': 'ssh://hg@bitbucket.org/', | ||||
Benjamin Pollack
|
r10777 | 'gcode': 'https://{1}.googlecode.com/hg/', | ||
'kiln': 'https://{1}.kilnhg.com/Repo/' | ||||
Alexander Solovyov
|
r9964 | } | ||
def extsetup(ui): | ||||
schemes.update(dict(ui.configitems('schemes'))) | ||||
t = templater.engine(lambda x: x) | ||||
for scheme, url in schemes.items(): | ||||
Brodie Rao
|
r13822 | if (os.name == 'nt' and len(scheme) == 1 and scheme.isalpha() | ||
and os.path.exists('%s:\\' % scheme)): | ||||
Pierre-Yves David
|
r26587 | raise error.Abort(_('custom scheme %s:// conflicts with drive ' | ||
Brodie Rao
|
r13822 | 'letter %s:\\\n') % (scheme, scheme.upper())) | ||
Matt Mackall
|
r14606 | hg.schemes[scheme] = ShortRepository(url, scheme, t) | ||
Brodie Rao
|
r13822 | |||
Brodie Rao
|
r14076 | extensions.wrapfunction(util, 'hasdriveletter', hasdriveletter) | ||
Jason R. Coombs
|
r27982 | |||
@command('debugexpandscheme', norepo=True) | ||||
def expandscheme(ui, url, **opts): | ||||
"""given a repo path, provide the scheme-expanded path | ||||
""" | ||||
repo = hg._peerlookup(url) | ||||
if isinstance(repo, ShortRepository): | ||||
url = repo.resolve(url) | ||||
ui.write(url + '\n') | ||||