##// END OF EJS Templates
narrow: pass 'narrow_widen' as source while generating changegroup...
Pulkit Goyal -
r39998:fa239565 default
parent child Browse files
Show More
@@ -1,363 +1,361 b''
1 # narrowbundle2.py - bundle2 extensions for narrow repository support
1 # narrowbundle2.py - bundle2 extensions for narrow repository support
2 #
2 #
3 # Copyright 2017 Google, Inc.
3 # Copyright 2017 Google, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import struct
11 import struct
12
12
13 from mercurial.i18n import _
13 from mercurial.i18n import _
14 from mercurial.node import (
14 from mercurial.node import (
15 bin,
15 bin,
16 nullid,
16 nullid,
17 )
17 )
18 from mercurial import (
18 from mercurial import (
19 bundle2,
19 bundle2,
20 changegroup,
20 changegroup,
21 error,
21 error,
22 exchange,
22 exchange,
23 extensions,
23 extensions,
24 match as matchmod,
24 match as matchmod,
25 narrowspec,
25 narrowspec,
26 repair,
26 repair,
27 repository,
27 repository,
28 util,
28 util,
29 wireprototypes,
29 wireprototypes,
30 )
30 )
31 from mercurial.utils import (
31 from mercurial.utils import (
32 stringutil,
32 stringutil,
33 )
33 )
34
34
35 NARROWCAP = 'narrow'
35 NARROWCAP = 'narrow'
36 _NARROWACL_SECTION = 'narrowhgacl'
36 _NARROWACL_SECTION = 'narrowhgacl'
37 _CHANGESPECPART = NARROWCAP + ':changespec'
37 _CHANGESPECPART = NARROWCAP + ':changespec'
38 _SPECPART = NARROWCAP + ':spec'
38 _SPECPART = NARROWCAP + ':spec'
39 _SPECPART_INCLUDE = 'include'
39 _SPECPART_INCLUDE = 'include'
40 _SPECPART_EXCLUDE = 'exclude'
40 _SPECPART_EXCLUDE = 'exclude'
41 _KILLNODESIGNAL = 'KILL'
41 _KILLNODESIGNAL = 'KILL'
42 _DONESIGNAL = 'DONE'
42 _DONESIGNAL = 'DONE'
43 _ELIDEDCSHEADER = '>20s20s20sl' # cset id, p1, p2, len(text)
43 _ELIDEDCSHEADER = '>20s20s20sl' # cset id, p1, p2, len(text)
44 _ELIDEDMFHEADER = '>20s20s20s20sl' # manifest id, p1, p2, link id, len(text)
44 _ELIDEDMFHEADER = '>20s20s20s20sl' # manifest id, p1, p2, link id, len(text)
45 _CSHEADERSIZE = struct.calcsize(_ELIDEDCSHEADER)
45 _CSHEADERSIZE = struct.calcsize(_ELIDEDCSHEADER)
46 _MFHEADERSIZE = struct.calcsize(_ELIDEDMFHEADER)
46 _MFHEADERSIZE = struct.calcsize(_ELIDEDMFHEADER)
47
47
48 # When advertising capabilities, always include narrow clone support.
48 # When advertising capabilities, always include narrow clone support.
49 def getrepocaps_narrow(orig, repo, **kwargs):
49 def getrepocaps_narrow(orig, repo, **kwargs):
50 caps = orig(repo, **kwargs)
50 caps = orig(repo, **kwargs)
51 caps[NARROWCAP] = ['v0']
51 caps[NARROWCAP] = ['v0']
52 return caps
52 return caps
53
53
54 def widen_bundle(repo, diffmatcher, common, known, cgversion, source, ellipses):
54 def widen_bundle(repo, diffmatcher, common, known, cgversion, ellipses):
55 """generates changegroup for widening a narrow clone
55 """generates changegroup for widening a narrow clone
56
56
57 repo is the localrepository instance
57 repo is the localrepository instance
58 diffmatcher is a differencemacther of '(newincludes, newexcludes) -
58 diffmatcher is a differencemacther of '(newincludes, newexcludes) -
59 (oldincludes, oldexcludes)'
59 (oldincludes, oldexcludes)'
60 common is set of common revs between server and client
60 common is set of common revs between server and client
61 known is a set of revs known on the client side (used in ellipses)
61 known is a set of revs known on the client side (used in ellipses)
62 cgversion is the changegroup version to send
62 cgversion is the changegroup version to send
63 source is the command which called this codepath
64 ellipses is boolean value telling whether to send ellipses data or not
63 ellipses is boolean value telling whether to send ellipses data or not
65
64
66 returns changegroup data of the changegroup built or return None if there
65 returns changegroup data of the changegroup built or return None if there
67 are no common revs
66 are no common revs
68 """
67 """
69 # XXX: This patch will start sending bundle2 after couple of patches when
68 # XXX: This patch will start sending bundle2 after couple of patches when
70 # called from the wireprotocol command
69 # called from the wireprotocol command
71 common = repo.revs("::%ln", common)
70 common = repo.revs("::%ln", common)
72 commonnodes = set()
71 commonnodes = set()
73 cl = repo.changelog
72 cl = repo.changelog
74 for c in common:
73 for c in common:
75 commonnodes.add(cl.node(c))
74 commonnodes.add(cl.node(c))
76 if commonnodes:
75 if commonnodes:
77 # XXX: we should only send the filelogs (and treemanifest). user
76 # XXX: we should only send the filelogs (and treemanifest). user
78 # already has the changelog and manifest
77 # already has the changelog and manifest
79 packer = changegroup.getbundler(cgversion, repo,
78 packer = changegroup.getbundler(cgversion, repo,
80 filematcher=diffmatcher,
79 filematcher=diffmatcher,
81 fullnodes=commonnodes)
80 fullnodes=commonnodes)
82 cgdata = packer.generate(set([nullid]), list(commonnodes), False,
81 cgdata = packer.generate(set([nullid]), list(commonnodes), False,
83 source, changelog=False)
82 'narrow_widen', changelog=False)
84
83
85 return cgdata
84 return cgdata
86
85
87 return None
86 return None
88
87
89 def getbundlechangegrouppart_widen(bundler, repo, source, bundlecaps=None,
88 def getbundlechangegrouppart_widen(bundler, repo, source, bundlecaps=None,
90 b2caps=None, heads=None, common=None,
89 b2caps=None, heads=None, common=None,
91 **kwargs):
90 **kwargs):
92 """Handling changegroup changegroup generation on the server when user
91 """Handling changegroup changegroup generation on the server when user
93 is widening their narrowspec"""
92 is widening their narrowspec"""
94
93
95 cgversions = b2caps.get('changegroup')
94 cgversions = b2caps.get('changegroup')
96 if cgversions: # 3.1 and 3.2 ship with an empty value
95 if cgversions: # 3.1 and 3.2 ship with an empty value
97 cgversions = [v for v in cgversions
96 cgversions = [v for v in cgversions
98 if v in changegroup.supportedoutgoingversions(repo)]
97 if v in changegroup.supportedoutgoingversions(repo)]
99 if not cgversions:
98 if not cgversions:
100 raise ValueError(_('no common changegroup version'))
99 raise ValueError(_('no common changegroup version'))
101 version = max(cgversions)
100 version = max(cgversions)
102 else:
101 else:
103 raise ValueError(_("server does not advertise changegroup version,"
102 raise ValueError(_("server does not advertise changegroup version,"
104 " can't negotiate support for ellipsis nodes"))
103 " can't negotiate support for ellipsis nodes"))
105
104
106 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
105 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
107 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
106 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
108 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
107 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
109 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
108 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
110 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
109 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
111 oldmatch = narrowspec.match(repo.root, include=oldinclude,
110 oldmatch = narrowspec.match(repo.root, include=oldinclude,
112 exclude=oldexclude)
111 exclude=oldexclude)
113 diffmatch = matchmod.differencematcher(newmatch, oldmatch)
112 diffmatch = matchmod.differencematcher(newmatch, oldmatch)
114 common = set(common or [nullid])
113 common = set(common or [nullid])
115
114
116 if (oldinclude != include or oldexclude != exclude):
115 if (oldinclude != include or oldexclude != exclude):
117 cgdata = widen_bundle(repo, diffmatch, common, [], version,
116 cgdata = widen_bundle(repo, diffmatch, common, [], version, False)
118 source, False)
119 if cgdata is not None:
117 if cgdata is not None:
120 part = bundler.newpart('changegroup', data=cgdata)
118 part = bundler.newpart('changegroup', data=cgdata)
121 part.addparam('version', version)
119 part.addparam('version', version)
122 if 'treemanifest' in repo.requirements:
120 if 'treemanifest' in repo.requirements:
123 part.addparam('treemanifest', '1')
121 part.addparam('treemanifest', '1')
124
122
125 # Serve a changegroup for a client with a narrow clone.
123 # Serve a changegroup for a client with a narrow clone.
126 def getbundlechangegrouppart_narrow(bundler, repo, source,
124 def getbundlechangegrouppart_narrow(bundler, repo, source,
127 bundlecaps=None, b2caps=None, heads=None,
125 bundlecaps=None, b2caps=None, heads=None,
128 common=None, **kwargs):
126 common=None, **kwargs):
129 assert repo.ui.configbool('experimental', 'narrowservebrokenellipses')
127 assert repo.ui.configbool('experimental', 'narrowservebrokenellipses')
130
128
131 cgversions = b2caps.get('changegroup')
129 cgversions = b2caps.get('changegroup')
132 if cgversions: # 3.1 and 3.2 ship with an empty value
130 if cgversions: # 3.1 and 3.2 ship with an empty value
133 cgversions = [v for v in cgversions
131 cgversions = [v for v in cgversions
134 if v in changegroup.supportedoutgoingversions(repo)]
132 if v in changegroup.supportedoutgoingversions(repo)]
135 if not cgversions:
133 if not cgversions:
136 raise ValueError(_('no common changegroup version'))
134 raise ValueError(_('no common changegroup version'))
137 version = max(cgversions)
135 version = max(cgversions)
138 else:
136 else:
139 raise ValueError(_("server does not advertise changegroup version,"
137 raise ValueError(_("server does not advertise changegroup version,"
140 " can't negotiate support for ellipsis nodes"))
138 " can't negotiate support for ellipsis nodes"))
141
139
142 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
140 include = sorted(filter(bool, kwargs.get(r'includepats', [])))
143 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
141 exclude = sorted(filter(bool, kwargs.get(r'excludepats', [])))
144 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
142 newmatch = narrowspec.match(repo.root, include=include, exclude=exclude)
145
143
146 depth = kwargs.get(r'depth', None)
144 depth = kwargs.get(r'depth', None)
147 if depth is not None:
145 if depth is not None:
148 depth = int(depth)
146 depth = int(depth)
149 if depth < 1:
147 if depth < 1:
150 raise error.Abort(_('depth must be positive, got %d') % depth)
148 raise error.Abort(_('depth must be positive, got %d') % depth)
151
149
152 heads = set(heads or repo.heads())
150 heads = set(heads or repo.heads())
153 common = set(common or [nullid])
151 common = set(common or [nullid])
154 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
152 oldinclude = sorted(filter(bool, kwargs.get(r'oldincludepats', [])))
155 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
153 oldexclude = sorted(filter(bool, kwargs.get(r'oldexcludepats', [])))
156 known = {bin(n) for n in kwargs.get(r'known', [])}
154 known = {bin(n) for n in kwargs.get(r'known', [])}
157 if known and (oldinclude != include or oldexclude != exclude):
155 if known and (oldinclude != include or oldexclude != exclude):
158 # Steps:
156 # Steps:
159 # 1. Send kill for "$known & ::common"
157 # 1. Send kill for "$known & ::common"
160 #
158 #
161 # 2. Send changegroup for ::common
159 # 2. Send changegroup for ::common
162 #
160 #
163 # 3. Proceed.
161 # 3. Proceed.
164 #
162 #
165 # In the future, we can send kills for only the specific
163 # In the future, we can send kills for only the specific
166 # nodes we know should go away or change shape, and then
164 # nodes we know should go away or change shape, and then
167 # send a data stream that tells the client something like this:
165 # send a data stream that tells the client something like this:
168 #
166 #
169 # a) apply this changegroup
167 # a) apply this changegroup
170 # b) apply nodes XXX, YYY, ZZZ that you already have
168 # b) apply nodes XXX, YYY, ZZZ that you already have
171 # c) goto a
169 # c) goto a
172 #
170 #
173 # until they've built up the full new state.
171 # until they've built up the full new state.
174 # Convert to revnums and intersect with "common". The client should
172 # Convert to revnums and intersect with "common". The client should
175 # have made it a subset of "common" already, but let's be safe.
173 # have made it a subset of "common" already, but let's be safe.
176 known = set(repo.revs("%ln & ::%ln", known, common))
174 known = set(repo.revs("%ln & ::%ln", known, common))
177 # TODO: we could send only roots() of this set, and the
175 # TODO: we could send only roots() of this set, and the
178 # list of nodes in common, and the client could work out
176 # list of nodes in common, and the client could work out
179 # what to strip, instead of us explicitly sending every
177 # what to strip, instead of us explicitly sending every
180 # single node.
178 # single node.
181 deadrevs = known
179 deadrevs = known
182 def genkills():
180 def genkills():
183 for r in deadrevs:
181 for r in deadrevs:
184 yield _KILLNODESIGNAL
182 yield _KILLNODESIGNAL
185 yield repo.changelog.node(r)
183 yield repo.changelog.node(r)
186 yield _DONESIGNAL
184 yield _DONESIGNAL
187 bundler.newpart(_CHANGESPECPART, data=genkills())
185 bundler.newpart(_CHANGESPECPART, data=genkills())
188 newvisit, newfull, newellipsis = exchange._computeellipsis(
186 newvisit, newfull, newellipsis = exchange._computeellipsis(
189 repo, set(), common, known, newmatch)
187 repo, set(), common, known, newmatch)
190 if newvisit:
188 if newvisit:
191 packer = changegroup.getbundler(version, repo,
189 packer = changegroup.getbundler(version, repo,
192 filematcher=newmatch,
190 filematcher=newmatch,
193 ellipses=True,
191 ellipses=True,
194 shallow=depth is not None,
192 shallow=depth is not None,
195 ellipsisroots=newellipsis,
193 ellipsisroots=newellipsis,
196 fullnodes=newfull)
194 fullnodes=newfull)
197 cgdata = packer.generate(common, newvisit, False, source)
195 cgdata = packer.generate(common, newvisit, False, 'narrow_widen')
198
196
199 part = bundler.newpart('changegroup', data=cgdata)
197 part = bundler.newpart('changegroup', data=cgdata)
200 part.addparam('version', version)
198 part.addparam('version', version)
201 if 'treemanifest' in repo.requirements:
199 if 'treemanifest' in repo.requirements:
202 part.addparam('treemanifest', '1')
200 part.addparam('treemanifest', '1')
203
201
204 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
202 visitnodes, relevant_nodes, ellipsisroots = exchange._computeellipsis(
205 repo, common, heads, set(), newmatch, depth=depth)
203 repo, common, heads, set(), newmatch, depth=depth)
206
204
207 repo.ui.debug('Found %d relevant revs\n' % len(relevant_nodes))
205 repo.ui.debug('Found %d relevant revs\n' % len(relevant_nodes))
208 if visitnodes:
206 if visitnodes:
209 packer = changegroup.getbundler(version, repo,
207 packer = changegroup.getbundler(version, repo,
210 filematcher=newmatch,
208 filematcher=newmatch,
211 ellipses=True,
209 ellipses=True,
212 shallow=depth is not None,
210 shallow=depth is not None,
213 ellipsisroots=ellipsisroots,
211 ellipsisroots=ellipsisroots,
214 fullnodes=relevant_nodes)
212 fullnodes=relevant_nodes)
215 cgdata = packer.generate(common, visitnodes, False, source)
213 cgdata = packer.generate(common, visitnodes, False, 'narrow_widen')
216
214
217 part = bundler.newpart('changegroup', data=cgdata)
215 part = bundler.newpart('changegroup', data=cgdata)
218 part.addparam('version', version)
216 part.addparam('version', version)
219 if 'treemanifest' in repo.requirements:
217 if 'treemanifest' in repo.requirements:
220 part.addparam('treemanifest', '1')
218 part.addparam('treemanifest', '1')
221
219
222 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE))
220 @bundle2.parthandler(_SPECPART, (_SPECPART_INCLUDE, _SPECPART_EXCLUDE))
223 def _handlechangespec_2(op, inpart):
221 def _handlechangespec_2(op, inpart):
224 includepats = set(inpart.params.get(_SPECPART_INCLUDE, '').splitlines())
222 includepats = set(inpart.params.get(_SPECPART_INCLUDE, '').splitlines())
225 excludepats = set(inpart.params.get(_SPECPART_EXCLUDE, '').splitlines())
223 excludepats = set(inpart.params.get(_SPECPART_EXCLUDE, '').splitlines())
226 narrowspec.validatepatterns(includepats)
224 narrowspec.validatepatterns(includepats)
227 narrowspec.validatepatterns(excludepats)
225 narrowspec.validatepatterns(excludepats)
228
226
229 if not repository.NARROW_REQUIREMENT in op.repo.requirements:
227 if not repository.NARROW_REQUIREMENT in op.repo.requirements:
230 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
228 op.repo.requirements.add(repository.NARROW_REQUIREMENT)
231 op.repo._writerequirements()
229 op.repo._writerequirements()
232 op.repo.setnarrowpats(includepats, excludepats)
230 op.repo.setnarrowpats(includepats, excludepats)
233
231
234 @bundle2.parthandler(_CHANGESPECPART)
232 @bundle2.parthandler(_CHANGESPECPART)
235 def _handlechangespec(op, inpart):
233 def _handlechangespec(op, inpart):
236 repo = op.repo
234 repo = op.repo
237 cl = repo.changelog
235 cl = repo.changelog
238
236
239 # changesets which need to be stripped entirely. either they're no longer
237 # changesets which need to be stripped entirely. either they're no longer
240 # needed in the new narrow spec, or the server is sending a replacement
238 # needed in the new narrow spec, or the server is sending a replacement
241 # in the changegroup part.
239 # in the changegroup part.
242 clkills = set()
240 clkills = set()
243
241
244 # A changespec part contains all the updates to ellipsis nodes
242 # A changespec part contains all the updates to ellipsis nodes
245 # that will happen as a result of widening or narrowing a
243 # that will happen as a result of widening or narrowing a
246 # repo. All the changes that this block encounters are ellipsis
244 # repo. All the changes that this block encounters are ellipsis
247 # nodes or flags to kill an existing ellipsis.
245 # nodes or flags to kill an existing ellipsis.
248 chunksignal = changegroup.readexactly(inpart, 4)
246 chunksignal = changegroup.readexactly(inpart, 4)
249 while chunksignal != _DONESIGNAL:
247 while chunksignal != _DONESIGNAL:
250 if chunksignal == _KILLNODESIGNAL:
248 if chunksignal == _KILLNODESIGNAL:
251 # a node used to be an ellipsis but isn't anymore
249 # a node used to be an ellipsis but isn't anymore
252 ck = changegroup.readexactly(inpart, 20)
250 ck = changegroup.readexactly(inpart, 20)
253 if cl.hasnode(ck):
251 if cl.hasnode(ck):
254 clkills.add(ck)
252 clkills.add(ck)
255 else:
253 else:
256 raise error.Abort(
254 raise error.Abort(
257 _('unexpected changespec node chunk type: %s') % chunksignal)
255 _('unexpected changespec node chunk type: %s') % chunksignal)
258 chunksignal = changegroup.readexactly(inpart, 4)
256 chunksignal = changegroup.readexactly(inpart, 4)
259
257
260 if clkills:
258 if clkills:
261 # preserve bookmarks that repair.strip() would otherwise strip
259 # preserve bookmarks that repair.strip() would otherwise strip
262 bmstore = repo._bookmarks
260 bmstore = repo._bookmarks
263 class dummybmstore(dict):
261 class dummybmstore(dict):
264 def applychanges(self, repo, tr, changes):
262 def applychanges(self, repo, tr, changes):
265 pass
263 pass
266 def recordchange(self, tr): # legacy version
264 def recordchange(self, tr): # legacy version
267 pass
265 pass
268 repo._bookmarks = dummybmstore()
266 repo._bookmarks = dummybmstore()
269 chgrpfile = repair.strip(op.ui, repo, list(clkills), backup=True,
267 chgrpfile = repair.strip(op.ui, repo, list(clkills), backup=True,
270 topic='widen')
268 topic='widen')
271 repo._bookmarks = bmstore
269 repo._bookmarks = bmstore
272 if chgrpfile:
270 if chgrpfile:
273 op._widen_uninterr = repo.ui.uninterruptable()
271 op._widen_uninterr = repo.ui.uninterruptable()
274 op._widen_uninterr.__enter__()
272 op._widen_uninterr.__enter__()
275 # presence of _widen_bundle attribute activates widen handler later
273 # presence of _widen_bundle attribute activates widen handler later
276 op._widen_bundle = chgrpfile
274 op._widen_bundle = chgrpfile
277 # Set the new narrowspec if we're widening. The setnewnarrowpats() method
275 # Set the new narrowspec if we're widening. The setnewnarrowpats() method
278 # will currently always be there when using the core+narrowhg server, but
276 # will currently always be there when using the core+narrowhg server, but
279 # other servers may include a changespec part even when not widening (e.g.
277 # other servers may include a changespec part even when not widening (e.g.
280 # because we're deepening a shallow repo).
278 # because we're deepening a shallow repo).
281 if util.safehasattr(repo, 'setnewnarrowpats'):
279 if util.safehasattr(repo, 'setnewnarrowpats'):
282 repo.setnewnarrowpats()
280 repo.setnewnarrowpats()
283
281
284 def handlechangegroup_widen(op, inpart):
282 def handlechangegroup_widen(op, inpart):
285 """Changegroup exchange handler which restores temporarily-stripped nodes"""
283 """Changegroup exchange handler which restores temporarily-stripped nodes"""
286 # We saved a bundle with stripped node data we must now restore.
284 # We saved a bundle with stripped node data we must now restore.
287 # This approach is based on mercurial/repair.py@6ee26a53c111.
285 # This approach is based on mercurial/repair.py@6ee26a53c111.
288 repo = op.repo
286 repo = op.repo
289 ui = op.ui
287 ui = op.ui
290
288
291 chgrpfile = op._widen_bundle
289 chgrpfile = op._widen_bundle
292 del op._widen_bundle
290 del op._widen_bundle
293 vfs = repo.vfs
291 vfs = repo.vfs
294
292
295 ui.note(_("adding branch\n"))
293 ui.note(_("adding branch\n"))
296 f = vfs.open(chgrpfile, "rb")
294 f = vfs.open(chgrpfile, "rb")
297 try:
295 try:
298 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
296 gen = exchange.readbundle(ui, f, chgrpfile, vfs)
299 if not ui.verbose:
297 if not ui.verbose:
300 # silence internal shuffling chatter
298 # silence internal shuffling chatter
301 ui.pushbuffer()
299 ui.pushbuffer()
302 if isinstance(gen, bundle2.unbundle20):
300 if isinstance(gen, bundle2.unbundle20):
303 with repo.transaction('strip') as tr:
301 with repo.transaction('strip') as tr:
304 bundle2.processbundle(repo, gen, lambda: tr)
302 bundle2.processbundle(repo, gen, lambda: tr)
305 else:
303 else:
306 gen.apply(repo, 'strip', 'bundle:' + vfs.join(chgrpfile), True)
304 gen.apply(repo, 'strip', 'bundle:' + vfs.join(chgrpfile), True)
307 if not ui.verbose:
305 if not ui.verbose:
308 ui.popbuffer()
306 ui.popbuffer()
309 finally:
307 finally:
310 f.close()
308 f.close()
311
309
312 # remove undo files
310 # remove undo files
313 for undovfs, undofile in repo.undofiles():
311 for undovfs, undofile in repo.undofiles():
314 try:
312 try:
315 undovfs.unlink(undofile)
313 undovfs.unlink(undofile)
316 except OSError as e:
314 except OSError as e:
317 if e.errno != errno.ENOENT:
315 if e.errno != errno.ENOENT:
318 ui.warn(_('error removing %s: %s\n') %
316 ui.warn(_('error removing %s: %s\n') %
319 (undovfs.join(undofile), stringutil.forcebytestr(e)))
317 (undovfs.join(undofile), stringutil.forcebytestr(e)))
320
318
321 # Remove partial backup only if there were no exceptions
319 # Remove partial backup only if there were no exceptions
322 op._widen_uninterr.__exit__(None, None, None)
320 op._widen_uninterr.__exit__(None, None, None)
323 vfs.unlink(chgrpfile)
321 vfs.unlink(chgrpfile)
324
322
325 def setup():
323 def setup():
326 """Enable narrow repo support in bundle2-related extension points."""
324 """Enable narrow repo support in bundle2-related extension points."""
327 extensions.wrapfunction(bundle2, 'getrepocaps', getrepocaps_narrow)
325 extensions.wrapfunction(bundle2, 'getrepocaps', getrepocaps_narrow)
328
326
329 getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS
327 getbundleargs = wireprototypes.GETBUNDLE_ARGUMENTS
330
328
331 getbundleargs['narrow'] = 'boolean'
329 getbundleargs['narrow'] = 'boolean'
332 getbundleargs['widen'] = 'boolean'
330 getbundleargs['widen'] = 'boolean'
333 getbundleargs['depth'] = 'plain'
331 getbundleargs['depth'] = 'plain'
334 getbundleargs['oldincludepats'] = 'csv'
332 getbundleargs['oldincludepats'] = 'csv'
335 getbundleargs['oldexcludepats'] = 'csv'
333 getbundleargs['oldexcludepats'] = 'csv'
336 getbundleargs['includepats'] = 'csv'
334 getbundleargs['includepats'] = 'csv'
337 getbundleargs['excludepats'] = 'csv'
335 getbundleargs['excludepats'] = 'csv'
338 getbundleargs['known'] = 'csv'
336 getbundleargs['known'] = 'csv'
339
337
340 # Extend changegroup serving to handle requests from narrow clients.
338 # Extend changegroup serving to handle requests from narrow clients.
341 origcgfn = exchange.getbundle2partsmapping['changegroup']
339 origcgfn = exchange.getbundle2partsmapping['changegroup']
342 def wrappedcgfn(*args, **kwargs):
340 def wrappedcgfn(*args, **kwargs):
343 repo = args[1]
341 repo = args[1]
344 if repo.ui.has_section(_NARROWACL_SECTION):
342 if repo.ui.has_section(_NARROWACL_SECTION):
345 kwargs = exchange.applynarrowacl(repo, kwargs)
343 kwargs = exchange.applynarrowacl(repo, kwargs)
346
344
347 if (kwargs.get(r'narrow', False) and
345 if (kwargs.get(r'narrow', False) and
348 repo.ui.configbool('experimental', 'narrowservebrokenellipses')):
346 repo.ui.configbool('experimental', 'narrowservebrokenellipses')):
349 getbundlechangegrouppart_narrow(*args, **kwargs)
347 getbundlechangegrouppart_narrow(*args, **kwargs)
350 elif kwargs.get(r'widen', False) and kwargs.get(r'narrow', False):
348 elif kwargs.get(r'widen', False) and kwargs.get(r'narrow', False):
351 getbundlechangegrouppart_widen(*args, **kwargs)
349 getbundlechangegrouppart_widen(*args, **kwargs)
352 else:
350 else:
353 origcgfn(*args, **kwargs)
351 origcgfn(*args, **kwargs)
354 exchange.getbundle2partsmapping['changegroup'] = wrappedcgfn
352 exchange.getbundle2partsmapping['changegroup'] = wrappedcgfn
355
353
356 # Extend changegroup receiver so client can fixup after widen requests.
354 # Extend changegroup receiver so client can fixup after widen requests.
357 origcghandler = bundle2.parthandlermapping['changegroup']
355 origcghandler = bundle2.parthandlermapping['changegroup']
358 def wrappedcghandler(op, inpart):
356 def wrappedcghandler(op, inpart):
359 origcghandler(op, inpart)
357 origcghandler(op, inpart)
360 if util.safehasattr(op, '_widen_bundle'):
358 if util.safehasattr(op, '_widen_bundle'):
361 handlechangegroup_widen(op, inpart)
359 handlechangegroup_widen(op, inpart)
362 wrappedcghandler.params = origcghandler.params
360 wrappedcghandler.params = origcghandler.params
363 bundle2.parthandlermapping['changegroup'] = wrappedcghandler
361 bundle2.parthandlermapping['changegroup'] = wrappedcghandler
General Comments 0
You need to be logged in to leave comments. Login now