schemes.py
158 lines
| 4.6 KiB
| text/x-python
|
PythonLexer
/ hgext / schemes.py
|
r9964 | # Copyright 2009, Alexander Solovyov <piranha@piranha.org.ua> | ||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
|
r10263 | # GNU General Public License version 2 or any later version. | ||
|
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/ | ||||
|
r10777 | kiln = https://{1}.kilnhg.com/Repo/ | ||
|
r9964 | |||
|
r9965 | You can override a predefined scheme by defining a new scheme with the | ||
same name. | ||||
|
r9964 | """ | ||
|
r28379 | import os | ||
import re | ||||
|
r29205 | |||
from mercurial.i18n import _ | ||||
|
r28379 | from mercurial import ( | ||
error, | ||||
extensions, | ||||
hg, | ||||
|
r30640 | pycompat, | ||
|
r32337 | registrar, | ||
|
r28379 | templater, | ||
r47669 | ) | |||
from mercurial.utils import ( | ||||
urlutil, | ||||
|
r28379 | ) | ||
|
r9964 | |||
|
r27982 | cmdtable = {} | ||
|
r32337 | command = registrar.command(cmdtable) | ||
|
r29841 | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for | ||
|
r25186 | # 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. | ||||
|
r43347 | testedwith = b'ships-with-hg-core' | ||
|
r16743 | |||
|
r44474 | _partre = re.compile(br'{(\d+)\}') | ||
|
r9964 | |||
|
r43346 | |||
|
r49801 | class ShortRepository: | ||
|
r9964 | def __init__(self, url, scheme, templater): | ||
self.scheme = scheme | ||||
self.templater = templater | ||||
self.url = url | ||||
try: | ||||
|
r31181 | self.parts = max(map(int, _partre.findall(self.url))) | ||
|
r9964 | except ValueError: | ||
self.parts = 0 | ||||
def __repr__(self): | ||||
|
r43347 | return b'<ShortRepository: %s>' % self.scheme | ||
|
r9964 | |||
|
r39585 | def instance(self, ui, url, create, intents=None, createopts=None): | ||
|
r27981 | url = self.resolve(url) | ||
|
r43346 | return hg._peerlookup(url).instance( | ||
ui, url, create, intents=intents, createopts=createopts | ||||
) | ||||
|
r27981 | |||
def resolve(self, url): | ||||
r47669 | # Should this use the urlutil.url class, or is manual parsing better? | |||
|
r18910 | try: | ||
|
r43347 | url = url.split(b'://', 1)[1] | ||
|
r18910 | except IndexError: | ||
|
r43347 | raise error.Abort(_(b"no '://' in scheme url '%s'") % url) | ||
parts = url.split(b'/', self.parts) | ||||
|
r9964 | if len(parts) > self.parts: | ||
tail = parts[-1] | ||||
parts = parts[:-1] | ||||
else: | ||||
|
r43347 | tail = b'' | ||
|
r44937 | context = {b'%d' % (i + 1): v for i, v in enumerate(parts)} | ||
|
r43347 | return b''.join(self.templater.process(self.url, context)) + tail | ||
|
r9964 | |||
|
r43346 | |||
|
r13827 | def hasdriveletter(orig, path): | ||
|
r15609 | if path: | ||
for scheme in schemes: | ||||
|
r43347 | if path.startswith(scheme + b':'): | ||
|
r15609 | return False | ||
|
r13822 | return orig(path) | ||
|
r43346 | |||
|
r9964 | schemes = { | ||
|
r43347 | b'py': b'http://hg.python.org/', | ||
b'bb': b'https://bitbucket.org/', | ||||
b'bb+ssh': b'ssh://hg@bitbucket.org/', | ||||
b'gcode': b'https://{1}.googlecode.com/hg/', | ||||
b'kiln': b'https://{1}.kilnhg.com/Repo/', | ||||
|
r43346 | } | ||
|
r9964 | |||
def extsetup(ui): | ||||
|
r43347 | schemes.update(dict(ui.configitems(b'schemes'))) | ||
|
r38373 | t = templater.engine(templater.parse) | ||
|
r9964 | for scheme, url in schemes.items(): | ||
|
r43346 | if ( | ||
pycompat.iswindows | ||||
and len(scheme) == 1 | ||||
and scheme.isalpha() | ||||
|
r43347 | and os.path.exists(b'%s:\\' % scheme) | ||
|
r43346 | ): | ||
raise error.Abort( | ||||
|
r43347 | _( | ||
b'custom scheme %s:// conflicts with drive ' | ||||
b'letter %s:\\\n' | ||||
) | ||||
|
r43346 | % (scheme, scheme.upper()) | ||
) | ||||
r50584 | url_scheme = urlutil.url(url).scheme | |||
if url_scheme in hg.peer_schemes: | ||||
hg.peer_schemes[scheme] = ShortRepository(url, scheme, t) | ||||
else: | ||||
hg.repo_schemes[scheme] = ShortRepository(url, scheme, t) | ||||
|
r13822 | |||
r47669 | extensions.wrapfunction(urlutil, b'hasdriveletter', hasdriveletter) | |||
|
r27982 | |||
|
r43346 | |||
|
r43347 | @command(b'debugexpandscheme', norepo=True) | ||
|
r27982 | def expandscheme(ui, url, **opts): | ||
|
r46554 | """given a repo path, provide the scheme-expanded path""" | ||
r50584 | scheme = urlutil.url(url).scheme | |||
if scheme in hg.peer_schemes: | ||||
cls = hg.peer_schemes[scheme] | ||||
else: | ||||
cls = hg.repo_schemes.get(scheme) | ||||
if cls is not None and isinstance(cls, ShortRepository): | ||||
url = cls.resolve(url) | ||||
|
r43347 | ui.write(url + b'\n') | ||