##// END OF EJS Templates
scheme: move the drive letter checking in its own function...
marmoute -
r50585:1863584f default
parent child Browse files
Show More
@@ -1,158 +1,159
1 # Copyright 2009, Alexander Solovyov <piranha@piranha.org.ua>
1 # Copyright 2009, Alexander Solovyov <piranha@piranha.org.ua>
2 #
2 #
3 # This software may be used and distributed according to the terms of the
3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version.
4 # GNU General Public License version 2 or any later version.
5
5
6 """extend schemes with shortcuts to repository swarms
6 """extend schemes with shortcuts to repository swarms
7
7
8 This extension allows you to specify shortcuts for parent URLs with a
8 This extension allows you to specify shortcuts for parent URLs with a
9 lot of repositories to act like a scheme, for example::
9 lot of repositories to act like a scheme, for example::
10
10
11 [schemes]
11 [schemes]
12 py = http://code.python.org/hg/
12 py = http://code.python.org/hg/
13
13
14 After that you can use it like::
14 After that you can use it like::
15
15
16 hg clone py://trunk/
16 hg clone py://trunk/
17
17
18 Additionally there is support for some more complex schemas, for
18 Additionally there is support for some more complex schemas, for
19 example used by Google Code::
19 example used by Google Code::
20
20
21 [schemes]
21 [schemes]
22 gcode = http://{1}.googlecode.com/hg/
22 gcode = http://{1}.googlecode.com/hg/
23
23
24 The syntax is taken from Mercurial templates, and you have unlimited
24 The syntax is taken from Mercurial templates, and you have unlimited
25 number of variables, starting with ``{1}`` and continuing with
25 number of variables, starting with ``{1}`` and continuing with
26 ``{2}``, ``{3}`` and so on. This variables will receive parts of URL
26 ``{2}``, ``{3}`` and so on. This variables will receive parts of URL
27 supplied, split by ``/``. Anything not specified as ``{part}`` will be
27 supplied, split by ``/``. Anything not specified as ``{part}`` will be
28 just appended to an URL.
28 just appended to an URL.
29
29
30 For convenience, the extension adds these schemes by default::
30 For convenience, the extension adds these schemes by default::
31
31
32 [schemes]
32 [schemes]
33 py = http://hg.python.org/
33 py = http://hg.python.org/
34 bb = https://bitbucket.org/
34 bb = https://bitbucket.org/
35 bb+ssh = ssh://hg@bitbucket.org/
35 bb+ssh = ssh://hg@bitbucket.org/
36 gcode = https://{1}.googlecode.com/hg/
36 gcode = https://{1}.googlecode.com/hg/
37 kiln = https://{1}.kilnhg.com/Repo/
37 kiln = https://{1}.kilnhg.com/Repo/
38
38
39 You can override a predefined scheme by defining a new scheme with the
39 You can override a predefined scheme by defining a new scheme with the
40 same name.
40 same name.
41 """
41 """
42
42
43 import os
43 import os
44 import re
44 import re
45
45
46 from mercurial.i18n import _
46 from mercurial.i18n import _
47 from mercurial import (
47 from mercurial import (
48 error,
48 error,
49 extensions,
49 extensions,
50 hg,
50 hg,
51 pycompat,
51 pycompat,
52 registrar,
52 registrar,
53 templater,
53 templater,
54 )
54 )
55 from mercurial.utils import (
55 from mercurial.utils import (
56 urlutil,
56 urlutil,
57 )
57 )
58
58
59 cmdtable = {}
59 cmdtable = {}
60 command = registrar.command(cmdtable)
60 command = registrar.command(cmdtable)
61 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
61 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
62 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
62 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
63 # be specifying the version(s) of Mercurial they are tested with, or
63 # be specifying the version(s) of Mercurial they are tested with, or
64 # leave the attribute unspecified.
64 # leave the attribute unspecified.
65 testedwith = b'ships-with-hg-core'
65 testedwith = b'ships-with-hg-core'
66
66
67 _partre = re.compile(br'{(\d+)\}')
67 _partre = re.compile(br'{(\d+)\}')
68
68
69
69
70 class ShortRepository:
70 class ShortRepository:
71 def __init__(self, url, scheme, templater):
71 def __init__(self, url, scheme, templater):
72 self.scheme = scheme
72 self.scheme = scheme
73 self.templater = templater
73 self.templater = templater
74 self.url = url
74 self.url = url
75 try:
75 try:
76 self.parts = max(map(int, _partre.findall(self.url)))
76 self.parts = max(map(int, _partre.findall(self.url)))
77 except ValueError:
77 except ValueError:
78 self.parts = 0
78 self.parts = 0
79
79
80 def __repr__(self):
80 def __repr__(self):
81 return b'<ShortRepository: %s>' % self.scheme
81 return b'<ShortRepository: %s>' % self.scheme
82
82
83 def instance(self, ui, url, create, intents=None, createopts=None):
83 def instance(self, ui, url, create, intents=None, createopts=None):
84 url = self.resolve(url)
84 url = self.resolve(url)
85 return hg._peerlookup(url).instance(
85 return hg._peerlookup(url).instance(
86 ui, url, create, intents=intents, createopts=createopts
86 ui, url, create, intents=intents, createopts=createopts
87 )
87 )
88
88
89 def resolve(self, url):
89 def resolve(self, url):
90 # Should this use the urlutil.url class, or is manual parsing better?
90 # Should this use the urlutil.url class, or is manual parsing better?
91 try:
91 try:
92 url = url.split(b'://', 1)[1]
92 url = url.split(b'://', 1)[1]
93 except IndexError:
93 except IndexError:
94 raise error.Abort(_(b"no '://' in scheme url '%s'") % url)
94 raise error.Abort(_(b"no '://' in scheme url '%s'") % url)
95 parts = url.split(b'/', self.parts)
95 parts = url.split(b'/', self.parts)
96 if len(parts) > self.parts:
96 if len(parts) > self.parts:
97 tail = parts[-1]
97 tail = parts[-1]
98 parts = parts[:-1]
98 parts = parts[:-1]
99 else:
99 else:
100 tail = b''
100 tail = b''
101 context = {b'%d' % (i + 1): v for i, v in enumerate(parts)}
101 context = {b'%d' % (i + 1): v for i, v in enumerate(parts)}
102 return b''.join(self.templater.process(self.url, context)) + tail
102 return b''.join(self.templater.process(self.url, context)) + tail
103
103
104
104
105 def hasdriveletter(orig, path):
105 def hasdriveletter(orig, path):
106 if path:
106 if path:
107 for scheme in schemes:
107 for scheme in schemes:
108 if path.startswith(scheme + b':'):
108 if path.startswith(scheme + b':'):
109 return False
109 return False
110 return orig(path)
110 return orig(path)
111
111
112
112
113 schemes = {
113 schemes = {
114 b'py': b'http://hg.python.org/',
114 b'py': b'http://hg.python.org/',
115 b'bb': b'https://bitbucket.org/',
115 b'bb': b'https://bitbucket.org/',
116 b'bb+ssh': b'ssh://hg@bitbucket.org/',
116 b'bb+ssh': b'ssh://hg@bitbucket.org/',
117 b'gcode': b'https://{1}.googlecode.com/hg/',
117 b'gcode': b'https://{1}.googlecode.com/hg/',
118 b'kiln': b'https://{1}.kilnhg.com/Repo/',
118 b'kiln': b'https://{1}.kilnhg.com/Repo/',
119 }
119 }
120
120
121
121
122 def extsetup(ui):
122 def _check_drive_letter(scheme):
123 schemes.update(dict(ui.configitems(b'schemes')))
123 """check if a scheme conflict with a Windows drive letter"""
124 t = templater.engine(templater.parse)
125 for scheme, url in schemes.items():
126 if (
124 if (
127 pycompat.iswindows
125 pycompat.iswindows
128 and len(scheme) == 1
126 and len(scheme) == 1
129 and scheme.isalpha()
127 and scheme.isalpha()
130 and os.path.exists(b'%s:\\' % scheme)
128 and os.path.exists(b'%s:\\' % scheme)
131 ):
129 ):
132 raise error.Abort(
130 msg = _(b'custom scheme %s:// conflicts with drive letter %s:\\\n')
133 _(
131 msg %= (scheme, scheme.upper())
134 b'custom scheme %s:// conflicts with drive '
132 raise error.Abort(msg)
135 b'letter %s:\\\n'
133
136 )
134
137 % (scheme, scheme.upper())
135 def extsetup(ui):
138 )
136 schemes.update(dict(ui.configitems(b'schemes')))
137 t = templater.engine(templater.parse)
138 for scheme, url in schemes.items():
139 _check_drive_letter(schemes)
139 url_scheme = urlutil.url(url).scheme
140 url_scheme = urlutil.url(url).scheme
140 if url_scheme in hg.peer_schemes:
141 if url_scheme in hg.peer_schemes:
141 hg.peer_schemes[scheme] = ShortRepository(url, scheme, t)
142 hg.peer_schemes[scheme] = ShortRepository(url, scheme, t)
142 else:
143 else:
143 hg.repo_schemes[scheme] = ShortRepository(url, scheme, t)
144 hg.repo_schemes[scheme] = ShortRepository(url, scheme, t)
144
145
145 extensions.wrapfunction(urlutil, b'hasdriveletter', hasdriveletter)
146 extensions.wrapfunction(urlutil, b'hasdriveletter', hasdriveletter)
146
147
147
148
148 @command(b'debugexpandscheme', norepo=True)
149 @command(b'debugexpandscheme', norepo=True)
149 def expandscheme(ui, url, **opts):
150 def expandscheme(ui, url, **opts):
150 """given a repo path, provide the scheme-expanded path"""
151 """given a repo path, provide the scheme-expanded path"""
151 scheme = urlutil.url(url).scheme
152 scheme = urlutil.url(url).scheme
152 if scheme in hg.peer_schemes:
153 if scheme in hg.peer_schemes:
153 cls = hg.peer_schemes[scheme]
154 cls = hg.peer_schemes[scheme]
154 else:
155 else:
155 cls = hg.repo_schemes.get(scheme)
156 cls = hg.repo_schemes.get(scheme)
156 if cls is not None and isinstance(cls, ShortRepository):
157 if cls is not None and isinstance(cls, ShortRepository):
157 url = cls.resolve(url)
158 url = cls.resolve(url)
158 ui.write(url + b'\n')
159 ui.write(url + b'\n')
General Comments 0
You need to be logged in to leave comments. Login now