##// END OF EJS Templates
peer: introduce real peer classes...
Peter Arrenbrecht -
r17192:1ac628cd default
parent child Browse files
Show More
@@ -6,7 +6,7 b''
6 import os
6 import os
7 import urllib2
7 import urllib2
8
8
9 from mercurial import error, httprepo, util, wireproto
9 from mercurial import error, httppeer, util, wireproto
10 from mercurial.wireproto import batchable, future
10 from mercurial.wireproto import batchable, future
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12
12
@@ -82,7 +82,7 b' def wirereposetup(ui, repo):'
82 # unfortunately, httprepository._callpush tries to convert its
82 # unfortunately, httprepository._callpush tries to convert its
83 # input file-like into a bundle before sending it, so we can't use
83 # input file-like into a bundle before sending it, so we can't use
84 # it ...
84 # it ...
85 if issubclass(self.__class__, httprepo.httprepository):
85 if issubclass(self.__class__, httppeer.httppeer):
86 res = None
86 res = None
87 try:
87 try:
88 res = self._call('putlfile', data=fd, sha=sha,
88 res = self._call('putlfile', data=fd, sha=sha,
@@ -9,7 +9,7 b''
9 '''setup for largefiles extension: uisetup'''
9 '''setup for largefiles extension: uisetup'''
10
10
11 from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \
11 from mercurial import archival, cmdutil, commands, extensions, filemerge, hg, \
12 httprepo, localrepo, merge, sshrepo, sshserver, wireproto
12 httppeer, localrepo, merge, sshpeer, sshserver, wireproto
13 from mercurial.i18n import _
13 from mercurial.i18n import _
14 from mercurial.hgweb import hgweb_mod, protocol, webcommands
14 from mercurial.hgweb import hgweb_mod, protocol, webcommands
15 from mercurial.subrepo import hgsubrepo
15 from mercurial.subrepo import hgsubrepo
@@ -143,10 +143,10 b' def uisetup(ui):'
143
143
144 # can't do this in reposetup because it needs to have happened before
144 # can't do this in reposetup because it needs to have happened before
145 # wirerepo.__init__ is called
145 # wirerepo.__init__ is called
146 proto.ssholdcallstream = sshrepo.sshrepository._callstream
146 proto.ssholdcallstream = sshpeer.sshpeer._callstream
147 proto.httpoldcallstream = httprepo.httprepository._callstream
147 proto.httpoldcallstream = httppeer.httppeer._callstream
148 sshrepo.sshrepository._callstream = proto.sshrepocallstream
148 sshpeer.sshpeer._callstream = proto.sshrepocallstream
149 httprepo.httprepository._callstream = proto.httprepocallstream
149 httppeer.httppeer._callstream = proto.httprepocallstream
150
150
151 # don't die on seeing a repo with the largefiles requirement
151 # don't die on seeing a repo with the largefiles requirement
152 localrepo.localrepository.supported |= set(['largefiles'])
152 localrepo.localrepository.supported |= set(['largefiles'])
@@ -16,7 +16,7 b' import sshserver, hgweb, hgweb.server, c'
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
@@ -1789,6 +1789,9 b' def debugdiscovery(ui, repo, remoteurl="'
1789 if localheads:
1789 if localheads:
1790 raise util.Abort('cannot use localheads with old style '
1790 raise util.Abort('cannot use localheads with old style '
1791 'discovery')
1791 'discovery')
1792 if not util.safehasattr(remote, 'branches'):
1793 # enable in-client legacy support
1794 remote = localrepo.locallegacypeer(remote.local())
1792 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1795 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1793 force=True)
1796 force=True)
1794 common = set(common)
1797 common = set(common)
@@ -9,7 +9,7 b''
9 from i18n import _
9 from i18n import _
10 from lock import release
10 from lock import release
11 from node import hex, nullid
11 from node import hex, nullid
12 import localrepo, bundlerepo, httprepo, sshrepo, statichttprepo, bookmarks
12 import localrepo, bundlerepo, httppeer, sshpeer, statichttprepo, bookmarks
13 import lock, util, extensions, error, node, scmutil
13 import lock, util, extensions, error, node, scmutil
14 import cmdutil, discovery
14 import cmdutil, discovery
15 import merge as mergemod
15 import merge as mergemod
@@ -65,9 +65,9 b' def parseurl(path, branches=None):'
65 schemes = {
65 schemes = {
66 'bundle': bundlerepo,
66 'bundle': bundlerepo,
67 'file': _local,
67 'file': _local,
68 'http': httprepo,
68 'http': httppeer,
69 'https': httprepo,
69 'https': httppeer,
70 'ssh': sshrepo,
70 'ssh': sshpeer,
71 'static-http': statichttprepo,
71 'static-http': statichttprepo,
72 }
72 }
73
73
@@ -1,4 +1,4 b''
1 # httprepo.py - HTTP repository proxy classes for mercurial
1 # httppeer.py - HTTP repository proxy classes for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
@@ -23,7 +23,7 b' def zgenerator(f):'
23 raise IOError(None, _('connection ended unexpectedly'))
23 raise IOError(None, _('connection ended unexpectedly'))
24 yield zd.flush()
24 yield zd.flush()
25
25
26 class httprepository(wireproto.wirerepository):
26 class httppeer(wireproto.wirepeer):
27 def __init__(self, ui, path):
27 def __init__(self, ui, path):
28 self.path = path
28 self.path = path
29 self.caps = None
29 self.caps = None
@@ -56,7 +56,7 b' class httprepository(wireproto.wirerepos'
56 def _fetchcaps(self):
56 def _fetchcaps(self):
57 self.caps = set(self._call('capabilities').split())
57 self.caps = set(self._call('capabilities').split())
58
58
59 def get_caps(self):
59 def _capabilities(self):
60 if self.caps is None:
60 if self.caps is None:
61 try:
61 try:
62 self._fetchcaps()
62 self._fetchcaps()
@@ -66,8 +66,6 b' class httprepository(wireproto.wirerepos'
66 (' '.join(self.caps or ['none'])))
66 (' '.join(self.caps or ['none'])))
67 return self.caps
67 return self.caps
68
68
69 capabilities = property(get_caps)
70
71 def lock(self):
69 def lock(self):
72 raise util.Abort(_('operation not supported over http'))
70 raise util.Abort(_('operation not supported over http'))
73
71
@@ -215,21 +213,21 b' class httprepository(wireproto.wirerepos'
215 def _decompress(self, stream):
213 def _decompress(self, stream):
216 return util.chunkbuffer(zgenerator(stream))
214 return util.chunkbuffer(zgenerator(stream))
217
215
218 class httpsrepository(httprepository):
216 class httpspeer(httppeer):
219 def __init__(self, ui, path):
217 def __init__(self, ui, path):
220 if not url.has_https:
218 if not url.has_https:
221 raise util.Abort(_('Python support for SSL and HTTPS '
219 raise util.Abort(_('Python support for SSL and HTTPS '
222 'is not installed'))
220 'is not installed'))
223 httprepository.__init__(self, ui, path)
221 httppeer.__init__(self, ui, path)
224
222
225 def instance(ui, path, create):
223 def instance(ui, path, create):
226 if create:
224 if create:
227 raise util.Abort(_('cannot create new http repository'))
225 raise util.Abort(_('cannot create new http repository'))
228 try:
226 try:
229 if path.startswith('https:'):
227 if path.startswith('https:'):
230 inst = httpsrepository(ui, path)
228 inst = httpspeer(ui, path)
231 else:
229 else:
232 inst = httprepository(ui, path)
230 inst = httppeer(ui, path)
233 try:
231 try:
234 # Try to do useful work when checking compatibility.
232 # Try to do useful work when checking compatibility.
235 # Usually saves a roundtrip since we want the caps anyway.
233 # Usually saves a roundtrip since we want the caps anyway.
@@ -6,7 +6,7 b''
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 from node import bin, hex, nullid, nullrev, short
7 from node import bin, hex, nullid, nullrev, short
8 from i18n import _
8 from i18n import _
9 import repo, changegroup, subrepo, discovery, pushkey, obsolete
9 import peer, changegroup, subrepo, discovery, pushkey, obsolete
10 import changelog, dirstate, filelog, manifest, context, bookmarks, phases
10 import changelog, dirstate, filelog, manifest, context, bookmarks, phases
11 import lock, transaction, store, encoding, base85
11 import lock, transaction, store, encoding, base85
12 import scmutil, util, extensions, hook, error, revset
12 import scmutil, util, extensions, hook, error, revset
@@ -23,9 +23,90 b' class storecache(filecache):'
23 def join(self, obj, fname):
23 def join(self, obj, fname):
24 return obj.sjoin(fname)
24 return obj.sjoin(fname)
25
25
26 class localrepository(repo.repository):
26 MODERNCAPS = set(('lookup', 'branchmap', 'pushkey', 'known', 'getbundle'))
27 capabilities = set(('lookup', 'changegroupsubset', 'branchmap', 'pushkey',
27 LEGACYCAPS = MODERNCAPS.union(set(['changegroupsubset']))
28 'known', 'getbundle'))
28
29 class localpeer(peer.peerrepository):
30 '''peer for a local repo; reflects only the most recent API'''
31
32 def __init__(self, repo, caps=MODERNCAPS):
33 peer.peerrepository.__init__(self)
34 self._repo = repo
35 self.ui = repo.ui
36 self._caps = repo._restrictcapabilities(caps)
37 self.requirements = repo.requirements
38 self.supportedformats = repo.supportedformats
39
40 def close(self):
41 self._repo.close()
42
43 def _capabilities(self):
44 return self._caps
45
46 def local(self):
47 return self._repo
48
49 def cancopy(self):
50 return self._repo.cancopy() # so bundlerepo can override
51
52 def url(self):
53 return self._repo.url()
54
55 def lookup(self, key):
56 return self._repo.lookup(key)
57
58 def branchmap(self):
59 return self._repo.branchmap()
60
61 def heads(self):
62 return self._repo.heads()
63
64 def known(self, nodes):
65 return self._repo.known(nodes)
66
67 def getbundle(self, source, heads=None, common=None):
68 return self._repo.getbundle(source, heads=heads, common=common)
69
70 # TODO We might want to move the next two calls into legacypeer and add
71 # unbundle instead.
72
73 def lock(self):
74 return self._repo.lock()
75
76 def addchangegroup(self, cg, source, url):
77 return self._repo.addchangegroup(cg, source, url)
78
79 def pushkey(self, namespace, key, old, new):
80 return self._repo.pushkey(namespace, key, old, new)
81
82 def listkeys(self, namespace):
83 return self._repo.listkeys(namespace)
84
85 def debugwireargs(self, one, two, three=None, four=None, five=None):
86 '''used to test argument passing over the wire'''
87 return "%s %s %s %s %s" % (one, two, three, four, five)
88
89 class locallegacypeer(localpeer):
90 '''peer extension which implements legacy methods too; used for tests with
91 restricted capabilities'''
92
93 def __init__(self, repo):
94 localpeer.__init__(self, repo, caps=LEGACYCAPS)
95
96 def branches(self, nodes):
97 return self._repo.branches(nodes)
98
99 def between(self, pairs):
100 return self._repo.between(pairs)
101
102 def changegroup(self, basenodes, source):
103 return self._repo.changegroup(basenodes, source)
104
105 def changegroupsubset(self, bases, heads, source):
106 return self._repo.changegroupsubset(bases, heads, source)
107
108 class localrepository(object):
109
29 supportedformats = set(('revlogv1', 'generaldelta'))
110 supportedformats = set(('revlogv1', 'generaldelta'))
30 supported = supportedformats | set(('store', 'fncache', 'shared',
111 supported = supportedformats | set(('store', 'fncache', 'shared',
31 'dotencode'))
112 'dotencode'))
@@ -36,7 +117,6 b' class localrepository(repo.repository):'
36 return self.requirements[:]
117 return self.requirements[:]
37
118
38 def __init__(self, baseui, path=None, create=False):
119 def __init__(self, baseui, path=None, create=False):
39 repo.repository.__init__(self)
40 self.wopener = scmutil.opener(path, expand=True)
120 self.wopener = scmutil.opener(path, expand=True)
41 self.wvfs = self.wopener
121 self.wvfs = self.wopener
42 self.root = self.wvfs.base
122 self.root = self.wvfs.base
@@ -126,6 +206,12 b' class localrepository(repo.repository):'
126 # Maps a property name to its util.filecacheentry
206 # Maps a property name to its util.filecacheentry
127 self._filecache = {}
207 self._filecache = {}
128
208
209 def close(self):
210 pass
211
212 def _restrictcapabilities(self, caps):
213 return caps
214
129 def _applyrequirements(self, requirements):
215 def _applyrequirements(self, requirements):
130 self.requirements = requirements
216 self.requirements = requirements
131 self.sopener.options = dict((r, 1) for r in requirements
217 self.sopener.options = dict((r, 1) for r in requirements
@@ -175,6 +261,9 b' class localrepository(repo.repository):'
175 parts.pop()
261 parts.pop()
176 return False
262 return False
177
263
264 def peer(self):
265 return localpeer(self) # not cached to avoid reference cycle
266
178 @filecache('bookmarks')
267 @filecache('bookmarks')
179 def _bookmarks(self):
268 def _bookmarks(self):
180 return bookmarks.read(self)
269 return bookmarks.read(self)
@@ -668,6 +757,9 b' class localrepository(repo.repository):'
668 def local(self):
757 def local(self):
669 return self
758 return self
670
759
760 def cancopy(self):
761 return self.local() # so statichttprepo's override of local() works
762
671 def join(self, f):
763 def join(self, f):
672 return os.path.join(self.path, f)
764 return os.path.join(self.path, f)
673
765
@@ -1,4 +1,4 b''
1 # repo.py - repository base classes for mercurial
1 # peer.py - repository base classes for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
@@ -9,16 +9,18 b''
9 from i18n import _
9 from i18n import _
10 import error
10 import error
11
11
12 class repository(object):
12 class peerrepository(object):
13
13 def capable(self, name):
14 def capable(self, name):
14 '''tell whether repo supports named capability.
15 '''tell whether repo supports named capability.
15 return False if not supported.
16 return False if not supported.
16 if boolean capability, return True.
17 if boolean capability, return True.
17 if string capability, return string.'''
18 if string capability, return string.'''
18 if name in self.capabilities:
19 caps = self._capabilities()
20 if name in caps:
19 return True
21 return True
20 name_eq = name + '='
22 name_eq = name + '='
21 for cap in self.capabilities:
23 for cap in caps:
22 if cap.startswith(name_eq):
24 if cap.startswith(name_eq):
23 return cap[len(name_eq):]
25 return cap[len(name_eq):]
24 return False
26 return False
@@ -31,13 +33,17 b' class repository(object):'
31 'support the %r capability') % (purpose, name))
33 'support the %r capability') % (purpose, name))
32
34
33 def local(self):
35 def local(self):
34 return False
36 '''return peer as a localrepo, or None'''
37 return None
38
39 def peer(self):
40 return self
35
41
36 def peer(self):
42 def peer(self):
37 return self
43 return self
38
44
39 def cancopy(self):
45 def cancopy(self):
40 return self.local()
46 return False
41
47
42 def close(self):
48 def close(self):
43 pass
49 pass
@@ -1,4 +1,4 b''
1 # sshrepo.py - ssh repository proxy class for mercurial
1 # sshpeer.py - ssh repository proxy class for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
@@ -25,7 +25,7 b' def _serverquote(s):'
25 return s
25 return s
26 return "'%s'" % s.replace("'", "'\\''")
26 return "'%s'" % s.replace("'", "'\\''")
27
27
28 class sshrepository(wireproto.wirerepository):
28 class sshpeer(wireproto.wirepeer):
29 def __init__(self, ui, path, create=False):
29 def __init__(self, ui, path, create=False):
30 self._url = path
30 self._url = path
31 self.ui = ui
31 self.ui = ui
@@ -90,12 +90,15 b' class sshrepository(wireproto.wirereposi'
90 self._abort(error.RepoError(_('no suitable response from '
90 self._abort(error.RepoError(_('no suitable response from '
91 'remote hg')))
91 'remote hg')))
92
92
93 self.capabilities = set()
93 self._caps = set()
94 for l in reversed(lines):
94 for l in reversed(lines):
95 if l.startswith("capabilities:"):
95 if l.startswith("capabilities:"):
96 self.capabilities.update(l[:-1].split(":")[1].split())
96 self._caps.update(l[:-1].split(":")[1].split())
97 break
97 break
98
98
99 def _capabilities(self):
100 return self._caps
101
99 def readerr(self):
102 def readerr(self):
100 while True:
103 while True:
101 size = util.fstat(self.pipee).st_size
104 size = util.fstat(self.pipee).st_size
@@ -233,4 +236,4 b' class sshrepository(wireproto.wirereposi'
233 except ValueError:
236 except ValueError:
234 self._abort(error.ResponseError(_("unexpected response:"), r))
237 self._abort(error.ResponseError(_("unexpected response:"), r))
235
238
236 instance = sshrepository
239 instance = sshpeer
@@ -76,6 +76,10 b' def build_opener(ui, authinfo):'
76
76
77 return statichttpopener
77 return statichttpopener
78
78
79 class statichttppeer(localrepo.localpeer):
80 def local(self):
81 return None
82
79 class statichttprepository(localrepo.localrepository):
83 class statichttprepository(localrepo.localrepository):
80 def __init__(self, ui, path):
84 def __init__(self, ui, path):
81 self._url = path
85 self._url = path
@@ -116,6 +120,7 b' class statichttprepository(localrepo.loc'
116 self.svfs = self.sopener
120 self.svfs = self.sopener
117 self.sjoin = self.store.join
121 self.sjoin = self.store.join
118 self._filecache = {}
122 self._filecache = {}
123 self.requirements = requirements
119
124
120 self.manifest = manifest.manifest(self.sopener)
125 self.manifest = manifest.manifest(self.sopener)
121 self.changelog = changelog.changelog(self.sopener)
126 self.changelog = changelog.changelog(self.sopener)
@@ -125,7 +130,9 b' class statichttprepository(localrepo.loc'
125 self._branchcachetip = None
130 self._branchcachetip = None
126 self.encodepats = None
131 self.encodepats = None
127 self.decodepats = None
132 self.decodepats = None
128 self.capabilities.difference_update(["pushkey"])
133
134 def _restrictcapabilities(self, caps):
135 return caps.difference(["pushkey"])
129
136
130 def url(self):
137 def url(self):
131 return self._url
138 return self._url
@@ -133,6 +140,9 b' class statichttprepository(localrepo.loc'
133 def local(self):
140 def local(self):
134 return False
141 return False
135
142
143 def peer(self):
144 return statichttppeer(self)
145
136 def lock(self, wait=True):
146 def lock(self, wait=True):
137 raise util.Abort(_('cannot lock static-http repository'))
147 raise util.Abort(_('cannot lock static-http repository'))
138
148
@@ -9,7 +9,7 b' import urllib, tempfile, os, sys'
9 from i18n import _
9 from i18n import _
10 from node import bin, hex
10 from node import bin, hex
11 import changegroup as changegroupmod
11 import changegroup as changegroupmod
12 import repo, error, encoding, util, store
12 import peer, error, encoding, util, store
13 import phases
13 import phases
14
14
15 # abstract batching support
15 # abstract batching support
@@ -149,7 +149,7 b' def unescapearg(escaped):'
149 def todict(**args):
149 def todict(**args):
150 return args
150 return args
151
151
152 class wirerepository(repo.repository):
152 class wirepeer(peer.peerrepository):
153
153
154 def batch(self):
154 def batch(self):
155 return remotebatch(self)
155 return remotebatch(self)
@@ -6,13 +6,18 b' then'
6 fi
6 fi
7
7
8 cat > notcapable-$CAP.py << EOF
8 cat > notcapable-$CAP.py << EOF
9 from mercurial import extensions, repo
9 from mercurial import extensions, peer, localrepo
10 def extsetup():
10 def extsetup():
11 extensions.wrapfunction(repo.repository, 'capable', wrapper)
11 extensions.wrapfunction(peer.peerrepository, 'capable', wrapcapable)
12 def wrapper(orig, self, name, *args, **kwargs):
12 extensions.wrapfunction(localrepo.localrepository, 'peer', wrappeer)
13 def wrapcapable(orig, self, name, *args, **kwargs):
13 if name in '$CAP'.split(' '):
14 if name in '$CAP'.split(' '):
14 return False
15 return False
15 return orig(self, name, *args, **kwargs)
16 return orig(self, name, *args, **kwargs)
17 def wrappeer(orig, self):
18 # Since we're disabling some newer features, we need to make sure local
19 # repos add in the legacy features again.
20 return localrepo.locallegacypeer(self)
16 EOF
21 EOF
17
22
18 echo '[extensions]' >> $HGRCPATH
23 echo '[extensions]' >> $HGRCPATH
@@ -9,7 +9,7 b' class proto(object):'
9 names = spec.split()
9 names = spec.split()
10 return [args[n] for n in names]
10 return [args[n] for n in names]
11
11
12 class clientrepo(wireproto.wirerepository):
12 class clientpeer(wireproto.wirepeer):
13 def __init__(self, serverrepo):
13 def __init__(self, serverrepo):
14 self.serverrepo = serverrepo
14 self.serverrepo = serverrepo
15 def _call(self, cmd, **args):
15 def _call(self, cmd, **args):
@@ -36,7 +36,7 b' def greet(repo, proto, name):'
36 wireproto.commands['greet'] = (greet, 'name',)
36 wireproto.commands['greet'] = (greet, 'name',)
37
37
38 srv = serverrepo()
38 srv = serverrepo()
39 clt = clientrepo(srv)
39 clt = clientpeer(srv)
40
40
41 print clt.greet("Foobar")
41 print clt.greet("Foobar")
42 b = clt.batch()
42 b = clt.batch()
General Comments 0
You need to be logged in to leave comments. Login now