##// END OF EJS Templates
transaction: include txnname in the hookargs dictionary...
marmoute -
r42062:94faa2e8 default
parent child Browse files
Show More
@@ -1,3087 +1,3087 b''
1 # localrepo.py - read/write repository class for mercurial
1 # localrepo.py - read/write repository class for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
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 hashlib
11 import hashlib
12 import os
12 import os
13 import random
13 import random
14 import sys
14 import sys
15 import time
15 import time
16 import weakref
16 import weakref
17
17
18 from .i18n import _
18 from .i18n import _
19 from .node import (
19 from .node import (
20 bin,
20 bin,
21 hex,
21 hex,
22 nullid,
22 nullid,
23 nullrev,
23 nullrev,
24 short,
24 short,
25 )
25 )
26 from . import (
26 from . import (
27 bookmarks,
27 bookmarks,
28 branchmap,
28 branchmap,
29 bundle2,
29 bundle2,
30 changegroup,
30 changegroup,
31 changelog,
31 changelog,
32 color,
32 color,
33 context,
33 context,
34 dirstate,
34 dirstate,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 filelog,
41 filelog,
42 hook,
42 hook,
43 lock as lockmod,
43 lock as lockmod,
44 manifest,
44 manifest,
45 match as matchmod,
45 match as matchmod,
46 merge as mergemod,
46 merge as mergemod,
47 mergeutil,
47 mergeutil,
48 namespaces,
48 namespaces,
49 narrowspec,
49 narrowspec,
50 obsolete,
50 obsolete,
51 pathutil,
51 pathutil,
52 phases,
52 phases,
53 pushkey,
53 pushkey,
54 pycompat,
54 pycompat,
55 repository,
55 repository,
56 repoview,
56 repoview,
57 revset,
57 revset,
58 revsetlang,
58 revsetlang,
59 scmutil,
59 scmutil,
60 sparse,
60 sparse,
61 store as storemod,
61 store as storemod,
62 subrepoutil,
62 subrepoutil,
63 tags as tagsmod,
63 tags as tagsmod,
64 transaction,
64 transaction,
65 txnutil,
65 txnutil,
66 util,
66 util,
67 vfs as vfsmod,
67 vfs as vfsmod,
68 )
68 )
69 from .utils import (
69 from .utils import (
70 interfaceutil,
70 interfaceutil,
71 procutil,
71 procutil,
72 stringutil,
72 stringutil,
73 )
73 )
74
74
75 from .revlogutils import (
75 from .revlogutils import (
76 constants as revlogconst,
76 constants as revlogconst,
77 )
77 )
78
78
79 release = lockmod.release
79 release = lockmod.release
80 urlerr = util.urlerr
80 urlerr = util.urlerr
81 urlreq = util.urlreq
81 urlreq = util.urlreq
82
82
83 # set of (path, vfs-location) tuples. vfs-location is:
83 # set of (path, vfs-location) tuples. vfs-location is:
84 # - 'plain for vfs relative paths
84 # - 'plain for vfs relative paths
85 # - '' for svfs relative paths
85 # - '' for svfs relative paths
86 _cachedfiles = set()
86 _cachedfiles = set()
87
87
88 class _basefilecache(scmutil.filecache):
88 class _basefilecache(scmutil.filecache):
89 """All filecache usage on repo are done for logic that should be unfiltered
89 """All filecache usage on repo are done for logic that should be unfiltered
90 """
90 """
91 def __get__(self, repo, type=None):
91 def __get__(self, repo, type=None):
92 if repo is None:
92 if repo is None:
93 return self
93 return self
94 # proxy to unfiltered __dict__ since filtered repo has no entry
94 # proxy to unfiltered __dict__ since filtered repo has no entry
95 unfi = repo.unfiltered()
95 unfi = repo.unfiltered()
96 try:
96 try:
97 return unfi.__dict__[self.sname]
97 return unfi.__dict__[self.sname]
98 except KeyError:
98 except KeyError:
99 pass
99 pass
100 return super(_basefilecache, self).__get__(unfi, type)
100 return super(_basefilecache, self).__get__(unfi, type)
101
101
102 def set(self, repo, value):
102 def set(self, repo, value):
103 return super(_basefilecache, self).set(repo.unfiltered(), value)
103 return super(_basefilecache, self).set(repo.unfiltered(), value)
104
104
105 class repofilecache(_basefilecache):
105 class repofilecache(_basefilecache):
106 """filecache for files in .hg but outside of .hg/store"""
106 """filecache for files in .hg but outside of .hg/store"""
107 def __init__(self, *paths):
107 def __init__(self, *paths):
108 super(repofilecache, self).__init__(*paths)
108 super(repofilecache, self).__init__(*paths)
109 for path in paths:
109 for path in paths:
110 _cachedfiles.add((path, 'plain'))
110 _cachedfiles.add((path, 'plain'))
111
111
112 def join(self, obj, fname):
112 def join(self, obj, fname):
113 return obj.vfs.join(fname)
113 return obj.vfs.join(fname)
114
114
115 class storecache(_basefilecache):
115 class storecache(_basefilecache):
116 """filecache for files in the store"""
116 """filecache for files in the store"""
117 def __init__(self, *paths):
117 def __init__(self, *paths):
118 super(storecache, self).__init__(*paths)
118 super(storecache, self).__init__(*paths)
119 for path in paths:
119 for path in paths:
120 _cachedfiles.add((path, ''))
120 _cachedfiles.add((path, ''))
121
121
122 def join(self, obj, fname):
122 def join(self, obj, fname):
123 return obj.sjoin(fname)
123 return obj.sjoin(fname)
124
124
125 def isfilecached(repo, name):
125 def isfilecached(repo, name):
126 """check if a repo has already cached "name" filecache-ed property
126 """check if a repo has already cached "name" filecache-ed property
127
127
128 This returns (cachedobj-or-None, iscached) tuple.
128 This returns (cachedobj-or-None, iscached) tuple.
129 """
129 """
130 cacheentry = repo.unfiltered()._filecache.get(name, None)
130 cacheentry = repo.unfiltered()._filecache.get(name, None)
131 if not cacheentry:
131 if not cacheentry:
132 return None, False
132 return None, False
133 return cacheentry.obj, True
133 return cacheentry.obj, True
134
134
135 class unfilteredpropertycache(util.propertycache):
135 class unfilteredpropertycache(util.propertycache):
136 """propertycache that apply to unfiltered repo only"""
136 """propertycache that apply to unfiltered repo only"""
137
137
138 def __get__(self, repo, type=None):
138 def __get__(self, repo, type=None):
139 unfi = repo.unfiltered()
139 unfi = repo.unfiltered()
140 if unfi is repo:
140 if unfi is repo:
141 return super(unfilteredpropertycache, self).__get__(unfi)
141 return super(unfilteredpropertycache, self).__get__(unfi)
142 return getattr(unfi, self.name)
142 return getattr(unfi, self.name)
143
143
144 class filteredpropertycache(util.propertycache):
144 class filteredpropertycache(util.propertycache):
145 """propertycache that must take filtering in account"""
145 """propertycache that must take filtering in account"""
146
146
147 def cachevalue(self, obj, value):
147 def cachevalue(self, obj, value):
148 object.__setattr__(obj, self.name, value)
148 object.__setattr__(obj, self.name, value)
149
149
150
150
151 def hasunfilteredcache(repo, name):
151 def hasunfilteredcache(repo, name):
152 """check if a repo has an unfilteredpropertycache value for <name>"""
152 """check if a repo has an unfilteredpropertycache value for <name>"""
153 return name in vars(repo.unfiltered())
153 return name in vars(repo.unfiltered())
154
154
155 def unfilteredmethod(orig):
155 def unfilteredmethod(orig):
156 """decorate method that always need to be run on unfiltered version"""
156 """decorate method that always need to be run on unfiltered version"""
157 def wrapper(repo, *args, **kwargs):
157 def wrapper(repo, *args, **kwargs):
158 return orig(repo.unfiltered(), *args, **kwargs)
158 return orig(repo.unfiltered(), *args, **kwargs)
159 return wrapper
159 return wrapper
160
160
161 moderncaps = {'lookup', 'branchmap', 'pushkey', 'known', 'getbundle',
161 moderncaps = {'lookup', 'branchmap', 'pushkey', 'known', 'getbundle',
162 'unbundle'}
162 'unbundle'}
163 legacycaps = moderncaps.union({'changegroupsubset'})
163 legacycaps = moderncaps.union({'changegroupsubset'})
164
164
165 @interfaceutil.implementer(repository.ipeercommandexecutor)
165 @interfaceutil.implementer(repository.ipeercommandexecutor)
166 class localcommandexecutor(object):
166 class localcommandexecutor(object):
167 def __init__(self, peer):
167 def __init__(self, peer):
168 self._peer = peer
168 self._peer = peer
169 self._sent = False
169 self._sent = False
170 self._closed = False
170 self._closed = False
171
171
172 def __enter__(self):
172 def __enter__(self):
173 return self
173 return self
174
174
175 def __exit__(self, exctype, excvalue, exctb):
175 def __exit__(self, exctype, excvalue, exctb):
176 self.close()
176 self.close()
177
177
178 def callcommand(self, command, args):
178 def callcommand(self, command, args):
179 if self._sent:
179 if self._sent:
180 raise error.ProgrammingError('callcommand() cannot be used after '
180 raise error.ProgrammingError('callcommand() cannot be used after '
181 'sendcommands()')
181 'sendcommands()')
182
182
183 if self._closed:
183 if self._closed:
184 raise error.ProgrammingError('callcommand() cannot be used after '
184 raise error.ProgrammingError('callcommand() cannot be used after '
185 'close()')
185 'close()')
186
186
187 # We don't need to support anything fancy. Just call the named
187 # We don't need to support anything fancy. Just call the named
188 # method on the peer and return a resolved future.
188 # method on the peer and return a resolved future.
189 fn = getattr(self._peer, pycompat.sysstr(command))
189 fn = getattr(self._peer, pycompat.sysstr(command))
190
190
191 f = pycompat.futures.Future()
191 f = pycompat.futures.Future()
192
192
193 try:
193 try:
194 result = fn(**pycompat.strkwargs(args))
194 result = fn(**pycompat.strkwargs(args))
195 except Exception:
195 except Exception:
196 pycompat.future_set_exception_info(f, sys.exc_info()[1:])
196 pycompat.future_set_exception_info(f, sys.exc_info()[1:])
197 else:
197 else:
198 f.set_result(result)
198 f.set_result(result)
199
199
200 return f
200 return f
201
201
202 def sendcommands(self):
202 def sendcommands(self):
203 self._sent = True
203 self._sent = True
204
204
205 def close(self):
205 def close(self):
206 self._closed = True
206 self._closed = True
207
207
208 @interfaceutil.implementer(repository.ipeercommands)
208 @interfaceutil.implementer(repository.ipeercommands)
209 class localpeer(repository.peer):
209 class localpeer(repository.peer):
210 '''peer for a local repo; reflects only the most recent API'''
210 '''peer for a local repo; reflects only the most recent API'''
211
211
212 def __init__(self, repo, caps=None):
212 def __init__(self, repo, caps=None):
213 super(localpeer, self).__init__()
213 super(localpeer, self).__init__()
214
214
215 if caps is None:
215 if caps is None:
216 caps = moderncaps.copy()
216 caps = moderncaps.copy()
217 self._repo = repo.filtered('served')
217 self._repo = repo.filtered('served')
218 self.ui = repo.ui
218 self.ui = repo.ui
219 self._caps = repo._restrictcapabilities(caps)
219 self._caps = repo._restrictcapabilities(caps)
220
220
221 # Begin of _basepeer interface.
221 # Begin of _basepeer interface.
222
222
223 def url(self):
223 def url(self):
224 return self._repo.url()
224 return self._repo.url()
225
225
226 def local(self):
226 def local(self):
227 return self._repo
227 return self._repo
228
228
229 def peer(self):
229 def peer(self):
230 return self
230 return self
231
231
232 def canpush(self):
232 def canpush(self):
233 return True
233 return True
234
234
235 def close(self):
235 def close(self):
236 self._repo.close()
236 self._repo.close()
237
237
238 # End of _basepeer interface.
238 # End of _basepeer interface.
239
239
240 # Begin of _basewirecommands interface.
240 # Begin of _basewirecommands interface.
241
241
242 def branchmap(self):
242 def branchmap(self):
243 return self._repo.branchmap()
243 return self._repo.branchmap()
244
244
245 def capabilities(self):
245 def capabilities(self):
246 return self._caps
246 return self._caps
247
247
248 def clonebundles(self):
248 def clonebundles(self):
249 return self._repo.tryread('clonebundles.manifest')
249 return self._repo.tryread('clonebundles.manifest')
250
250
251 def debugwireargs(self, one, two, three=None, four=None, five=None):
251 def debugwireargs(self, one, two, three=None, four=None, five=None):
252 """Used to test argument passing over the wire"""
252 """Used to test argument passing over the wire"""
253 return "%s %s %s %s %s" % (one, two, pycompat.bytestr(three),
253 return "%s %s %s %s %s" % (one, two, pycompat.bytestr(three),
254 pycompat.bytestr(four),
254 pycompat.bytestr(four),
255 pycompat.bytestr(five))
255 pycompat.bytestr(five))
256
256
257 def getbundle(self, source, heads=None, common=None, bundlecaps=None,
257 def getbundle(self, source, heads=None, common=None, bundlecaps=None,
258 **kwargs):
258 **kwargs):
259 chunks = exchange.getbundlechunks(self._repo, source, heads=heads,
259 chunks = exchange.getbundlechunks(self._repo, source, heads=heads,
260 common=common, bundlecaps=bundlecaps,
260 common=common, bundlecaps=bundlecaps,
261 **kwargs)[1]
261 **kwargs)[1]
262 cb = util.chunkbuffer(chunks)
262 cb = util.chunkbuffer(chunks)
263
263
264 if exchange.bundle2requested(bundlecaps):
264 if exchange.bundle2requested(bundlecaps):
265 # When requesting a bundle2, getbundle returns a stream to make the
265 # When requesting a bundle2, getbundle returns a stream to make the
266 # wire level function happier. We need to build a proper object
266 # wire level function happier. We need to build a proper object
267 # from it in local peer.
267 # from it in local peer.
268 return bundle2.getunbundler(self.ui, cb)
268 return bundle2.getunbundler(self.ui, cb)
269 else:
269 else:
270 return changegroup.getunbundler('01', cb, None)
270 return changegroup.getunbundler('01', cb, None)
271
271
272 def heads(self):
272 def heads(self):
273 return self._repo.heads()
273 return self._repo.heads()
274
274
275 def known(self, nodes):
275 def known(self, nodes):
276 return self._repo.known(nodes)
276 return self._repo.known(nodes)
277
277
278 def listkeys(self, namespace):
278 def listkeys(self, namespace):
279 return self._repo.listkeys(namespace)
279 return self._repo.listkeys(namespace)
280
280
281 def lookup(self, key):
281 def lookup(self, key):
282 return self._repo.lookup(key)
282 return self._repo.lookup(key)
283
283
284 def pushkey(self, namespace, key, old, new):
284 def pushkey(self, namespace, key, old, new):
285 return self._repo.pushkey(namespace, key, old, new)
285 return self._repo.pushkey(namespace, key, old, new)
286
286
287 def stream_out(self):
287 def stream_out(self):
288 raise error.Abort(_('cannot perform stream clone against local '
288 raise error.Abort(_('cannot perform stream clone against local '
289 'peer'))
289 'peer'))
290
290
291 def unbundle(self, bundle, heads, url):
291 def unbundle(self, bundle, heads, url):
292 """apply a bundle on a repo
292 """apply a bundle on a repo
293
293
294 This function handles the repo locking itself."""
294 This function handles the repo locking itself."""
295 try:
295 try:
296 try:
296 try:
297 bundle = exchange.readbundle(self.ui, bundle, None)
297 bundle = exchange.readbundle(self.ui, bundle, None)
298 ret = exchange.unbundle(self._repo, bundle, heads, 'push', url)
298 ret = exchange.unbundle(self._repo, bundle, heads, 'push', url)
299 if util.safehasattr(ret, 'getchunks'):
299 if util.safehasattr(ret, 'getchunks'):
300 # This is a bundle20 object, turn it into an unbundler.
300 # This is a bundle20 object, turn it into an unbundler.
301 # This little dance should be dropped eventually when the
301 # This little dance should be dropped eventually when the
302 # API is finally improved.
302 # API is finally improved.
303 stream = util.chunkbuffer(ret.getchunks())
303 stream = util.chunkbuffer(ret.getchunks())
304 ret = bundle2.getunbundler(self.ui, stream)
304 ret = bundle2.getunbundler(self.ui, stream)
305 return ret
305 return ret
306 except Exception as exc:
306 except Exception as exc:
307 # If the exception contains output salvaged from a bundle2
307 # If the exception contains output salvaged from a bundle2
308 # reply, we need to make sure it is printed before continuing
308 # reply, we need to make sure it is printed before continuing
309 # to fail. So we build a bundle2 with such output and consume
309 # to fail. So we build a bundle2 with such output and consume
310 # it directly.
310 # it directly.
311 #
311 #
312 # This is not very elegant but allows a "simple" solution for
312 # This is not very elegant but allows a "simple" solution for
313 # issue4594
313 # issue4594
314 output = getattr(exc, '_bundle2salvagedoutput', ())
314 output = getattr(exc, '_bundle2salvagedoutput', ())
315 if output:
315 if output:
316 bundler = bundle2.bundle20(self._repo.ui)
316 bundler = bundle2.bundle20(self._repo.ui)
317 for out in output:
317 for out in output:
318 bundler.addpart(out)
318 bundler.addpart(out)
319 stream = util.chunkbuffer(bundler.getchunks())
319 stream = util.chunkbuffer(bundler.getchunks())
320 b = bundle2.getunbundler(self.ui, stream)
320 b = bundle2.getunbundler(self.ui, stream)
321 bundle2.processbundle(self._repo, b)
321 bundle2.processbundle(self._repo, b)
322 raise
322 raise
323 except error.PushRaced as exc:
323 except error.PushRaced as exc:
324 raise error.ResponseError(_('push failed:'),
324 raise error.ResponseError(_('push failed:'),
325 stringutil.forcebytestr(exc))
325 stringutil.forcebytestr(exc))
326
326
327 # End of _basewirecommands interface.
327 # End of _basewirecommands interface.
328
328
329 # Begin of peer interface.
329 # Begin of peer interface.
330
330
331 def commandexecutor(self):
331 def commandexecutor(self):
332 return localcommandexecutor(self)
332 return localcommandexecutor(self)
333
333
334 # End of peer interface.
334 # End of peer interface.
335
335
336 @interfaceutil.implementer(repository.ipeerlegacycommands)
336 @interfaceutil.implementer(repository.ipeerlegacycommands)
337 class locallegacypeer(localpeer):
337 class locallegacypeer(localpeer):
338 '''peer extension which implements legacy methods too; used for tests with
338 '''peer extension which implements legacy methods too; used for tests with
339 restricted capabilities'''
339 restricted capabilities'''
340
340
341 def __init__(self, repo):
341 def __init__(self, repo):
342 super(locallegacypeer, self).__init__(repo, caps=legacycaps)
342 super(locallegacypeer, self).__init__(repo, caps=legacycaps)
343
343
344 # Begin of baselegacywirecommands interface.
344 # Begin of baselegacywirecommands interface.
345
345
346 def between(self, pairs):
346 def between(self, pairs):
347 return self._repo.between(pairs)
347 return self._repo.between(pairs)
348
348
349 def branches(self, nodes):
349 def branches(self, nodes):
350 return self._repo.branches(nodes)
350 return self._repo.branches(nodes)
351
351
352 def changegroup(self, nodes, source):
352 def changegroup(self, nodes, source):
353 outgoing = discovery.outgoing(self._repo, missingroots=nodes,
353 outgoing = discovery.outgoing(self._repo, missingroots=nodes,
354 missingheads=self._repo.heads())
354 missingheads=self._repo.heads())
355 return changegroup.makechangegroup(self._repo, outgoing, '01', source)
355 return changegroup.makechangegroup(self._repo, outgoing, '01', source)
356
356
357 def changegroupsubset(self, bases, heads, source):
357 def changegroupsubset(self, bases, heads, source):
358 outgoing = discovery.outgoing(self._repo, missingroots=bases,
358 outgoing = discovery.outgoing(self._repo, missingroots=bases,
359 missingheads=heads)
359 missingheads=heads)
360 return changegroup.makechangegroup(self._repo, outgoing, '01', source)
360 return changegroup.makechangegroup(self._repo, outgoing, '01', source)
361
361
362 # End of baselegacywirecommands interface.
362 # End of baselegacywirecommands interface.
363
363
364 # Increment the sub-version when the revlog v2 format changes to lock out old
364 # Increment the sub-version when the revlog v2 format changes to lock out old
365 # clients.
365 # clients.
366 REVLOGV2_REQUIREMENT = 'exp-revlogv2.1'
366 REVLOGV2_REQUIREMENT = 'exp-revlogv2.1'
367
367
368 # A repository with the sparserevlog feature will have delta chains that
368 # A repository with the sparserevlog feature will have delta chains that
369 # can spread over a larger span. Sparse reading cuts these large spans into
369 # can spread over a larger span. Sparse reading cuts these large spans into
370 # pieces, so that each piece isn't too big.
370 # pieces, so that each piece isn't too big.
371 # Without the sparserevlog capability, reading from the repository could use
371 # Without the sparserevlog capability, reading from the repository could use
372 # huge amounts of memory, because the whole span would be read at once,
372 # huge amounts of memory, because the whole span would be read at once,
373 # including all the intermediate revisions that aren't pertinent for the chain.
373 # including all the intermediate revisions that aren't pertinent for the chain.
374 # This is why once a repository has enabled sparse-read, it becomes required.
374 # This is why once a repository has enabled sparse-read, it becomes required.
375 SPARSEREVLOG_REQUIREMENT = 'sparserevlog'
375 SPARSEREVLOG_REQUIREMENT = 'sparserevlog'
376
376
377 # Functions receiving (ui, features) that extensions can register to impact
377 # Functions receiving (ui, features) that extensions can register to impact
378 # the ability to load repositories with custom requirements. Only
378 # the ability to load repositories with custom requirements. Only
379 # functions defined in loaded extensions are called.
379 # functions defined in loaded extensions are called.
380 #
380 #
381 # The function receives a set of requirement strings that the repository
381 # The function receives a set of requirement strings that the repository
382 # is capable of opening. Functions will typically add elements to the
382 # is capable of opening. Functions will typically add elements to the
383 # set to reflect that the extension knows how to handle that requirements.
383 # set to reflect that the extension knows how to handle that requirements.
384 featuresetupfuncs = set()
384 featuresetupfuncs = set()
385
385
386 def makelocalrepository(baseui, path, intents=None):
386 def makelocalrepository(baseui, path, intents=None):
387 """Create a local repository object.
387 """Create a local repository object.
388
388
389 Given arguments needed to construct a local repository, this function
389 Given arguments needed to construct a local repository, this function
390 performs various early repository loading functionality (such as
390 performs various early repository loading functionality (such as
391 reading the ``.hg/requires`` and ``.hg/hgrc`` files), validates that
391 reading the ``.hg/requires`` and ``.hg/hgrc`` files), validates that
392 the repository can be opened, derives a type suitable for representing
392 the repository can be opened, derives a type suitable for representing
393 that repository, and returns an instance of it.
393 that repository, and returns an instance of it.
394
394
395 The returned object conforms to the ``repository.completelocalrepository``
395 The returned object conforms to the ``repository.completelocalrepository``
396 interface.
396 interface.
397
397
398 The repository type is derived by calling a series of factory functions
398 The repository type is derived by calling a series of factory functions
399 for each aspect/interface of the final repository. These are defined by
399 for each aspect/interface of the final repository. These are defined by
400 ``REPO_INTERFACES``.
400 ``REPO_INTERFACES``.
401
401
402 Each factory function is called to produce a type implementing a specific
402 Each factory function is called to produce a type implementing a specific
403 interface. The cumulative list of returned types will be combined into a
403 interface. The cumulative list of returned types will be combined into a
404 new type and that type will be instantiated to represent the local
404 new type and that type will be instantiated to represent the local
405 repository.
405 repository.
406
406
407 The factory functions each receive various state that may be consulted
407 The factory functions each receive various state that may be consulted
408 as part of deriving a type.
408 as part of deriving a type.
409
409
410 Extensions should wrap these factory functions to customize repository type
410 Extensions should wrap these factory functions to customize repository type
411 creation. Note that an extension's wrapped function may be called even if
411 creation. Note that an extension's wrapped function may be called even if
412 that extension is not loaded for the repo being constructed. Extensions
412 that extension is not loaded for the repo being constructed. Extensions
413 should check if their ``__name__`` appears in the
413 should check if their ``__name__`` appears in the
414 ``extensionmodulenames`` set passed to the factory function and no-op if
414 ``extensionmodulenames`` set passed to the factory function and no-op if
415 not.
415 not.
416 """
416 """
417 ui = baseui.copy()
417 ui = baseui.copy()
418 # Prevent copying repo configuration.
418 # Prevent copying repo configuration.
419 ui.copy = baseui.copy
419 ui.copy = baseui.copy
420
420
421 # Working directory VFS rooted at repository root.
421 # Working directory VFS rooted at repository root.
422 wdirvfs = vfsmod.vfs(path, expandpath=True, realpath=True)
422 wdirvfs = vfsmod.vfs(path, expandpath=True, realpath=True)
423
423
424 # Main VFS for .hg/ directory.
424 # Main VFS for .hg/ directory.
425 hgpath = wdirvfs.join(b'.hg')
425 hgpath = wdirvfs.join(b'.hg')
426 hgvfs = vfsmod.vfs(hgpath, cacheaudited=True)
426 hgvfs = vfsmod.vfs(hgpath, cacheaudited=True)
427
427
428 # The .hg/ path should exist and should be a directory. All other
428 # The .hg/ path should exist and should be a directory. All other
429 # cases are errors.
429 # cases are errors.
430 if not hgvfs.isdir():
430 if not hgvfs.isdir():
431 try:
431 try:
432 hgvfs.stat()
432 hgvfs.stat()
433 except OSError as e:
433 except OSError as e:
434 if e.errno != errno.ENOENT:
434 if e.errno != errno.ENOENT:
435 raise
435 raise
436
436
437 raise error.RepoError(_(b'repository %s not found') % path)
437 raise error.RepoError(_(b'repository %s not found') % path)
438
438
439 # .hg/requires file contains a newline-delimited list of
439 # .hg/requires file contains a newline-delimited list of
440 # features/capabilities the opener (us) must have in order to use
440 # features/capabilities the opener (us) must have in order to use
441 # the repository. This file was introduced in Mercurial 0.9.2,
441 # the repository. This file was introduced in Mercurial 0.9.2,
442 # which means very old repositories may not have one. We assume
442 # which means very old repositories may not have one. We assume
443 # a missing file translates to no requirements.
443 # a missing file translates to no requirements.
444 try:
444 try:
445 requirements = set(hgvfs.read(b'requires').splitlines())
445 requirements = set(hgvfs.read(b'requires').splitlines())
446 except IOError as e:
446 except IOError as e:
447 if e.errno != errno.ENOENT:
447 if e.errno != errno.ENOENT:
448 raise
448 raise
449 requirements = set()
449 requirements = set()
450
450
451 # The .hg/hgrc file may load extensions or contain config options
451 # The .hg/hgrc file may load extensions or contain config options
452 # that influence repository construction. Attempt to load it and
452 # that influence repository construction. Attempt to load it and
453 # process any new extensions that it may have pulled in.
453 # process any new extensions that it may have pulled in.
454 if loadhgrc(ui, wdirvfs, hgvfs, requirements):
454 if loadhgrc(ui, wdirvfs, hgvfs, requirements):
455 afterhgrcload(ui, wdirvfs, hgvfs, requirements)
455 afterhgrcload(ui, wdirvfs, hgvfs, requirements)
456 extensions.loadall(ui)
456 extensions.loadall(ui)
457 extensions.populateui(ui)
457 extensions.populateui(ui)
458
458
459 # Set of module names of extensions loaded for this repository.
459 # Set of module names of extensions loaded for this repository.
460 extensionmodulenames = {m.__name__ for n, m in extensions.extensions(ui)}
460 extensionmodulenames = {m.__name__ for n, m in extensions.extensions(ui)}
461
461
462 supportedrequirements = gathersupportedrequirements(ui)
462 supportedrequirements = gathersupportedrequirements(ui)
463
463
464 # We first validate the requirements are known.
464 # We first validate the requirements are known.
465 ensurerequirementsrecognized(requirements, supportedrequirements)
465 ensurerequirementsrecognized(requirements, supportedrequirements)
466
466
467 # Then we validate that the known set is reasonable to use together.
467 # Then we validate that the known set is reasonable to use together.
468 ensurerequirementscompatible(ui, requirements)
468 ensurerequirementscompatible(ui, requirements)
469
469
470 # TODO there are unhandled edge cases related to opening repositories with
470 # TODO there are unhandled edge cases related to opening repositories with
471 # shared storage. If storage is shared, we should also test for requirements
471 # shared storage. If storage is shared, we should also test for requirements
472 # compatibility in the pointed-to repo. This entails loading the .hg/hgrc in
472 # compatibility in the pointed-to repo. This entails loading the .hg/hgrc in
473 # that repo, as that repo may load extensions needed to open it. This is a
473 # that repo, as that repo may load extensions needed to open it. This is a
474 # bit complicated because we don't want the other hgrc to overwrite settings
474 # bit complicated because we don't want the other hgrc to overwrite settings
475 # in this hgrc.
475 # in this hgrc.
476 #
476 #
477 # This bug is somewhat mitigated by the fact that we copy the .hg/requires
477 # This bug is somewhat mitigated by the fact that we copy the .hg/requires
478 # file when sharing repos. But if a requirement is added after the share is
478 # file when sharing repos. But if a requirement is added after the share is
479 # performed, thereby introducing a new requirement for the opener, we may
479 # performed, thereby introducing a new requirement for the opener, we may
480 # will not see that and could encounter a run-time error interacting with
480 # will not see that and could encounter a run-time error interacting with
481 # that shared store since it has an unknown-to-us requirement.
481 # that shared store since it has an unknown-to-us requirement.
482
482
483 # At this point, we know we should be capable of opening the repository.
483 # At this point, we know we should be capable of opening the repository.
484 # Now get on with doing that.
484 # Now get on with doing that.
485
485
486 features = set()
486 features = set()
487
487
488 # The "store" part of the repository holds versioned data. How it is
488 # The "store" part of the repository holds versioned data. How it is
489 # accessed is determined by various requirements. The ``shared`` or
489 # accessed is determined by various requirements. The ``shared`` or
490 # ``relshared`` requirements indicate the store lives in the path contained
490 # ``relshared`` requirements indicate the store lives in the path contained
491 # in the ``.hg/sharedpath`` file. This is an absolute path for
491 # in the ``.hg/sharedpath`` file. This is an absolute path for
492 # ``shared`` and relative to ``.hg/`` for ``relshared``.
492 # ``shared`` and relative to ``.hg/`` for ``relshared``.
493 if b'shared' in requirements or b'relshared' in requirements:
493 if b'shared' in requirements or b'relshared' in requirements:
494 sharedpath = hgvfs.read(b'sharedpath').rstrip(b'\n')
494 sharedpath = hgvfs.read(b'sharedpath').rstrip(b'\n')
495 if b'relshared' in requirements:
495 if b'relshared' in requirements:
496 sharedpath = hgvfs.join(sharedpath)
496 sharedpath = hgvfs.join(sharedpath)
497
497
498 sharedvfs = vfsmod.vfs(sharedpath, realpath=True)
498 sharedvfs = vfsmod.vfs(sharedpath, realpath=True)
499
499
500 if not sharedvfs.exists():
500 if not sharedvfs.exists():
501 raise error.RepoError(_(b'.hg/sharedpath points to nonexistent '
501 raise error.RepoError(_(b'.hg/sharedpath points to nonexistent '
502 b'directory %s') % sharedvfs.base)
502 b'directory %s') % sharedvfs.base)
503
503
504 features.add(repository.REPO_FEATURE_SHARED_STORAGE)
504 features.add(repository.REPO_FEATURE_SHARED_STORAGE)
505
505
506 storebasepath = sharedvfs.base
506 storebasepath = sharedvfs.base
507 cachepath = sharedvfs.join(b'cache')
507 cachepath = sharedvfs.join(b'cache')
508 else:
508 else:
509 storebasepath = hgvfs.base
509 storebasepath = hgvfs.base
510 cachepath = hgvfs.join(b'cache')
510 cachepath = hgvfs.join(b'cache')
511 wcachepath = hgvfs.join(b'wcache')
511 wcachepath = hgvfs.join(b'wcache')
512
512
513
513
514 # The store has changed over time and the exact layout is dictated by
514 # The store has changed over time and the exact layout is dictated by
515 # requirements. The store interface abstracts differences across all
515 # requirements. The store interface abstracts differences across all
516 # of them.
516 # of them.
517 store = makestore(requirements, storebasepath,
517 store = makestore(requirements, storebasepath,
518 lambda base: vfsmod.vfs(base, cacheaudited=True))
518 lambda base: vfsmod.vfs(base, cacheaudited=True))
519 hgvfs.createmode = store.createmode
519 hgvfs.createmode = store.createmode
520
520
521 storevfs = store.vfs
521 storevfs = store.vfs
522 storevfs.options = resolvestorevfsoptions(ui, requirements, features)
522 storevfs.options = resolvestorevfsoptions(ui, requirements, features)
523
523
524 # The cache vfs is used to manage cache files.
524 # The cache vfs is used to manage cache files.
525 cachevfs = vfsmod.vfs(cachepath, cacheaudited=True)
525 cachevfs = vfsmod.vfs(cachepath, cacheaudited=True)
526 cachevfs.createmode = store.createmode
526 cachevfs.createmode = store.createmode
527 # The cache vfs is used to manage cache files related to the working copy
527 # The cache vfs is used to manage cache files related to the working copy
528 wcachevfs = vfsmod.vfs(wcachepath, cacheaudited=True)
528 wcachevfs = vfsmod.vfs(wcachepath, cacheaudited=True)
529 wcachevfs.createmode = store.createmode
529 wcachevfs.createmode = store.createmode
530
530
531 # Now resolve the type for the repository object. We do this by repeatedly
531 # Now resolve the type for the repository object. We do this by repeatedly
532 # calling a factory function to produces types for specific aspects of the
532 # calling a factory function to produces types for specific aspects of the
533 # repo's operation. The aggregate returned types are used as base classes
533 # repo's operation. The aggregate returned types are used as base classes
534 # for a dynamically-derived type, which will represent our new repository.
534 # for a dynamically-derived type, which will represent our new repository.
535
535
536 bases = []
536 bases = []
537 extrastate = {}
537 extrastate = {}
538
538
539 for iface, fn in REPO_INTERFACES:
539 for iface, fn in REPO_INTERFACES:
540 # We pass all potentially useful state to give extensions tons of
540 # We pass all potentially useful state to give extensions tons of
541 # flexibility.
541 # flexibility.
542 typ = fn()(ui=ui,
542 typ = fn()(ui=ui,
543 intents=intents,
543 intents=intents,
544 requirements=requirements,
544 requirements=requirements,
545 features=features,
545 features=features,
546 wdirvfs=wdirvfs,
546 wdirvfs=wdirvfs,
547 hgvfs=hgvfs,
547 hgvfs=hgvfs,
548 store=store,
548 store=store,
549 storevfs=storevfs,
549 storevfs=storevfs,
550 storeoptions=storevfs.options,
550 storeoptions=storevfs.options,
551 cachevfs=cachevfs,
551 cachevfs=cachevfs,
552 wcachevfs=wcachevfs,
552 wcachevfs=wcachevfs,
553 extensionmodulenames=extensionmodulenames,
553 extensionmodulenames=extensionmodulenames,
554 extrastate=extrastate,
554 extrastate=extrastate,
555 baseclasses=bases)
555 baseclasses=bases)
556
556
557 if not isinstance(typ, type):
557 if not isinstance(typ, type):
558 raise error.ProgrammingError('unable to construct type for %s' %
558 raise error.ProgrammingError('unable to construct type for %s' %
559 iface)
559 iface)
560
560
561 bases.append(typ)
561 bases.append(typ)
562
562
563 # type() allows you to use characters in type names that wouldn't be
563 # type() allows you to use characters in type names that wouldn't be
564 # recognized as Python symbols in source code. We abuse that to add
564 # recognized as Python symbols in source code. We abuse that to add
565 # rich information about our constructed repo.
565 # rich information about our constructed repo.
566 name = pycompat.sysstr(b'derivedrepo:%s<%s>' % (
566 name = pycompat.sysstr(b'derivedrepo:%s<%s>' % (
567 wdirvfs.base,
567 wdirvfs.base,
568 b','.join(sorted(requirements))))
568 b','.join(sorted(requirements))))
569
569
570 cls = type(name, tuple(bases), {})
570 cls = type(name, tuple(bases), {})
571
571
572 return cls(
572 return cls(
573 baseui=baseui,
573 baseui=baseui,
574 ui=ui,
574 ui=ui,
575 origroot=path,
575 origroot=path,
576 wdirvfs=wdirvfs,
576 wdirvfs=wdirvfs,
577 hgvfs=hgvfs,
577 hgvfs=hgvfs,
578 requirements=requirements,
578 requirements=requirements,
579 supportedrequirements=supportedrequirements,
579 supportedrequirements=supportedrequirements,
580 sharedpath=storebasepath,
580 sharedpath=storebasepath,
581 store=store,
581 store=store,
582 cachevfs=cachevfs,
582 cachevfs=cachevfs,
583 wcachevfs=wcachevfs,
583 wcachevfs=wcachevfs,
584 features=features,
584 features=features,
585 intents=intents)
585 intents=intents)
586
586
587 def loadhgrc(ui, wdirvfs, hgvfs, requirements):
587 def loadhgrc(ui, wdirvfs, hgvfs, requirements):
588 """Load hgrc files/content into a ui instance.
588 """Load hgrc files/content into a ui instance.
589
589
590 This is called during repository opening to load any additional
590 This is called during repository opening to load any additional
591 config files or settings relevant to the current repository.
591 config files or settings relevant to the current repository.
592
592
593 Returns a bool indicating whether any additional configs were loaded.
593 Returns a bool indicating whether any additional configs were loaded.
594
594
595 Extensions should monkeypatch this function to modify how per-repo
595 Extensions should monkeypatch this function to modify how per-repo
596 configs are loaded. For example, an extension may wish to pull in
596 configs are loaded. For example, an extension may wish to pull in
597 configs from alternate files or sources.
597 configs from alternate files or sources.
598 """
598 """
599 try:
599 try:
600 ui.readconfig(hgvfs.join(b'hgrc'), root=wdirvfs.base)
600 ui.readconfig(hgvfs.join(b'hgrc'), root=wdirvfs.base)
601 return True
601 return True
602 except IOError:
602 except IOError:
603 return False
603 return False
604
604
605 def afterhgrcload(ui, wdirvfs, hgvfs, requirements):
605 def afterhgrcload(ui, wdirvfs, hgvfs, requirements):
606 """Perform additional actions after .hg/hgrc is loaded.
606 """Perform additional actions after .hg/hgrc is loaded.
607
607
608 This function is called during repository loading immediately after
608 This function is called during repository loading immediately after
609 the .hg/hgrc file is loaded and before per-repo extensions are loaded.
609 the .hg/hgrc file is loaded and before per-repo extensions are loaded.
610
610
611 The function can be used to validate configs, automatically add
611 The function can be used to validate configs, automatically add
612 options (including extensions) based on requirements, etc.
612 options (including extensions) based on requirements, etc.
613 """
613 """
614
614
615 # Map of requirements to list of extensions to load automatically when
615 # Map of requirements to list of extensions to load automatically when
616 # requirement is present.
616 # requirement is present.
617 autoextensions = {
617 autoextensions = {
618 b'largefiles': [b'largefiles'],
618 b'largefiles': [b'largefiles'],
619 b'lfs': [b'lfs'],
619 b'lfs': [b'lfs'],
620 }
620 }
621
621
622 for requirement, names in sorted(autoextensions.items()):
622 for requirement, names in sorted(autoextensions.items()):
623 if requirement not in requirements:
623 if requirement not in requirements:
624 continue
624 continue
625
625
626 for name in names:
626 for name in names:
627 if not ui.hasconfig(b'extensions', name):
627 if not ui.hasconfig(b'extensions', name):
628 ui.setconfig(b'extensions', name, b'', source='autoload')
628 ui.setconfig(b'extensions', name, b'', source='autoload')
629
629
630 def gathersupportedrequirements(ui):
630 def gathersupportedrequirements(ui):
631 """Determine the complete set of recognized requirements."""
631 """Determine the complete set of recognized requirements."""
632 # Start with all requirements supported by this file.
632 # Start with all requirements supported by this file.
633 supported = set(localrepository._basesupported)
633 supported = set(localrepository._basesupported)
634
634
635 # Execute ``featuresetupfuncs`` entries if they belong to an extension
635 # Execute ``featuresetupfuncs`` entries if they belong to an extension
636 # relevant to this ui instance.
636 # relevant to this ui instance.
637 modules = {m.__name__ for n, m in extensions.extensions(ui)}
637 modules = {m.__name__ for n, m in extensions.extensions(ui)}
638
638
639 for fn in featuresetupfuncs:
639 for fn in featuresetupfuncs:
640 if fn.__module__ in modules:
640 if fn.__module__ in modules:
641 fn(ui, supported)
641 fn(ui, supported)
642
642
643 # Add derived requirements from registered compression engines.
643 # Add derived requirements from registered compression engines.
644 for name in util.compengines:
644 for name in util.compengines:
645 engine = util.compengines[name]
645 engine = util.compengines[name]
646 if engine.revlogheader():
646 if engine.revlogheader():
647 supported.add(b'exp-compression-%s' % name)
647 supported.add(b'exp-compression-%s' % name)
648
648
649 return supported
649 return supported
650
650
651 def ensurerequirementsrecognized(requirements, supported):
651 def ensurerequirementsrecognized(requirements, supported):
652 """Validate that a set of local requirements is recognized.
652 """Validate that a set of local requirements is recognized.
653
653
654 Receives a set of requirements. Raises an ``error.RepoError`` if there
654 Receives a set of requirements. Raises an ``error.RepoError`` if there
655 exists any requirement in that set that currently loaded code doesn't
655 exists any requirement in that set that currently loaded code doesn't
656 recognize.
656 recognize.
657
657
658 Returns a set of supported requirements.
658 Returns a set of supported requirements.
659 """
659 """
660 missing = set()
660 missing = set()
661
661
662 for requirement in requirements:
662 for requirement in requirements:
663 if requirement in supported:
663 if requirement in supported:
664 continue
664 continue
665
665
666 if not requirement or not requirement[0:1].isalnum():
666 if not requirement or not requirement[0:1].isalnum():
667 raise error.RequirementError(_(b'.hg/requires file is corrupt'))
667 raise error.RequirementError(_(b'.hg/requires file is corrupt'))
668
668
669 missing.add(requirement)
669 missing.add(requirement)
670
670
671 if missing:
671 if missing:
672 raise error.RequirementError(
672 raise error.RequirementError(
673 _(b'repository requires features unknown to this Mercurial: %s') %
673 _(b'repository requires features unknown to this Mercurial: %s') %
674 b' '.join(sorted(missing)),
674 b' '.join(sorted(missing)),
675 hint=_(b'see https://mercurial-scm.org/wiki/MissingRequirement '
675 hint=_(b'see https://mercurial-scm.org/wiki/MissingRequirement '
676 b'for more information'))
676 b'for more information'))
677
677
678 def ensurerequirementscompatible(ui, requirements):
678 def ensurerequirementscompatible(ui, requirements):
679 """Validates that a set of recognized requirements is mutually compatible.
679 """Validates that a set of recognized requirements is mutually compatible.
680
680
681 Some requirements may not be compatible with others or require
681 Some requirements may not be compatible with others or require
682 config options that aren't enabled. This function is called during
682 config options that aren't enabled. This function is called during
683 repository opening to ensure that the set of requirements needed
683 repository opening to ensure that the set of requirements needed
684 to open a repository is sane and compatible with config options.
684 to open a repository is sane and compatible with config options.
685
685
686 Extensions can monkeypatch this function to perform additional
686 Extensions can monkeypatch this function to perform additional
687 checking.
687 checking.
688
688
689 ``error.RepoError`` should be raised on failure.
689 ``error.RepoError`` should be raised on failure.
690 """
690 """
691 if b'exp-sparse' in requirements and not sparse.enabled:
691 if b'exp-sparse' in requirements and not sparse.enabled:
692 raise error.RepoError(_(b'repository is using sparse feature but '
692 raise error.RepoError(_(b'repository is using sparse feature but '
693 b'sparse is not enabled; enable the '
693 b'sparse is not enabled; enable the '
694 b'"sparse" extensions to access'))
694 b'"sparse" extensions to access'))
695
695
696 def makestore(requirements, path, vfstype):
696 def makestore(requirements, path, vfstype):
697 """Construct a storage object for a repository."""
697 """Construct a storage object for a repository."""
698 if b'store' in requirements:
698 if b'store' in requirements:
699 if b'fncache' in requirements:
699 if b'fncache' in requirements:
700 return storemod.fncachestore(path, vfstype,
700 return storemod.fncachestore(path, vfstype,
701 b'dotencode' in requirements)
701 b'dotencode' in requirements)
702
702
703 return storemod.encodedstore(path, vfstype)
703 return storemod.encodedstore(path, vfstype)
704
704
705 return storemod.basicstore(path, vfstype)
705 return storemod.basicstore(path, vfstype)
706
706
707 def resolvestorevfsoptions(ui, requirements, features):
707 def resolvestorevfsoptions(ui, requirements, features):
708 """Resolve the options to pass to the store vfs opener.
708 """Resolve the options to pass to the store vfs opener.
709
709
710 The returned dict is used to influence behavior of the storage layer.
710 The returned dict is used to influence behavior of the storage layer.
711 """
711 """
712 options = {}
712 options = {}
713
713
714 if b'treemanifest' in requirements:
714 if b'treemanifest' in requirements:
715 options[b'treemanifest'] = True
715 options[b'treemanifest'] = True
716
716
717 # experimental config: format.manifestcachesize
717 # experimental config: format.manifestcachesize
718 manifestcachesize = ui.configint(b'format', b'manifestcachesize')
718 manifestcachesize = ui.configint(b'format', b'manifestcachesize')
719 if manifestcachesize is not None:
719 if manifestcachesize is not None:
720 options[b'manifestcachesize'] = manifestcachesize
720 options[b'manifestcachesize'] = manifestcachesize
721
721
722 # In the absence of another requirement superseding a revlog-related
722 # In the absence of another requirement superseding a revlog-related
723 # requirement, we have to assume the repo is using revlog version 0.
723 # requirement, we have to assume the repo is using revlog version 0.
724 # This revlog format is super old and we don't bother trying to parse
724 # This revlog format is super old and we don't bother trying to parse
725 # opener options for it because those options wouldn't do anything
725 # opener options for it because those options wouldn't do anything
726 # meaningful on such old repos.
726 # meaningful on such old repos.
727 if b'revlogv1' in requirements or REVLOGV2_REQUIREMENT in requirements:
727 if b'revlogv1' in requirements or REVLOGV2_REQUIREMENT in requirements:
728 options.update(resolverevlogstorevfsoptions(ui, requirements, features))
728 options.update(resolverevlogstorevfsoptions(ui, requirements, features))
729
729
730 return options
730 return options
731
731
732 def resolverevlogstorevfsoptions(ui, requirements, features):
732 def resolverevlogstorevfsoptions(ui, requirements, features):
733 """Resolve opener options specific to revlogs."""
733 """Resolve opener options specific to revlogs."""
734
734
735 options = {}
735 options = {}
736 options[b'flagprocessors'] = {}
736 options[b'flagprocessors'] = {}
737
737
738 if b'revlogv1' in requirements:
738 if b'revlogv1' in requirements:
739 options[b'revlogv1'] = True
739 options[b'revlogv1'] = True
740 if REVLOGV2_REQUIREMENT in requirements:
740 if REVLOGV2_REQUIREMENT in requirements:
741 options[b'revlogv2'] = True
741 options[b'revlogv2'] = True
742
742
743 if b'generaldelta' in requirements:
743 if b'generaldelta' in requirements:
744 options[b'generaldelta'] = True
744 options[b'generaldelta'] = True
745
745
746 # experimental config: format.chunkcachesize
746 # experimental config: format.chunkcachesize
747 chunkcachesize = ui.configint(b'format', b'chunkcachesize')
747 chunkcachesize = ui.configint(b'format', b'chunkcachesize')
748 if chunkcachesize is not None:
748 if chunkcachesize is not None:
749 options[b'chunkcachesize'] = chunkcachesize
749 options[b'chunkcachesize'] = chunkcachesize
750
750
751 deltabothparents = ui.configbool(b'storage',
751 deltabothparents = ui.configbool(b'storage',
752 b'revlog.optimize-delta-parent-choice')
752 b'revlog.optimize-delta-parent-choice')
753 options[b'deltabothparents'] = deltabothparents
753 options[b'deltabothparents'] = deltabothparents
754
754
755 lazydelta = ui.configbool(b'storage', b'revlog.reuse-external-delta')
755 lazydelta = ui.configbool(b'storage', b'revlog.reuse-external-delta')
756 lazydeltabase = False
756 lazydeltabase = False
757 if lazydelta:
757 if lazydelta:
758 lazydeltabase = ui.configbool(b'storage',
758 lazydeltabase = ui.configbool(b'storage',
759 b'revlog.reuse-external-delta-parent')
759 b'revlog.reuse-external-delta-parent')
760 if lazydeltabase is None:
760 if lazydeltabase is None:
761 lazydeltabase = not scmutil.gddeltaconfig(ui)
761 lazydeltabase = not scmutil.gddeltaconfig(ui)
762 options[b'lazydelta'] = lazydelta
762 options[b'lazydelta'] = lazydelta
763 options[b'lazydeltabase'] = lazydeltabase
763 options[b'lazydeltabase'] = lazydeltabase
764
764
765 chainspan = ui.configbytes(b'experimental', b'maxdeltachainspan')
765 chainspan = ui.configbytes(b'experimental', b'maxdeltachainspan')
766 if 0 <= chainspan:
766 if 0 <= chainspan:
767 options[b'maxdeltachainspan'] = chainspan
767 options[b'maxdeltachainspan'] = chainspan
768
768
769 mmapindexthreshold = ui.configbytes(b'experimental',
769 mmapindexthreshold = ui.configbytes(b'experimental',
770 b'mmapindexthreshold')
770 b'mmapindexthreshold')
771 if mmapindexthreshold is not None:
771 if mmapindexthreshold is not None:
772 options[b'mmapindexthreshold'] = mmapindexthreshold
772 options[b'mmapindexthreshold'] = mmapindexthreshold
773
773
774 withsparseread = ui.configbool(b'experimental', b'sparse-read')
774 withsparseread = ui.configbool(b'experimental', b'sparse-read')
775 srdensitythres = float(ui.config(b'experimental',
775 srdensitythres = float(ui.config(b'experimental',
776 b'sparse-read.density-threshold'))
776 b'sparse-read.density-threshold'))
777 srmingapsize = ui.configbytes(b'experimental',
777 srmingapsize = ui.configbytes(b'experimental',
778 b'sparse-read.min-gap-size')
778 b'sparse-read.min-gap-size')
779 options[b'with-sparse-read'] = withsparseread
779 options[b'with-sparse-read'] = withsparseread
780 options[b'sparse-read-density-threshold'] = srdensitythres
780 options[b'sparse-read-density-threshold'] = srdensitythres
781 options[b'sparse-read-min-gap-size'] = srmingapsize
781 options[b'sparse-read-min-gap-size'] = srmingapsize
782
782
783 sparserevlog = SPARSEREVLOG_REQUIREMENT in requirements
783 sparserevlog = SPARSEREVLOG_REQUIREMENT in requirements
784 options[b'sparse-revlog'] = sparserevlog
784 options[b'sparse-revlog'] = sparserevlog
785 if sparserevlog:
785 if sparserevlog:
786 options[b'generaldelta'] = True
786 options[b'generaldelta'] = True
787
787
788 maxchainlen = None
788 maxchainlen = None
789 if sparserevlog:
789 if sparserevlog:
790 maxchainlen = revlogconst.SPARSE_REVLOG_MAX_CHAIN_LENGTH
790 maxchainlen = revlogconst.SPARSE_REVLOG_MAX_CHAIN_LENGTH
791 # experimental config: format.maxchainlen
791 # experimental config: format.maxchainlen
792 maxchainlen = ui.configint(b'format', b'maxchainlen', maxchainlen)
792 maxchainlen = ui.configint(b'format', b'maxchainlen', maxchainlen)
793 if maxchainlen is not None:
793 if maxchainlen is not None:
794 options[b'maxchainlen'] = maxchainlen
794 options[b'maxchainlen'] = maxchainlen
795
795
796 for r in requirements:
796 for r in requirements:
797 if r.startswith(b'exp-compression-'):
797 if r.startswith(b'exp-compression-'):
798 options[b'compengine'] = r[len(b'exp-compression-'):]
798 options[b'compengine'] = r[len(b'exp-compression-'):]
799
799
800 if repository.NARROW_REQUIREMENT in requirements:
800 if repository.NARROW_REQUIREMENT in requirements:
801 options[b'enableellipsis'] = True
801 options[b'enableellipsis'] = True
802
802
803 return options
803 return options
804
804
805 def makemain(**kwargs):
805 def makemain(**kwargs):
806 """Produce a type conforming to ``ilocalrepositorymain``."""
806 """Produce a type conforming to ``ilocalrepositorymain``."""
807 return localrepository
807 return localrepository
808
808
809 @interfaceutil.implementer(repository.ilocalrepositoryfilestorage)
809 @interfaceutil.implementer(repository.ilocalrepositoryfilestorage)
810 class revlogfilestorage(object):
810 class revlogfilestorage(object):
811 """File storage when using revlogs."""
811 """File storage when using revlogs."""
812
812
813 def file(self, path):
813 def file(self, path):
814 if path[0] == b'/':
814 if path[0] == b'/':
815 path = path[1:]
815 path = path[1:]
816
816
817 return filelog.filelog(self.svfs, path)
817 return filelog.filelog(self.svfs, path)
818
818
819 @interfaceutil.implementer(repository.ilocalrepositoryfilestorage)
819 @interfaceutil.implementer(repository.ilocalrepositoryfilestorage)
820 class revlognarrowfilestorage(object):
820 class revlognarrowfilestorage(object):
821 """File storage when using revlogs and narrow files."""
821 """File storage when using revlogs and narrow files."""
822
822
823 def file(self, path):
823 def file(self, path):
824 if path[0] == b'/':
824 if path[0] == b'/':
825 path = path[1:]
825 path = path[1:]
826
826
827 return filelog.narrowfilelog(self.svfs, path, self._storenarrowmatch)
827 return filelog.narrowfilelog(self.svfs, path, self._storenarrowmatch)
828
828
829 def makefilestorage(requirements, features, **kwargs):
829 def makefilestorage(requirements, features, **kwargs):
830 """Produce a type conforming to ``ilocalrepositoryfilestorage``."""
830 """Produce a type conforming to ``ilocalrepositoryfilestorage``."""
831 features.add(repository.REPO_FEATURE_REVLOG_FILE_STORAGE)
831 features.add(repository.REPO_FEATURE_REVLOG_FILE_STORAGE)
832 features.add(repository.REPO_FEATURE_STREAM_CLONE)
832 features.add(repository.REPO_FEATURE_STREAM_CLONE)
833
833
834 if repository.NARROW_REQUIREMENT in requirements:
834 if repository.NARROW_REQUIREMENT in requirements:
835 return revlognarrowfilestorage
835 return revlognarrowfilestorage
836 else:
836 else:
837 return revlogfilestorage
837 return revlogfilestorage
838
838
839 # List of repository interfaces and factory functions for them. Each
839 # List of repository interfaces and factory functions for them. Each
840 # will be called in order during ``makelocalrepository()`` to iteratively
840 # will be called in order during ``makelocalrepository()`` to iteratively
841 # derive the final type for a local repository instance. We capture the
841 # derive the final type for a local repository instance. We capture the
842 # function as a lambda so we don't hold a reference and the module-level
842 # function as a lambda so we don't hold a reference and the module-level
843 # functions can be wrapped.
843 # functions can be wrapped.
844 REPO_INTERFACES = [
844 REPO_INTERFACES = [
845 (repository.ilocalrepositorymain, lambda: makemain),
845 (repository.ilocalrepositorymain, lambda: makemain),
846 (repository.ilocalrepositoryfilestorage, lambda: makefilestorage),
846 (repository.ilocalrepositoryfilestorage, lambda: makefilestorage),
847 ]
847 ]
848
848
849 @interfaceutil.implementer(repository.ilocalrepositorymain)
849 @interfaceutil.implementer(repository.ilocalrepositorymain)
850 class localrepository(object):
850 class localrepository(object):
851 """Main class for representing local repositories.
851 """Main class for representing local repositories.
852
852
853 All local repositories are instances of this class.
853 All local repositories are instances of this class.
854
854
855 Constructed on its own, instances of this class are not usable as
855 Constructed on its own, instances of this class are not usable as
856 repository objects. To obtain a usable repository object, call
856 repository objects. To obtain a usable repository object, call
857 ``hg.repository()``, ``localrepo.instance()``, or
857 ``hg.repository()``, ``localrepo.instance()``, or
858 ``localrepo.makelocalrepository()``. The latter is the lowest-level.
858 ``localrepo.makelocalrepository()``. The latter is the lowest-level.
859 ``instance()`` adds support for creating new repositories.
859 ``instance()`` adds support for creating new repositories.
860 ``hg.repository()`` adds more extension integration, including calling
860 ``hg.repository()`` adds more extension integration, including calling
861 ``reposetup()``. Generally speaking, ``hg.repository()`` should be
861 ``reposetup()``. Generally speaking, ``hg.repository()`` should be
862 used.
862 used.
863 """
863 """
864
864
865 # obsolete experimental requirements:
865 # obsolete experimental requirements:
866 # - manifestv2: An experimental new manifest format that allowed
866 # - manifestv2: An experimental new manifest format that allowed
867 # for stem compression of long paths. Experiment ended up not
867 # for stem compression of long paths. Experiment ended up not
868 # being successful (repository sizes went up due to worse delta
868 # being successful (repository sizes went up due to worse delta
869 # chains), and the code was deleted in 4.6.
869 # chains), and the code was deleted in 4.6.
870 supportedformats = {
870 supportedformats = {
871 'revlogv1',
871 'revlogv1',
872 'generaldelta',
872 'generaldelta',
873 'treemanifest',
873 'treemanifest',
874 REVLOGV2_REQUIREMENT,
874 REVLOGV2_REQUIREMENT,
875 SPARSEREVLOG_REQUIREMENT,
875 SPARSEREVLOG_REQUIREMENT,
876 }
876 }
877 _basesupported = supportedformats | {
877 _basesupported = supportedformats | {
878 'store',
878 'store',
879 'fncache',
879 'fncache',
880 'shared',
880 'shared',
881 'relshared',
881 'relshared',
882 'dotencode',
882 'dotencode',
883 'exp-sparse',
883 'exp-sparse',
884 'internal-phase'
884 'internal-phase'
885 }
885 }
886
886
887 # list of prefix for file which can be written without 'wlock'
887 # list of prefix for file which can be written without 'wlock'
888 # Extensions should extend this list when needed
888 # Extensions should extend this list when needed
889 _wlockfreeprefix = {
889 _wlockfreeprefix = {
890 # We migh consider requiring 'wlock' for the next
890 # We migh consider requiring 'wlock' for the next
891 # two, but pretty much all the existing code assume
891 # two, but pretty much all the existing code assume
892 # wlock is not needed so we keep them excluded for
892 # wlock is not needed so we keep them excluded for
893 # now.
893 # now.
894 'hgrc',
894 'hgrc',
895 'requires',
895 'requires',
896 # XXX cache is a complicatged business someone
896 # XXX cache is a complicatged business someone
897 # should investigate this in depth at some point
897 # should investigate this in depth at some point
898 'cache/',
898 'cache/',
899 # XXX shouldn't be dirstate covered by the wlock?
899 # XXX shouldn't be dirstate covered by the wlock?
900 'dirstate',
900 'dirstate',
901 # XXX bisect was still a bit too messy at the time
901 # XXX bisect was still a bit too messy at the time
902 # this changeset was introduced. Someone should fix
902 # this changeset was introduced. Someone should fix
903 # the remainig bit and drop this line
903 # the remainig bit and drop this line
904 'bisect.state',
904 'bisect.state',
905 }
905 }
906
906
907 def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, requirements,
907 def __init__(self, baseui, ui, origroot, wdirvfs, hgvfs, requirements,
908 supportedrequirements, sharedpath, store, cachevfs, wcachevfs,
908 supportedrequirements, sharedpath, store, cachevfs, wcachevfs,
909 features, intents=None):
909 features, intents=None):
910 """Create a new local repository instance.
910 """Create a new local repository instance.
911
911
912 Most callers should use ``hg.repository()``, ``localrepo.instance()``,
912 Most callers should use ``hg.repository()``, ``localrepo.instance()``,
913 or ``localrepo.makelocalrepository()`` for obtaining a new repository
913 or ``localrepo.makelocalrepository()`` for obtaining a new repository
914 object.
914 object.
915
915
916 Arguments:
916 Arguments:
917
917
918 baseui
918 baseui
919 ``ui.ui`` instance that ``ui`` argument was based off of.
919 ``ui.ui`` instance that ``ui`` argument was based off of.
920
920
921 ui
921 ui
922 ``ui.ui`` instance for use by the repository.
922 ``ui.ui`` instance for use by the repository.
923
923
924 origroot
924 origroot
925 ``bytes`` path to working directory root of this repository.
925 ``bytes`` path to working directory root of this repository.
926
926
927 wdirvfs
927 wdirvfs
928 ``vfs.vfs`` rooted at the working directory.
928 ``vfs.vfs`` rooted at the working directory.
929
929
930 hgvfs
930 hgvfs
931 ``vfs.vfs`` rooted at .hg/
931 ``vfs.vfs`` rooted at .hg/
932
932
933 requirements
933 requirements
934 ``set`` of bytestrings representing repository opening requirements.
934 ``set`` of bytestrings representing repository opening requirements.
935
935
936 supportedrequirements
936 supportedrequirements
937 ``set`` of bytestrings representing repository requirements that we
937 ``set`` of bytestrings representing repository requirements that we
938 know how to open. May be a supetset of ``requirements``.
938 know how to open. May be a supetset of ``requirements``.
939
939
940 sharedpath
940 sharedpath
941 ``bytes`` Defining path to storage base directory. Points to a
941 ``bytes`` Defining path to storage base directory. Points to a
942 ``.hg/`` directory somewhere.
942 ``.hg/`` directory somewhere.
943
943
944 store
944 store
945 ``store.basicstore`` (or derived) instance providing access to
945 ``store.basicstore`` (or derived) instance providing access to
946 versioned storage.
946 versioned storage.
947
947
948 cachevfs
948 cachevfs
949 ``vfs.vfs`` used for cache files.
949 ``vfs.vfs`` used for cache files.
950
950
951 wcachevfs
951 wcachevfs
952 ``vfs.vfs`` used for cache files related to the working copy.
952 ``vfs.vfs`` used for cache files related to the working copy.
953
953
954 features
954 features
955 ``set`` of bytestrings defining features/capabilities of this
955 ``set`` of bytestrings defining features/capabilities of this
956 instance.
956 instance.
957
957
958 intents
958 intents
959 ``set`` of system strings indicating what this repo will be used
959 ``set`` of system strings indicating what this repo will be used
960 for.
960 for.
961 """
961 """
962 self.baseui = baseui
962 self.baseui = baseui
963 self.ui = ui
963 self.ui = ui
964 self.origroot = origroot
964 self.origroot = origroot
965 # vfs rooted at working directory.
965 # vfs rooted at working directory.
966 self.wvfs = wdirvfs
966 self.wvfs = wdirvfs
967 self.root = wdirvfs.base
967 self.root = wdirvfs.base
968 # vfs rooted at .hg/. Used to access most non-store paths.
968 # vfs rooted at .hg/. Used to access most non-store paths.
969 self.vfs = hgvfs
969 self.vfs = hgvfs
970 self.path = hgvfs.base
970 self.path = hgvfs.base
971 self.requirements = requirements
971 self.requirements = requirements
972 self.supported = supportedrequirements
972 self.supported = supportedrequirements
973 self.sharedpath = sharedpath
973 self.sharedpath = sharedpath
974 self.store = store
974 self.store = store
975 self.cachevfs = cachevfs
975 self.cachevfs = cachevfs
976 self.wcachevfs = wcachevfs
976 self.wcachevfs = wcachevfs
977 self.features = features
977 self.features = features
978
978
979 self.filtername = None
979 self.filtername = None
980
980
981 if (self.ui.configbool('devel', 'all-warnings') or
981 if (self.ui.configbool('devel', 'all-warnings') or
982 self.ui.configbool('devel', 'check-locks')):
982 self.ui.configbool('devel', 'check-locks')):
983 self.vfs.audit = self._getvfsward(self.vfs.audit)
983 self.vfs.audit = self._getvfsward(self.vfs.audit)
984 # A list of callback to shape the phase if no data were found.
984 # A list of callback to shape the phase if no data were found.
985 # Callback are in the form: func(repo, roots) --> processed root.
985 # Callback are in the form: func(repo, roots) --> processed root.
986 # This list it to be filled by extension during repo setup
986 # This list it to be filled by extension during repo setup
987 self._phasedefaults = []
987 self._phasedefaults = []
988
988
989 color.setup(self.ui)
989 color.setup(self.ui)
990
990
991 self.spath = self.store.path
991 self.spath = self.store.path
992 self.svfs = self.store.vfs
992 self.svfs = self.store.vfs
993 self.sjoin = self.store.join
993 self.sjoin = self.store.join
994 if (self.ui.configbool('devel', 'all-warnings') or
994 if (self.ui.configbool('devel', 'all-warnings') or
995 self.ui.configbool('devel', 'check-locks')):
995 self.ui.configbool('devel', 'check-locks')):
996 if util.safehasattr(self.svfs, 'vfs'): # this is filtervfs
996 if util.safehasattr(self.svfs, 'vfs'): # this is filtervfs
997 self.svfs.vfs.audit = self._getsvfsward(self.svfs.vfs.audit)
997 self.svfs.vfs.audit = self._getsvfsward(self.svfs.vfs.audit)
998 else: # standard vfs
998 else: # standard vfs
999 self.svfs.audit = self._getsvfsward(self.svfs.audit)
999 self.svfs.audit = self._getsvfsward(self.svfs.audit)
1000
1000
1001 self._dirstatevalidatewarned = False
1001 self._dirstatevalidatewarned = False
1002
1002
1003 self._branchcaches = branchmap.BranchMapCache()
1003 self._branchcaches = branchmap.BranchMapCache()
1004 self._revbranchcache = None
1004 self._revbranchcache = None
1005 self._filterpats = {}
1005 self._filterpats = {}
1006 self._datafilters = {}
1006 self._datafilters = {}
1007 self._transref = self._lockref = self._wlockref = None
1007 self._transref = self._lockref = self._wlockref = None
1008
1008
1009 # A cache for various files under .hg/ that tracks file changes,
1009 # A cache for various files under .hg/ that tracks file changes,
1010 # (used by the filecache decorator)
1010 # (used by the filecache decorator)
1011 #
1011 #
1012 # Maps a property name to its util.filecacheentry
1012 # Maps a property name to its util.filecacheentry
1013 self._filecache = {}
1013 self._filecache = {}
1014
1014
1015 # hold sets of revision to be filtered
1015 # hold sets of revision to be filtered
1016 # should be cleared when something might have changed the filter value:
1016 # should be cleared when something might have changed the filter value:
1017 # - new changesets,
1017 # - new changesets,
1018 # - phase change,
1018 # - phase change,
1019 # - new obsolescence marker,
1019 # - new obsolescence marker,
1020 # - working directory parent change,
1020 # - working directory parent change,
1021 # - bookmark changes
1021 # - bookmark changes
1022 self.filteredrevcache = {}
1022 self.filteredrevcache = {}
1023
1023
1024 # post-dirstate-status hooks
1024 # post-dirstate-status hooks
1025 self._postdsstatus = []
1025 self._postdsstatus = []
1026
1026
1027 # generic mapping between names and nodes
1027 # generic mapping between names and nodes
1028 self.names = namespaces.namespaces()
1028 self.names = namespaces.namespaces()
1029
1029
1030 # Key to signature value.
1030 # Key to signature value.
1031 self._sparsesignaturecache = {}
1031 self._sparsesignaturecache = {}
1032 # Signature to cached matcher instance.
1032 # Signature to cached matcher instance.
1033 self._sparsematchercache = {}
1033 self._sparsematchercache = {}
1034
1034
1035 def _getvfsward(self, origfunc):
1035 def _getvfsward(self, origfunc):
1036 """build a ward for self.vfs"""
1036 """build a ward for self.vfs"""
1037 rref = weakref.ref(self)
1037 rref = weakref.ref(self)
1038 def checkvfs(path, mode=None):
1038 def checkvfs(path, mode=None):
1039 ret = origfunc(path, mode=mode)
1039 ret = origfunc(path, mode=mode)
1040 repo = rref()
1040 repo = rref()
1041 if (repo is None
1041 if (repo is None
1042 or not util.safehasattr(repo, '_wlockref')
1042 or not util.safehasattr(repo, '_wlockref')
1043 or not util.safehasattr(repo, '_lockref')):
1043 or not util.safehasattr(repo, '_lockref')):
1044 return
1044 return
1045 if mode in (None, 'r', 'rb'):
1045 if mode in (None, 'r', 'rb'):
1046 return
1046 return
1047 if path.startswith(repo.path):
1047 if path.startswith(repo.path):
1048 # truncate name relative to the repository (.hg)
1048 # truncate name relative to the repository (.hg)
1049 path = path[len(repo.path) + 1:]
1049 path = path[len(repo.path) + 1:]
1050 if path.startswith('cache/'):
1050 if path.startswith('cache/'):
1051 msg = 'accessing cache with vfs instead of cachevfs: "%s"'
1051 msg = 'accessing cache with vfs instead of cachevfs: "%s"'
1052 repo.ui.develwarn(msg % path, stacklevel=3, config="cache-vfs")
1052 repo.ui.develwarn(msg % path, stacklevel=3, config="cache-vfs")
1053 if path.startswith('journal.') or path.startswith('undo.'):
1053 if path.startswith('journal.') or path.startswith('undo.'):
1054 # journal is covered by 'lock'
1054 # journal is covered by 'lock'
1055 if repo._currentlock(repo._lockref) is None:
1055 if repo._currentlock(repo._lockref) is None:
1056 repo.ui.develwarn('write with no lock: "%s"' % path,
1056 repo.ui.develwarn('write with no lock: "%s"' % path,
1057 stacklevel=3, config='check-locks')
1057 stacklevel=3, config='check-locks')
1058 elif repo._currentlock(repo._wlockref) is None:
1058 elif repo._currentlock(repo._wlockref) is None:
1059 # rest of vfs files are covered by 'wlock'
1059 # rest of vfs files are covered by 'wlock'
1060 #
1060 #
1061 # exclude special files
1061 # exclude special files
1062 for prefix in self._wlockfreeprefix:
1062 for prefix in self._wlockfreeprefix:
1063 if path.startswith(prefix):
1063 if path.startswith(prefix):
1064 return
1064 return
1065 repo.ui.develwarn('write with no wlock: "%s"' % path,
1065 repo.ui.develwarn('write with no wlock: "%s"' % path,
1066 stacklevel=3, config='check-locks')
1066 stacklevel=3, config='check-locks')
1067 return ret
1067 return ret
1068 return checkvfs
1068 return checkvfs
1069
1069
1070 def _getsvfsward(self, origfunc):
1070 def _getsvfsward(self, origfunc):
1071 """build a ward for self.svfs"""
1071 """build a ward for self.svfs"""
1072 rref = weakref.ref(self)
1072 rref = weakref.ref(self)
1073 def checksvfs(path, mode=None):
1073 def checksvfs(path, mode=None):
1074 ret = origfunc(path, mode=mode)
1074 ret = origfunc(path, mode=mode)
1075 repo = rref()
1075 repo = rref()
1076 if repo is None or not util.safehasattr(repo, '_lockref'):
1076 if repo is None or not util.safehasattr(repo, '_lockref'):
1077 return
1077 return
1078 if mode in (None, 'r', 'rb'):
1078 if mode in (None, 'r', 'rb'):
1079 return
1079 return
1080 if path.startswith(repo.sharedpath):
1080 if path.startswith(repo.sharedpath):
1081 # truncate name relative to the repository (.hg)
1081 # truncate name relative to the repository (.hg)
1082 path = path[len(repo.sharedpath) + 1:]
1082 path = path[len(repo.sharedpath) + 1:]
1083 if repo._currentlock(repo._lockref) is None:
1083 if repo._currentlock(repo._lockref) is None:
1084 repo.ui.develwarn('write with no lock: "%s"' % path,
1084 repo.ui.develwarn('write with no lock: "%s"' % path,
1085 stacklevel=4)
1085 stacklevel=4)
1086 return ret
1086 return ret
1087 return checksvfs
1087 return checksvfs
1088
1088
1089 def close(self):
1089 def close(self):
1090 self._writecaches()
1090 self._writecaches()
1091
1091
1092 def _writecaches(self):
1092 def _writecaches(self):
1093 if self._revbranchcache:
1093 if self._revbranchcache:
1094 self._revbranchcache.write()
1094 self._revbranchcache.write()
1095
1095
1096 def _restrictcapabilities(self, caps):
1096 def _restrictcapabilities(self, caps):
1097 if self.ui.configbool('experimental', 'bundle2-advertise'):
1097 if self.ui.configbool('experimental', 'bundle2-advertise'):
1098 caps = set(caps)
1098 caps = set(caps)
1099 capsblob = bundle2.encodecaps(bundle2.getrepocaps(self,
1099 capsblob = bundle2.encodecaps(bundle2.getrepocaps(self,
1100 role='client'))
1100 role='client'))
1101 caps.add('bundle2=' + urlreq.quote(capsblob))
1101 caps.add('bundle2=' + urlreq.quote(capsblob))
1102 return caps
1102 return caps
1103
1103
1104 def _writerequirements(self):
1104 def _writerequirements(self):
1105 scmutil.writerequires(self.vfs, self.requirements)
1105 scmutil.writerequires(self.vfs, self.requirements)
1106
1106
1107 # Don't cache auditor/nofsauditor, or you'll end up with reference cycle:
1107 # Don't cache auditor/nofsauditor, or you'll end up with reference cycle:
1108 # self -> auditor -> self._checknested -> self
1108 # self -> auditor -> self._checknested -> self
1109
1109
1110 @property
1110 @property
1111 def auditor(self):
1111 def auditor(self):
1112 # This is only used by context.workingctx.match in order to
1112 # This is only used by context.workingctx.match in order to
1113 # detect files in subrepos.
1113 # detect files in subrepos.
1114 return pathutil.pathauditor(self.root, callback=self._checknested)
1114 return pathutil.pathauditor(self.root, callback=self._checknested)
1115
1115
1116 @property
1116 @property
1117 def nofsauditor(self):
1117 def nofsauditor(self):
1118 # This is only used by context.basectx.match in order to detect
1118 # This is only used by context.basectx.match in order to detect
1119 # files in subrepos.
1119 # files in subrepos.
1120 return pathutil.pathauditor(self.root, callback=self._checknested,
1120 return pathutil.pathauditor(self.root, callback=self._checknested,
1121 realfs=False, cached=True)
1121 realfs=False, cached=True)
1122
1122
1123 def _checknested(self, path):
1123 def _checknested(self, path):
1124 """Determine if path is a legal nested repository."""
1124 """Determine if path is a legal nested repository."""
1125 if not path.startswith(self.root):
1125 if not path.startswith(self.root):
1126 return False
1126 return False
1127 subpath = path[len(self.root) + 1:]
1127 subpath = path[len(self.root) + 1:]
1128 normsubpath = util.pconvert(subpath)
1128 normsubpath = util.pconvert(subpath)
1129
1129
1130 # XXX: Checking against the current working copy is wrong in
1130 # XXX: Checking against the current working copy is wrong in
1131 # the sense that it can reject things like
1131 # the sense that it can reject things like
1132 #
1132 #
1133 # $ hg cat -r 10 sub/x.txt
1133 # $ hg cat -r 10 sub/x.txt
1134 #
1134 #
1135 # if sub/ is no longer a subrepository in the working copy
1135 # if sub/ is no longer a subrepository in the working copy
1136 # parent revision.
1136 # parent revision.
1137 #
1137 #
1138 # However, it can of course also allow things that would have
1138 # However, it can of course also allow things that would have
1139 # been rejected before, such as the above cat command if sub/
1139 # been rejected before, such as the above cat command if sub/
1140 # is a subrepository now, but was a normal directory before.
1140 # is a subrepository now, but was a normal directory before.
1141 # The old path auditor would have rejected by mistake since it
1141 # The old path auditor would have rejected by mistake since it
1142 # panics when it sees sub/.hg/.
1142 # panics when it sees sub/.hg/.
1143 #
1143 #
1144 # All in all, checking against the working copy seems sensible
1144 # All in all, checking against the working copy seems sensible
1145 # since we want to prevent access to nested repositories on
1145 # since we want to prevent access to nested repositories on
1146 # the filesystem *now*.
1146 # the filesystem *now*.
1147 ctx = self[None]
1147 ctx = self[None]
1148 parts = util.splitpath(subpath)
1148 parts = util.splitpath(subpath)
1149 while parts:
1149 while parts:
1150 prefix = '/'.join(parts)
1150 prefix = '/'.join(parts)
1151 if prefix in ctx.substate:
1151 if prefix in ctx.substate:
1152 if prefix == normsubpath:
1152 if prefix == normsubpath:
1153 return True
1153 return True
1154 else:
1154 else:
1155 sub = ctx.sub(prefix)
1155 sub = ctx.sub(prefix)
1156 return sub.checknested(subpath[len(prefix) + 1:])
1156 return sub.checknested(subpath[len(prefix) + 1:])
1157 else:
1157 else:
1158 parts.pop()
1158 parts.pop()
1159 return False
1159 return False
1160
1160
1161 def peer(self):
1161 def peer(self):
1162 return localpeer(self) # not cached to avoid reference cycle
1162 return localpeer(self) # not cached to avoid reference cycle
1163
1163
1164 def unfiltered(self):
1164 def unfiltered(self):
1165 """Return unfiltered version of the repository
1165 """Return unfiltered version of the repository
1166
1166
1167 Intended to be overwritten by filtered repo."""
1167 Intended to be overwritten by filtered repo."""
1168 return self
1168 return self
1169
1169
1170 def filtered(self, name, visibilityexceptions=None):
1170 def filtered(self, name, visibilityexceptions=None):
1171 """Return a filtered version of a repository"""
1171 """Return a filtered version of a repository"""
1172 cls = repoview.newtype(self.unfiltered().__class__)
1172 cls = repoview.newtype(self.unfiltered().__class__)
1173 return cls(self, name, visibilityexceptions)
1173 return cls(self, name, visibilityexceptions)
1174
1174
1175 @repofilecache('bookmarks', 'bookmarks.current')
1175 @repofilecache('bookmarks', 'bookmarks.current')
1176 def _bookmarks(self):
1176 def _bookmarks(self):
1177 return bookmarks.bmstore(self)
1177 return bookmarks.bmstore(self)
1178
1178
1179 @property
1179 @property
1180 def _activebookmark(self):
1180 def _activebookmark(self):
1181 return self._bookmarks.active
1181 return self._bookmarks.active
1182
1182
1183 # _phasesets depend on changelog. what we need is to call
1183 # _phasesets depend on changelog. what we need is to call
1184 # _phasecache.invalidate() if '00changelog.i' was changed, but it
1184 # _phasecache.invalidate() if '00changelog.i' was changed, but it
1185 # can't be easily expressed in filecache mechanism.
1185 # can't be easily expressed in filecache mechanism.
1186 @storecache('phaseroots', '00changelog.i')
1186 @storecache('phaseroots', '00changelog.i')
1187 def _phasecache(self):
1187 def _phasecache(self):
1188 return phases.phasecache(self, self._phasedefaults)
1188 return phases.phasecache(self, self._phasedefaults)
1189
1189
1190 @storecache('obsstore')
1190 @storecache('obsstore')
1191 def obsstore(self):
1191 def obsstore(self):
1192 return obsolete.makestore(self.ui, self)
1192 return obsolete.makestore(self.ui, self)
1193
1193
1194 @storecache('00changelog.i')
1194 @storecache('00changelog.i')
1195 def changelog(self):
1195 def changelog(self):
1196 return changelog.changelog(self.svfs,
1196 return changelog.changelog(self.svfs,
1197 trypending=txnutil.mayhavepending(self.root))
1197 trypending=txnutil.mayhavepending(self.root))
1198
1198
1199 @storecache('00manifest.i')
1199 @storecache('00manifest.i')
1200 def manifestlog(self):
1200 def manifestlog(self):
1201 rootstore = manifest.manifestrevlog(self.svfs)
1201 rootstore = manifest.manifestrevlog(self.svfs)
1202 return manifest.manifestlog(self.svfs, self, rootstore,
1202 return manifest.manifestlog(self.svfs, self, rootstore,
1203 self._storenarrowmatch)
1203 self._storenarrowmatch)
1204
1204
1205 @repofilecache('dirstate')
1205 @repofilecache('dirstate')
1206 def dirstate(self):
1206 def dirstate(self):
1207 return self._makedirstate()
1207 return self._makedirstate()
1208
1208
1209 def _makedirstate(self):
1209 def _makedirstate(self):
1210 """Extension point for wrapping the dirstate per-repo."""
1210 """Extension point for wrapping the dirstate per-repo."""
1211 sparsematchfn = lambda: sparse.matcher(self)
1211 sparsematchfn = lambda: sparse.matcher(self)
1212
1212
1213 return dirstate.dirstate(self.vfs, self.ui, self.root,
1213 return dirstate.dirstate(self.vfs, self.ui, self.root,
1214 self._dirstatevalidate, sparsematchfn)
1214 self._dirstatevalidate, sparsematchfn)
1215
1215
1216 def _dirstatevalidate(self, node):
1216 def _dirstatevalidate(self, node):
1217 try:
1217 try:
1218 self.changelog.rev(node)
1218 self.changelog.rev(node)
1219 return node
1219 return node
1220 except error.LookupError:
1220 except error.LookupError:
1221 if not self._dirstatevalidatewarned:
1221 if not self._dirstatevalidatewarned:
1222 self._dirstatevalidatewarned = True
1222 self._dirstatevalidatewarned = True
1223 self.ui.warn(_("warning: ignoring unknown"
1223 self.ui.warn(_("warning: ignoring unknown"
1224 " working parent %s!\n") % short(node))
1224 " working parent %s!\n") % short(node))
1225 return nullid
1225 return nullid
1226
1226
1227 @storecache(narrowspec.FILENAME)
1227 @storecache(narrowspec.FILENAME)
1228 def narrowpats(self):
1228 def narrowpats(self):
1229 """matcher patterns for this repository's narrowspec
1229 """matcher patterns for this repository's narrowspec
1230
1230
1231 A tuple of (includes, excludes).
1231 A tuple of (includes, excludes).
1232 """
1232 """
1233 return narrowspec.load(self)
1233 return narrowspec.load(self)
1234
1234
1235 @storecache(narrowspec.FILENAME)
1235 @storecache(narrowspec.FILENAME)
1236 def _storenarrowmatch(self):
1236 def _storenarrowmatch(self):
1237 if repository.NARROW_REQUIREMENT not in self.requirements:
1237 if repository.NARROW_REQUIREMENT not in self.requirements:
1238 return matchmod.always()
1238 return matchmod.always()
1239 include, exclude = self.narrowpats
1239 include, exclude = self.narrowpats
1240 return narrowspec.match(self.root, include=include, exclude=exclude)
1240 return narrowspec.match(self.root, include=include, exclude=exclude)
1241
1241
1242 @storecache(narrowspec.FILENAME)
1242 @storecache(narrowspec.FILENAME)
1243 def _narrowmatch(self):
1243 def _narrowmatch(self):
1244 if repository.NARROW_REQUIREMENT not in self.requirements:
1244 if repository.NARROW_REQUIREMENT not in self.requirements:
1245 return matchmod.always()
1245 return matchmod.always()
1246 narrowspec.checkworkingcopynarrowspec(self)
1246 narrowspec.checkworkingcopynarrowspec(self)
1247 include, exclude = self.narrowpats
1247 include, exclude = self.narrowpats
1248 return narrowspec.match(self.root, include=include, exclude=exclude)
1248 return narrowspec.match(self.root, include=include, exclude=exclude)
1249
1249
1250 def narrowmatch(self, match=None, includeexact=False):
1250 def narrowmatch(self, match=None, includeexact=False):
1251 """matcher corresponding the the repo's narrowspec
1251 """matcher corresponding the the repo's narrowspec
1252
1252
1253 If `match` is given, then that will be intersected with the narrow
1253 If `match` is given, then that will be intersected with the narrow
1254 matcher.
1254 matcher.
1255
1255
1256 If `includeexact` is True, then any exact matches from `match` will
1256 If `includeexact` is True, then any exact matches from `match` will
1257 be included even if they're outside the narrowspec.
1257 be included even if they're outside the narrowspec.
1258 """
1258 """
1259 if match:
1259 if match:
1260 if includeexact and not self._narrowmatch.always():
1260 if includeexact and not self._narrowmatch.always():
1261 # do not exclude explicitly-specified paths so that they can
1261 # do not exclude explicitly-specified paths so that they can
1262 # be warned later on
1262 # be warned later on
1263 em = matchmod.exact(match.files())
1263 em = matchmod.exact(match.files())
1264 nm = matchmod.unionmatcher([self._narrowmatch, em])
1264 nm = matchmod.unionmatcher([self._narrowmatch, em])
1265 return matchmod.intersectmatchers(match, nm)
1265 return matchmod.intersectmatchers(match, nm)
1266 return matchmod.intersectmatchers(match, self._narrowmatch)
1266 return matchmod.intersectmatchers(match, self._narrowmatch)
1267 return self._narrowmatch
1267 return self._narrowmatch
1268
1268
1269 def setnarrowpats(self, newincludes, newexcludes):
1269 def setnarrowpats(self, newincludes, newexcludes):
1270 narrowspec.save(self, newincludes, newexcludes)
1270 narrowspec.save(self, newincludes, newexcludes)
1271 self.invalidate(clearfilecache=True)
1271 self.invalidate(clearfilecache=True)
1272
1272
1273 def __getitem__(self, changeid):
1273 def __getitem__(self, changeid):
1274 if changeid is None:
1274 if changeid is None:
1275 return context.workingctx(self)
1275 return context.workingctx(self)
1276 if isinstance(changeid, context.basectx):
1276 if isinstance(changeid, context.basectx):
1277 return changeid
1277 return changeid
1278 if isinstance(changeid, slice):
1278 if isinstance(changeid, slice):
1279 # wdirrev isn't contiguous so the slice shouldn't include it
1279 # wdirrev isn't contiguous so the slice shouldn't include it
1280 return [self[i]
1280 return [self[i]
1281 for i in pycompat.xrange(*changeid.indices(len(self)))
1281 for i in pycompat.xrange(*changeid.indices(len(self)))
1282 if i not in self.changelog.filteredrevs]
1282 if i not in self.changelog.filteredrevs]
1283 try:
1283 try:
1284 if isinstance(changeid, int):
1284 if isinstance(changeid, int):
1285 node = self.changelog.node(changeid)
1285 node = self.changelog.node(changeid)
1286 rev = changeid
1286 rev = changeid
1287 elif changeid == 'null':
1287 elif changeid == 'null':
1288 node = nullid
1288 node = nullid
1289 rev = nullrev
1289 rev = nullrev
1290 elif changeid == 'tip':
1290 elif changeid == 'tip':
1291 node = self.changelog.tip()
1291 node = self.changelog.tip()
1292 rev = self.changelog.rev(node)
1292 rev = self.changelog.rev(node)
1293 elif changeid == '.':
1293 elif changeid == '.':
1294 # this is a hack to delay/avoid loading obsmarkers
1294 # this is a hack to delay/avoid loading obsmarkers
1295 # when we know that '.' won't be hidden
1295 # when we know that '.' won't be hidden
1296 node = self.dirstate.p1()
1296 node = self.dirstate.p1()
1297 rev = self.unfiltered().changelog.rev(node)
1297 rev = self.unfiltered().changelog.rev(node)
1298 elif len(changeid) == 20:
1298 elif len(changeid) == 20:
1299 try:
1299 try:
1300 node = changeid
1300 node = changeid
1301 rev = self.changelog.rev(changeid)
1301 rev = self.changelog.rev(changeid)
1302 except error.FilteredLookupError:
1302 except error.FilteredLookupError:
1303 changeid = hex(changeid) # for the error message
1303 changeid = hex(changeid) # for the error message
1304 raise
1304 raise
1305 except LookupError:
1305 except LookupError:
1306 # check if it might have come from damaged dirstate
1306 # check if it might have come from damaged dirstate
1307 #
1307 #
1308 # XXX we could avoid the unfiltered if we had a recognizable
1308 # XXX we could avoid the unfiltered if we had a recognizable
1309 # exception for filtered changeset access
1309 # exception for filtered changeset access
1310 if (self.local()
1310 if (self.local()
1311 and changeid in self.unfiltered().dirstate.parents()):
1311 and changeid in self.unfiltered().dirstate.parents()):
1312 msg = _("working directory has unknown parent '%s'!")
1312 msg = _("working directory has unknown parent '%s'!")
1313 raise error.Abort(msg % short(changeid))
1313 raise error.Abort(msg % short(changeid))
1314 changeid = hex(changeid) # for the error message
1314 changeid = hex(changeid) # for the error message
1315 raise
1315 raise
1316
1316
1317 elif len(changeid) == 40:
1317 elif len(changeid) == 40:
1318 node = bin(changeid)
1318 node = bin(changeid)
1319 rev = self.changelog.rev(node)
1319 rev = self.changelog.rev(node)
1320 else:
1320 else:
1321 raise error.ProgrammingError(
1321 raise error.ProgrammingError(
1322 "unsupported changeid '%s' of type %s" %
1322 "unsupported changeid '%s' of type %s" %
1323 (changeid, type(changeid)))
1323 (changeid, type(changeid)))
1324
1324
1325 return context.changectx(self, rev, node)
1325 return context.changectx(self, rev, node)
1326
1326
1327 except (error.FilteredIndexError, error.FilteredLookupError):
1327 except (error.FilteredIndexError, error.FilteredLookupError):
1328 raise error.FilteredRepoLookupError(_("filtered revision '%s'")
1328 raise error.FilteredRepoLookupError(_("filtered revision '%s'")
1329 % pycompat.bytestr(changeid))
1329 % pycompat.bytestr(changeid))
1330 except (IndexError, LookupError):
1330 except (IndexError, LookupError):
1331 raise error.RepoLookupError(
1331 raise error.RepoLookupError(
1332 _("unknown revision '%s'") % pycompat.bytestr(changeid))
1332 _("unknown revision '%s'") % pycompat.bytestr(changeid))
1333 except error.WdirUnsupported:
1333 except error.WdirUnsupported:
1334 return context.workingctx(self)
1334 return context.workingctx(self)
1335
1335
1336 def __contains__(self, changeid):
1336 def __contains__(self, changeid):
1337 """True if the given changeid exists
1337 """True if the given changeid exists
1338
1338
1339 error.AmbiguousPrefixLookupError is raised if an ambiguous node
1339 error.AmbiguousPrefixLookupError is raised if an ambiguous node
1340 specified.
1340 specified.
1341 """
1341 """
1342 try:
1342 try:
1343 self[changeid]
1343 self[changeid]
1344 return True
1344 return True
1345 except error.RepoLookupError:
1345 except error.RepoLookupError:
1346 return False
1346 return False
1347
1347
1348 def __nonzero__(self):
1348 def __nonzero__(self):
1349 return True
1349 return True
1350
1350
1351 __bool__ = __nonzero__
1351 __bool__ = __nonzero__
1352
1352
1353 def __len__(self):
1353 def __len__(self):
1354 # no need to pay the cost of repoview.changelog
1354 # no need to pay the cost of repoview.changelog
1355 unfi = self.unfiltered()
1355 unfi = self.unfiltered()
1356 return len(unfi.changelog)
1356 return len(unfi.changelog)
1357
1357
1358 def __iter__(self):
1358 def __iter__(self):
1359 return iter(self.changelog)
1359 return iter(self.changelog)
1360
1360
1361 def revs(self, expr, *args):
1361 def revs(self, expr, *args):
1362 '''Find revisions matching a revset.
1362 '''Find revisions matching a revset.
1363
1363
1364 The revset is specified as a string ``expr`` that may contain
1364 The revset is specified as a string ``expr`` that may contain
1365 %-formatting to escape certain types. See ``revsetlang.formatspec``.
1365 %-formatting to escape certain types. See ``revsetlang.formatspec``.
1366
1366
1367 Revset aliases from the configuration are not expanded. To expand
1367 Revset aliases from the configuration are not expanded. To expand
1368 user aliases, consider calling ``scmutil.revrange()`` or
1368 user aliases, consider calling ``scmutil.revrange()`` or
1369 ``repo.anyrevs([expr], user=True)``.
1369 ``repo.anyrevs([expr], user=True)``.
1370
1370
1371 Returns a revset.abstractsmartset, which is a list-like interface
1371 Returns a revset.abstractsmartset, which is a list-like interface
1372 that contains integer revisions.
1372 that contains integer revisions.
1373 '''
1373 '''
1374 tree = revsetlang.spectree(expr, *args)
1374 tree = revsetlang.spectree(expr, *args)
1375 return revset.makematcher(tree)(self)
1375 return revset.makematcher(tree)(self)
1376
1376
1377 def set(self, expr, *args):
1377 def set(self, expr, *args):
1378 '''Find revisions matching a revset and emit changectx instances.
1378 '''Find revisions matching a revset and emit changectx instances.
1379
1379
1380 This is a convenience wrapper around ``revs()`` that iterates the
1380 This is a convenience wrapper around ``revs()`` that iterates the
1381 result and is a generator of changectx instances.
1381 result and is a generator of changectx instances.
1382
1382
1383 Revset aliases from the configuration are not expanded. To expand
1383 Revset aliases from the configuration are not expanded. To expand
1384 user aliases, consider calling ``scmutil.revrange()``.
1384 user aliases, consider calling ``scmutil.revrange()``.
1385 '''
1385 '''
1386 for r in self.revs(expr, *args):
1386 for r in self.revs(expr, *args):
1387 yield self[r]
1387 yield self[r]
1388
1388
1389 def anyrevs(self, specs, user=False, localalias=None):
1389 def anyrevs(self, specs, user=False, localalias=None):
1390 '''Find revisions matching one of the given revsets.
1390 '''Find revisions matching one of the given revsets.
1391
1391
1392 Revset aliases from the configuration are not expanded by default. To
1392 Revset aliases from the configuration are not expanded by default. To
1393 expand user aliases, specify ``user=True``. To provide some local
1393 expand user aliases, specify ``user=True``. To provide some local
1394 definitions overriding user aliases, set ``localalias`` to
1394 definitions overriding user aliases, set ``localalias`` to
1395 ``{name: definitionstring}``.
1395 ``{name: definitionstring}``.
1396 '''
1396 '''
1397 if user:
1397 if user:
1398 m = revset.matchany(self.ui, specs,
1398 m = revset.matchany(self.ui, specs,
1399 lookup=revset.lookupfn(self),
1399 lookup=revset.lookupfn(self),
1400 localalias=localalias)
1400 localalias=localalias)
1401 else:
1401 else:
1402 m = revset.matchany(None, specs, localalias=localalias)
1402 m = revset.matchany(None, specs, localalias=localalias)
1403 return m(self)
1403 return m(self)
1404
1404
1405 def url(self):
1405 def url(self):
1406 return 'file:' + self.root
1406 return 'file:' + self.root
1407
1407
1408 def hook(self, name, throw=False, **args):
1408 def hook(self, name, throw=False, **args):
1409 """Call a hook, passing this repo instance.
1409 """Call a hook, passing this repo instance.
1410
1410
1411 This a convenience method to aid invoking hooks. Extensions likely
1411 This a convenience method to aid invoking hooks. Extensions likely
1412 won't call this unless they have registered a custom hook or are
1412 won't call this unless they have registered a custom hook or are
1413 replacing code that is expected to call a hook.
1413 replacing code that is expected to call a hook.
1414 """
1414 """
1415 return hook.hook(self.ui, self, name, throw, **args)
1415 return hook.hook(self.ui, self, name, throw, **args)
1416
1416
1417 @filteredpropertycache
1417 @filteredpropertycache
1418 def _tagscache(self):
1418 def _tagscache(self):
1419 '''Returns a tagscache object that contains various tags related
1419 '''Returns a tagscache object that contains various tags related
1420 caches.'''
1420 caches.'''
1421
1421
1422 # This simplifies its cache management by having one decorated
1422 # This simplifies its cache management by having one decorated
1423 # function (this one) and the rest simply fetch things from it.
1423 # function (this one) and the rest simply fetch things from it.
1424 class tagscache(object):
1424 class tagscache(object):
1425 def __init__(self):
1425 def __init__(self):
1426 # These two define the set of tags for this repository. tags
1426 # These two define the set of tags for this repository. tags
1427 # maps tag name to node; tagtypes maps tag name to 'global' or
1427 # maps tag name to node; tagtypes maps tag name to 'global' or
1428 # 'local'. (Global tags are defined by .hgtags across all
1428 # 'local'. (Global tags are defined by .hgtags across all
1429 # heads, and local tags are defined in .hg/localtags.)
1429 # heads, and local tags are defined in .hg/localtags.)
1430 # They constitute the in-memory cache of tags.
1430 # They constitute the in-memory cache of tags.
1431 self.tags = self.tagtypes = None
1431 self.tags = self.tagtypes = None
1432
1432
1433 self.nodetagscache = self.tagslist = None
1433 self.nodetagscache = self.tagslist = None
1434
1434
1435 cache = tagscache()
1435 cache = tagscache()
1436 cache.tags, cache.tagtypes = self._findtags()
1436 cache.tags, cache.tagtypes = self._findtags()
1437
1437
1438 return cache
1438 return cache
1439
1439
1440 def tags(self):
1440 def tags(self):
1441 '''return a mapping of tag to node'''
1441 '''return a mapping of tag to node'''
1442 t = {}
1442 t = {}
1443 if self.changelog.filteredrevs:
1443 if self.changelog.filteredrevs:
1444 tags, tt = self._findtags()
1444 tags, tt = self._findtags()
1445 else:
1445 else:
1446 tags = self._tagscache.tags
1446 tags = self._tagscache.tags
1447 rev = self.changelog.rev
1447 rev = self.changelog.rev
1448 for k, v in tags.iteritems():
1448 for k, v in tags.iteritems():
1449 try:
1449 try:
1450 # ignore tags to unknown nodes
1450 # ignore tags to unknown nodes
1451 rev(v)
1451 rev(v)
1452 t[k] = v
1452 t[k] = v
1453 except (error.LookupError, ValueError):
1453 except (error.LookupError, ValueError):
1454 pass
1454 pass
1455 return t
1455 return t
1456
1456
1457 def _findtags(self):
1457 def _findtags(self):
1458 '''Do the hard work of finding tags. Return a pair of dicts
1458 '''Do the hard work of finding tags. Return a pair of dicts
1459 (tags, tagtypes) where tags maps tag name to node, and tagtypes
1459 (tags, tagtypes) where tags maps tag name to node, and tagtypes
1460 maps tag name to a string like \'global\' or \'local\'.
1460 maps tag name to a string like \'global\' or \'local\'.
1461 Subclasses or extensions are free to add their own tags, but
1461 Subclasses or extensions are free to add their own tags, but
1462 should be aware that the returned dicts will be retained for the
1462 should be aware that the returned dicts will be retained for the
1463 duration of the localrepo object.'''
1463 duration of the localrepo object.'''
1464
1464
1465 # XXX what tagtype should subclasses/extensions use? Currently
1465 # XXX what tagtype should subclasses/extensions use? Currently
1466 # mq and bookmarks add tags, but do not set the tagtype at all.
1466 # mq and bookmarks add tags, but do not set the tagtype at all.
1467 # Should each extension invent its own tag type? Should there
1467 # Should each extension invent its own tag type? Should there
1468 # be one tagtype for all such "virtual" tags? Or is the status
1468 # be one tagtype for all such "virtual" tags? Or is the status
1469 # quo fine?
1469 # quo fine?
1470
1470
1471
1471
1472 # map tag name to (node, hist)
1472 # map tag name to (node, hist)
1473 alltags = tagsmod.findglobaltags(self.ui, self)
1473 alltags = tagsmod.findglobaltags(self.ui, self)
1474 # map tag name to tag type
1474 # map tag name to tag type
1475 tagtypes = dict((tag, 'global') for tag in alltags)
1475 tagtypes = dict((tag, 'global') for tag in alltags)
1476
1476
1477 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
1477 tagsmod.readlocaltags(self.ui, self, alltags, tagtypes)
1478
1478
1479 # Build the return dicts. Have to re-encode tag names because
1479 # Build the return dicts. Have to re-encode tag names because
1480 # the tags module always uses UTF-8 (in order not to lose info
1480 # the tags module always uses UTF-8 (in order not to lose info
1481 # writing to the cache), but the rest of Mercurial wants them in
1481 # writing to the cache), but the rest of Mercurial wants them in
1482 # local encoding.
1482 # local encoding.
1483 tags = {}
1483 tags = {}
1484 for (name, (node, hist)) in alltags.iteritems():
1484 for (name, (node, hist)) in alltags.iteritems():
1485 if node != nullid:
1485 if node != nullid:
1486 tags[encoding.tolocal(name)] = node
1486 tags[encoding.tolocal(name)] = node
1487 tags['tip'] = self.changelog.tip()
1487 tags['tip'] = self.changelog.tip()
1488 tagtypes = dict([(encoding.tolocal(name), value)
1488 tagtypes = dict([(encoding.tolocal(name), value)
1489 for (name, value) in tagtypes.iteritems()])
1489 for (name, value) in tagtypes.iteritems()])
1490 return (tags, tagtypes)
1490 return (tags, tagtypes)
1491
1491
1492 def tagtype(self, tagname):
1492 def tagtype(self, tagname):
1493 '''
1493 '''
1494 return the type of the given tag. result can be:
1494 return the type of the given tag. result can be:
1495
1495
1496 'local' : a local tag
1496 'local' : a local tag
1497 'global' : a global tag
1497 'global' : a global tag
1498 None : tag does not exist
1498 None : tag does not exist
1499 '''
1499 '''
1500
1500
1501 return self._tagscache.tagtypes.get(tagname)
1501 return self._tagscache.tagtypes.get(tagname)
1502
1502
1503 def tagslist(self):
1503 def tagslist(self):
1504 '''return a list of tags ordered by revision'''
1504 '''return a list of tags ordered by revision'''
1505 if not self._tagscache.tagslist:
1505 if not self._tagscache.tagslist:
1506 l = []
1506 l = []
1507 for t, n in self.tags().iteritems():
1507 for t, n in self.tags().iteritems():
1508 l.append((self.changelog.rev(n), t, n))
1508 l.append((self.changelog.rev(n), t, n))
1509 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
1509 self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)]
1510
1510
1511 return self._tagscache.tagslist
1511 return self._tagscache.tagslist
1512
1512
1513 def nodetags(self, node):
1513 def nodetags(self, node):
1514 '''return the tags associated with a node'''
1514 '''return the tags associated with a node'''
1515 if not self._tagscache.nodetagscache:
1515 if not self._tagscache.nodetagscache:
1516 nodetagscache = {}
1516 nodetagscache = {}
1517 for t, n in self._tagscache.tags.iteritems():
1517 for t, n in self._tagscache.tags.iteritems():
1518 nodetagscache.setdefault(n, []).append(t)
1518 nodetagscache.setdefault(n, []).append(t)
1519 for tags in nodetagscache.itervalues():
1519 for tags in nodetagscache.itervalues():
1520 tags.sort()
1520 tags.sort()
1521 self._tagscache.nodetagscache = nodetagscache
1521 self._tagscache.nodetagscache = nodetagscache
1522 return self._tagscache.nodetagscache.get(node, [])
1522 return self._tagscache.nodetagscache.get(node, [])
1523
1523
1524 def nodebookmarks(self, node):
1524 def nodebookmarks(self, node):
1525 """return the list of bookmarks pointing to the specified node"""
1525 """return the list of bookmarks pointing to the specified node"""
1526 return self._bookmarks.names(node)
1526 return self._bookmarks.names(node)
1527
1527
1528 def branchmap(self):
1528 def branchmap(self):
1529 '''returns a dictionary {branch: [branchheads]} with branchheads
1529 '''returns a dictionary {branch: [branchheads]} with branchheads
1530 ordered by increasing revision number'''
1530 ordered by increasing revision number'''
1531 return self._branchcaches[self]
1531 return self._branchcaches[self]
1532
1532
1533 @unfilteredmethod
1533 @unfilteredmethod
1534 def revbranchcache(self):
1534 def revbranchcache(self):
1535 if not self._revbranchcache:
1535 if not self._revbranchcache:
1536 self._revbranchcache = branchmap.revbranchcache(self.unfiltered())
1536 self._revbranchcache = branchmap.revbranchcache(self.unfiltered())
1537 return self._revbranchcache
1537 return self._revbranchcache
1538
1538
1539 def branchtip(self, branch, ignoremissing=False):
1539 def branchtip(self, branch, ignoremissing=False):
1540 '''return the tip node for a given branch
1540 '''return the tip node for a given branch
1541
1541
1542 If ignoremissing is True, then this method will not raise an error.
1542 If ignoremissing is True, then this method will not raise an error.
1543 This is helpful for callers that only expect None for a missing branch
1543 This is helpful for callers that only expect None for a missing branch
1544 (e.g. namespace).
1544 (e.g. namespace).
1545
1545
1546 '''
1546 '''
1547 try:
1547 try:
1548 return self.branchmap().branchtip(branch)
1548 return self.branchmap().branchtip(branch)
1549 except KeyError:
1549 except KeyError:
1550 if not ignoremissing:
1550 if not ignoremissing:
1551 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
1551 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
1552 else:
1552 else:
1553 pass
1553 pass
1554
1554
1555 def lookup(self, key):
1555 def lookup(self, key):
1556 return scmutil.revsymbol(self, key).node()
1556 return scmutil.revsymbol(self, key).node()
1557
1557
1558 def lookupbranch(self, key):
1558 def lookupbranch(self, key):
1559 if key in self.branchmap():
1559 if key in self.branchmap():
1560 return key
1560 return key
1561
1561
1562 return scmutil.revsymbol(self, key).branch()
1562 return scmutil.revsymbol(self, key).branch()
1563
1563
1564 def known(self, nodes):
1564 def known(self, nodes):
1565 cl = self.changelog
1565 cl = self.changelog
1566 nm = cl.nodemap
1566 nm = cl.nodemap
1567 filtered = cl.filteredrevs
1567 filtered = cl.filteredrevs
1568 result = []
1568 result = []
1569 for n in nodes:
1569 for n in nodes:
1570 r = nm.get(n)
1570 r = nm.get(n)
1571 resp = not (r is None or r in filtered)
1571 resp = not (r is None or r in filtered)
1572 result.append(resp)
1572 result.append(resp)
1573 return result
1573 return result
1574
1574
1575 def local(self):
1575 def local(self):
1576 return self
1576 return self
1577
1577
1578 def publishing(self):
1578 def publishing(self):
1579 # it's safe (and desirable) to trust the publish flag unconditionally
1579 # it's safe (and desirable) to trust the publish flag unconditionally
1580 # so that we don't finalize changes shared between users via ssh or nfs
1580 # so that we don't finalize changes shared between users via ssh or nfs
1581 return self.ui.configbool('phases', 'publish', untrusted=True)
1581 return self.ui.configbool('phases', 'publish', untrusted=True)
1582
1582
1583 def cancopy(self):
1583 def cancopy(self):
1584 # so statichttprepo's override of local() works
1584 # so statichttprepo's override of local() works
1585 if not self.local():
1585 if not self.local():
1586 return False
1586 return False
1587 if not self.publishing():
1587 if not self.publishing():
1588 return True
1588 return True
1589 # if publishing we can't copy if there is filtered content
1589 # if publishing we can't copy if there is filtered content
1590 return not self.filtered('visible').changelog.filteredrevs
1590 return not self.filtered('visible').changelog.filteredrevs
1591
1591
1592 def shared(self):
1592 def shared(self):
1593 '''the type of shared repository (None if not shared)'''
1593 '''the type of shared repository (None if not shared)'''
1594 if self.sharedpath != self.path:
1594 if self.sharedpath != self.path:
1595 return 'store'
1595 return 'store'
1596 return None
1596 return None
1597
1597
1598 def wjoin(self, f, *insidef):
1598 def wjoin(self, f, *insidef):
1599 return self.vfs.reljoin(self.root, f, *insidef)
1599 return self.vfs.reljoin(self.root, f, *insidef)
1600
1600
1601 def setparents(self, p1, p2=nullid):
1601 def setparents(self, p1, p2=nullid):
1602 with self.dirstate.parentchange():
1602 with self.dirstate.parentchange():
1603 copies = self.dirstate.setparents(p1, p2)
1603 copies = self.dirstate.setparents(p1, p2)
1604 pctx = self[p1]
1604 pctx = self[p1]
1605 if copies:
1605 if copies:
1606 # Adjust copy records, the dirstate cannot do it, it
1606 # Adjust copy records, the dirstate cannot do it, it
1607 # requires access to parents manifests. Preserve them
1607 # requires access to parents manifests. Preserve them
1608 # only for entries added to first parent.
1608 # only for entries added to first parent.
1609 for f in copies:
1609 for f in copies:
1610 if f not in pctx and copies[f] in pctx:
1610 if f not in pctx and copies[f] in pctx:
1611 self.dirstate.copy(copies[f], f)
1611 self.dirstate.copy(copies[f], f)
1612 if p2 == nullid:
1612 if p2 == nullid:
1613 for f, s in sorted(self.dirstate.copies().items()):
1613 for f, s in sorted(self.dirstate.copies().items()):
1614 if f not in pctx and s not in pctx:
1614 if f not in pctx and s not in pctx:
1615 self.dirstate.copy(None, f)
1615 self.dirstate.copy(None, f)
1616
1616
1617 def filectx(self, path, changeid=None, fileid=None, changectx=None):
1617 def filectx(self, path, changeid=None, fileid=None, changectx=None):
1618 """changeid must be a changeset revision, if specified.
1618 """changeid must be a changeset revision, if specified.
1619 fileid can be a file revision or node."""
1619 fileid can be a file revision or node."""
1620 return context.filectx(self, path, changeid, fileid,
1620 return context.filectx(self, path, changeid, fileid,
1621 changectx=changectx)
1621 changectx=changectx)
1622
1622
1623 def getcwd(self):
1623 def getcwd(self):
1624 return self.dirstate.getcwd()
1624 return self.dirstate.getcwd()
1625
1625
1626 def pathto(self, f, cwd=None):
1626 def pathto(self, f, cwd=None):
1627 return self.dirstate.pathto(f, cwd)
1627 return self.dirstate.pathto(f, cwd)
1628
1628
1629 def _loadfilter(self, filter):
1629 def _loadfilter(self, filter):
1630 if filter not in self._filterpats:
1630 if filter not in self._filterpats:
1631 l = []
1631 l = []
1632 for pat, cmd in self.ui.configitems(filter):
1632 for pat, cmd in self.ui.configitems(filter):
1633 if cmd == '!':
1633 if cmd == '!':
1634 continue
1634 continue
1635 mf = matchmod.match(self.root, '', [pat])
1635 mf = matchmod.match(self.root, '', [pat])
1636 fn = None
1636 fn = None
1637 params = cmd
1637 params = cmd
1638 for name, filterfn in self._datafilters.iteritems():
1638 for name, filterfn in self._datafilters.iteritems():
1639 if cmd.startswith(name):
1639 if cmd.startswith(name):
1640 fn = filterfn
1640 fn = filterfn
1641 params = cmd[len(name):].lstrip()
1641 params = cmd[len(name):].lstrip()
1642 break
1642 break
1643 if not fn:
1643 if not fn:
1644 fn = lambda s, c, **kwargs: procutil.filter(s, c)
1644 fn = lambda s, c, **kwargs: procutil.filter(s, c)
1645 # Wrap old filters not supporting keyword arguments
1645 # Wrap old filters not supporting keyword arguments
1646 if not pycompat.getargspec(fn)[2]:
1646 if not pycompat.getargspec(fn)[2]:
1647 oldfn = fn
1647 oldfn = fn
1648 fn = lambda s, c, **kwargs: oldfn(s, c)
1648 fn = lambda s, c, **kwargs: oldfn(s, c)
1649 l.append((mf, fn, params))
1649 l.append((mf, fn, params))
1650 self._filterpats[filter] = l
1650 self._filterpats[filter] = l
1651 return self._filterpats[filter]
1651 return self._filterpats[filter]
1652
1652
1653 def _filter(self, filterpats, filename, data):
1653 def _filter(self, filterpats, filename, data):
1654 for mf, fn, cmd in filterpats:
1654 for mf, fn, cmd in filterpats:
1655 if mf(filename):
1655 if mf(filename):
1656 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
1656 self.ui.debug("filtering %s through %s\n" % (filename, cmd))
1657 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
1657 data = fn(data, cmd, ui=self.ui, repo=self, filename=filename)
1658 break
1658 break
1659
1659
1660 return data
1660 return data
1661
1661
1662 @unfilteredpropertycache
1662 @unfilteredpropertycache
1663 def _encodefilterpats(self):
1663 def _encodefilterpats(self):
1664 return self._loadfilter('encode')
1664 return self._loadfilter('encode')
1665
1665
1666 @unfilteredpropertycache
1666 @unfilteredpropertycache
1667 def _decodefilterpats(self):
1667 def _decodefilterpats(self):
1668 return self._loadfilter('decode')
1668 return self._loadfilter('decode')
1669
1669
1670 def adddatafilter(self, name, filter):
1670 def adddatafilter(self, name, filter):
1671 self._datafilters[name] = filter
1671 self._datafilters[name] = filter
1672
1672
1673 def wread(self, filename):
1673 def wread(self, filename):
1674 if self.wvfs.islink(filename):
1674 if self.wvfs.islink(filename):
1675 data = self.wvfs.readlink(filename)
1675 data = self.wvfs.readlink(filename)
1676 else:
1676 else:
1677 data = self.wvfs.read(filename)
1677 data = self.wvfs.read(filename)
1678 return self._filter(self._encodefilterpats, filename, data)
1678 return self._filter(self._encodefilterpats, filename, data)
1679
1679
1680 def wwrite(self, filename, data, flags, backgroundclose=False, **kwargs):
1680 def wwrite(self, filename, data, flags, backgroundclose=False, **kwargs):
1681 """write ``data`` into ``filename`` in the working directory
1681 """write ``data`` into ``filename`` in the working directory
1682
1682
1683 This returns length of written (maybe decoded) data.
1683 This returns length of written (maybe decoded) data.
1684 """
1684 """
1685 data = self._filter(self._decodefilterpats, filename, data)
1685 data = self._filter(self._decodefilterpats, filename, data)
1686 if 'l' in flags:
1686 if 'l' in flags:
1687 self.wvfs.symlink(data, filename)
1687 self.wvfs.symlink(data, filename)
1688 else:
1688 else:
1689 self.wvfs.write(filename, data, backgroundclose=backgroundclose,
1689 self.wvfs.write(filename, data, backgroundclose=backgroundclose,
1690 **kwargs)
1690 **kwargs)
1691 if 'x' in flags:
1691 if 'x' in flags:
1692 self.wvfs.setflags(filename, False, True)
1692 self.wvfs.setflags(filename, False, True)
1693 else:
1693 else:
1694 self.wvfs.setflags(filename, False, False)
1694 self.wvfs.setflags(filename, False, False)
1695 return len(data)
1695 return len(data)
1696
1696
1697 def wwritedata(self, filename, data):
1697 def wwritedata(self, filename, data):
1698 return self._filter(self._decodefilterpats, filename, data)
1698 return self._filter(self._decodefilterpats, filename, data)
1699
1699
1700 def currenttransaction(self):
1700 def currenttransaction(self):
1701 """return the current transaction or None if non exists"""
1701 """return the current transaction or None if non exists"""
1702 if self._transref:
1702 if self._transref:
1703 tr = self._transref()
1703 tr = self._transref()
1704 else:
1704 else:
1705 tr = None
1705 tr = None
1706
1706
1707 if tr and tr.running():
1707 if tr and tr.running():
1708 return tr
1708 return tr
1709 return None
1709 return None
1710
1710
1711 def transaction(self, desc, report=None):
1711 def transaction(self, desc, report=None):
1712 if (self.ui.configbool('devel', 'all-warnings')
1712 if (self.ui.configbool('devel', 'all-warnings')
1713 or self.ui.configbool('devel', 'check-locks')):
1713 or self.ui.configbool('devel', 'check-locks')):
1714 if self._currentlock(self._lockref) is None:
1714 if self._currentlock(self._lockref) is None:
1715 raise error.ProgrammingError('transaction requires locking')
1715 raise error.ProgrammingError('transaction requires locking')
1716 tr = self.currenttransaction()
1716 tr = self.currenttransaction()
1717 if tr is not None:
1717 if tr is not None:
1718 return tr.nest(name=desc)
1718 return tr.nest(name=desc)
1719
1719
1720 # abort here if the journal already exists
1720 # abort here if the journal already exists
1721 if self.svfs.exists("journal"):
1721 if self.svfs.exists("journal"):
1722 raise error.RepoError(
1722 raise error.RepoError(
1723 _("abandoned transaction found"),
1723 _("abandoned transaction found"),
1724 hint=_("run 'hg recover' to clean up transaction"))
1724 hint=_("run 'hg recover' to clean up transaction"))
1725
1725
1726 idbase = "%.40f#%f" % (random.random(), time.time())
1726 idbase = "%.40f#%f" % (random.random(), time.time())
1727 ha = hex(hashlib.sha1(idbase).digest())
1727 ha = hex(hashlib.sha1(idbase).digest())
1728 txnid = 'TXN:' + ha
1728 txnid = 'TXN:' + ha
1729 self.hook('pretxnopen', throw=True, txnname=desc, txnid=txnid)
1729 self.hook('pretxnopen', throw=True, txnname=desc, txnid=txnid)
1730
1730
1731 self._writejournal(desc)
1731 self._writejournal(desc)
1732 renames = [(vfs, x, undoname(x)) for vfs, x in self._journalfiles()]
1732 renames = [(vfs, x, undoname(x)) for vfs, x in self._journalfiles()]
1733 if report:
1733 if report:
1734 rp = report
1734 rp = report
1735 else:
1735 else:
1736 rp = self.ui.warn
1736 rp = self.ui.warn
1737 vfsmap = {'plain': self.vfs, 'store': self.svfs} # root of .hg/
1737 vfsmap = {'plain': self.vfs, 'store': self.svfs} # root of .hg/
1738 # we must avoid cyclic reference between repo and transaction.
1738 # we must avoid cyclic reference between repo and transaction.
1739 reporef = weakref.ref(self)
1739 reporef = weakref.ref(self)
1740 # Code to track tag movement
1740 # Code to track tag movement
1741 #
1741 #
1742 # Since tags are all handled as file content, it is actually quite hard
1742 # Since tags are all handled as file content, it is actually quite hard
1743 # to track these movement from a code perspective. So we fallback to a
1743 # to track these movement from a code perspective. So we fallback to a
1744 # tracking at the repository level. One could envision to track changes
1744 # tracking at the repository level. One could envision to track changes
1745 # to the '.hgtags' file through changegroup apply but that fails to
1745 # to the '.hgtags' file through changegroup apply but that fails to
1746 # cope with case where transaction expose new heads without changegroup
1746 # cope with case where transaction expose new heads without changegroup
1747 # being involved (eg: phase movement).
1747 # being involved (eg: phase movement).
1748 #
1748 #
1749 # For now, We gate the feature behind a flag since this likely comes
1749 # For now, We gate the feature behind a flag since this likely comes
1750 # with performance impacts. The current code run more often than needed
1750 # with performance impacts. The current code run more often than needed
1751 # and do not use caches as much as it could. The current focus is on
1751 # and do not use caches as much as it could. The current focus is on
1752 # the behavior of the feature so we disable it by default. The flag
1752 # the behavior of the feature so we disable it by default. The flag
1753 # will be removed when we are happy with the performance impact.
1753 # will be removed when we are happy with the performance impact.
1754 #
1754 #
1755 # Once this feature is no longer experimental move the following
1755 # Once this feature is no longer experimental move the following
1756 # documentation to the appropriate help section:
1756 # documentation to the appropriate help section:
1757 #
1757 #
1758 # The ``HG_TAG_MOVED`` variable will be set if the transaction touched
1758 # The ``HG_TAG_MOVED`` variable will be set if the transaction touched
1759 # tags (new or changed or deleted tags). In addition the details of
1759 # tags (new or changed or deleted tags). In addition the details of
1760 # these changes are made available in a file at:
1760 # these changes are made available in a file at:
1761 # ``REPOROOT/.hg/changes/tags.changes``.
1761 # ``REPOROOT/.hg/changes/tags.changes``.
1762 # Make sure you check for HG_TAG_MOVED before reading that file as it
1762 # Make sure you check for HG_TAG_MOVED before reading that file as it
1763 # might exist from a previous transaction even if no tag were touched
1763 # might exist from a previous transaction even if no tag were touched
1764 # in this one. Changes are recorded in a line base format::
1764 # in this one. Changes are recorded in a line base format::
1765 #
1765 #
1766 # <action> <hex-node> <tag-name>\n
1766 # <action> <hex-node> <tag-name>\n
1767 #
1767 #
1768 # Actions are defined as follow:
1768 # Actions are defined as follow:
1769 # "-R": tag is removed,
1769 # "-R": tag is removed,
1770 # "+A": tag is added,
1770 # "+A": tag is added,
1771 # "-M": tag is moved (old value),
1771 # "-M": tag is moved (old value),
1772 # "+M": tag is moved (new value),
1772 # "+M": tag is moved (new value),
1773 tracktags = lambda x: None
1773 tracktags = lambda x: None
1774 # experimental config: experimental.hook-track-tags
1774 # experimental config: experimental.hook-track-tags
1775 shouldtracktags = self.ui.configbool('experimental', 'hook-track-tags')
1775 shouldtracktags = self.ui.configbool('experimental', 'hook-track-tags')
1776 if desc != 'strip' and shouldtracktags:
1776 if desc != 'strip' and shouldtracktags:
1777 oldheads = self.changelog.headrevs()
1777 oldheads = self.changelog.headrevs()
1778 def tracktags(tr2):
1778 def tracktags(tr2):
1779 repo = reporef()
1779 repo = reporef()
1780 oldfnodes = tagsmod.fnoderevs(repo.ui, repo, oldheads)
1780 oldfnodes = tagsmod.fnoderevs(repo.ui, repo, oldheads)
1781 newheads = repo.changelog.headrevs()
1781 newheads = repo.changelog.headrevs()
1782 newfnodes = tagsmod.fnoderevs(repo.ui, repo, newheads)
1782 newfnodes = tagsmod.fnoderevs(repo.ui, repo, newheads)
1783 # notes: we compare lists here.
1783 # notes: we compare lists here.
1784 # As we do it only once buiding set would not be cheaper
1784 # As we do it only once buiding set would not be cheaper
1785 changes = tagsmod.difftags(repo.ui, repo, oldfnodes, newfnodes)
1785 changes = tagsmod.difftags(repo.ui, repo, oldfnodes, newfnodes)
1786 if changes:
1786 if changes:
1787 tr2.hookargs['tag_moved'] = '1'
1787 tr2.hookargs['tag_moved'] = '1'
1788 with repo.vfs('changes/tags.changes', 'w',
1788 with repo.vfs('changes/tags.changes', 'w',
1789 atomictemp=True) as changesfile:
1789 atomictemp=True) as changesfile:
1790 # note: we do not register the file to the transaction
1790 # note: we do not register the file to the transaction
1791 # because we needs it to still exist on the transaction
1791 # because we needs it to still exist on the transaction
1792 # is close (for txnclose hooks)
1792 # is close (for txnclose hooks)
1793 tagsmod.writediff(changesfile, changes)
1793 tagsmod.writediff(changesfile, changes)
1794 def validate(tr2):
1794 def validate(tr2):
1795 """will run pre-closing hooks"""
1795 """will run pre-closing hooks"""
1796 # XXX the transaction API is a bit lacking here so we take a hacky
1796 # XXX the transaction API is a bit lacking here so we take a hacky
1797 # path for now
1797 # path for now
1798 #
1798 #
1799 # We cannot add this as a "pending" hooks since the 'tr.hookargs'
1799 # We cannot add this as a "pending" hooks since the 'tr.hookargs'
1800 # dict is copied before these run. In addition we needs the data
1800 # dict is copied before these run. In addition we needs the data
1801 # available to in memory hooks too.
1801 # available to in memory hooks too.
1802 #
1802 #
1803 # Moreover, we also need to make sure this runs before txnclose
1803 # Moreover, we also need to make sure this runs before txnclose
1804 # hooks and there is no "pending" mechanism that would execute
1804 # hooks and there is no "pending" mechanism that would execute
1805 # logic only if hooks are about to run.
1805 # logic only if hooks are about to run.
1806 #
1806 #
1807 # Fixing this limitation of the transaction is also needed to track
1807 # Fixing this limitation of the transaction is also needed to track
1808 # other families of changes (bookmarks, phases, obsolescence).
1808 # other families of changes (bookmarks, phases, obsolescence).
1809 #
1809 #
1810 # This will have to be fixed before we remove the experimental
1810 # This will have to be fixed before we remove the experimental
1811 # gating.
1811 # gating.
1812 tracktags(tr2)
1812 tracktags(tr2)
1813 repo = reporef()
1813 repo = reporef()
1814 if repo.ui.configbool('experimental', 'single-head-per-branch'):
1814 if repo.ui.configbool('experimental', 'single-head-per-branch'):
1815 scmutil.enforcesinglehead(repo, tr2, desc)
1815 scmutil.enforcesinglehead(repo, tr2, desc)
1816 if hook.hashook(repo.ui, 'pretxnclose-bookmark'):
1816 if hook.hashook(repo.ui, 'pretxnclose-bookmark'):
1817 for name, (old, new) in sorted(tr.changes['bookmarks'].items()):
1817 for name, (old, new) in sorted(tr.changes['bookmarks'].items()):
1818 args = tr.hookargs.copy()
1818 args = tr.hookargs.copy()
1819 args.update(bookmarks.preparehookargs(name, old, new))
1819 args.update(bookmarks.preparehookargs(name, old, new))
1820 repo.hook('pretxnclose-bookmark', throw=True,
1820 repo.hook('pretxnclose-bookmark', throw=True,
1821 txnname=desc,
1822 **pycompat.strkwargs(args))
1821 **pycompat.strkwargs(args))
1823 if hook.hashook(repo.ui, 'pretxnclose-phase'):
1822 if hook.hashook(repo.ui, 'pretxnclose-phase'):
1824 cl = repo.unfiltered().changelog
1823 cl = repo.unfiltered().changelog
1825 for rev, (old, new) in tr.changes['phases'].items():
1824 for rev, (old, new) in tr.changes['phases'].items():
1826 args = tr.hookargs.copy()
1825 args = tr.hookargs.copy()
1827 node = hex(cl.node(rev))
1826 node = hex(cl.node(rev))
1828 args.update(phases.preparehookargs(node, old, new))
1827 args.update(phases.preparehookargs(node, old, new))
1829 repo.hook('pretxnclose-phase', throw=True, txnname=desc,
1828 repo.hook('pretxnclose-phase', throw=True,
1830 **pycompat.strkwargs(args))
1829 **pycompat.strkwargs(args))
1831
1830
1832 repo.hook('pretxnclose', throw=True,
1831 repo.hook('pretxnclose', throw=True,
1833 txnname=desc, **pycompat.strkwargs(tr.hookargs))
1832 **pycompat.strkwargs(tr.hookargs))
1834 def releasefn(tr, success):
1833 def releasefn(tr, success):
1835 repo = reporef()
1834 repo = reporef()
1836 if success:
1835 if success:
1837 # this should be explicitly invoked here, because
1836 # this should be explicitly invoked here, because
1838 # in-memory changes aren't written out at closing
1837 # in-memory changes aren't written out at closing
1839 # transaction, if tr.addfilegenerator (via
1838 # transaction, if tr.addfilegenerator (via
1840 # dirstate.write or so) isn't invoked while
1839 # dirstate.write or so) isn't invoked while
1841 # transaction running
1840 # transaction running
1842 repo.dirstate.write(None)
1841 repo.dirstate.write(None)
1843 else:
1842 else:
1844 # discard all changes (including ones already written
1843 # discard all changes (including ones already written
1845 # out) in this transaction
1844 # out) in this transaction
1846 narrowspec.restorebackup(self, 'journal.narrowspec')
1845 narrowspec.restorebackup(self, 'journal.narrowspec')
1847 narrowspec.restorewcbackup(self, 'journal.narrowspec.dirstate')
1846 narrowspec.restorewcbackup(self, 'journal.narrowspec.dirstate')
1848 repo.dirstate.restorebackup(None, 'journal.dirstate')
1847 repo.dirstate.restorebackup(None, 'journal.dirstate')
1849
1848
1850 repo.invalidate(clearfilecache=True)
1849 repo.invalidate(clearfilecache=True)
1851
1850
1852 tr = transaction.transaction(rp, self.svfs, vfsmap,
1851 tr = transaction.transaction(rp, self.svfs, vfsmap,
1853 "journal",
1852 "journal",
1854 "undo",
1853 "undo",
1855 aftertrans(renames),
1854 aftertrans(renames),
1856 self.store.createmode,
1855 self.store.createmode,
1857 validator=validate,
1856 validator=validate,
1858 releasefn=releasefn,
1857 releasefn=releasefn,
1859 checkambigfiles=_cachedfiles,
1858 checkambigfiles=_cachedfiles,
1860 name=desc)
1859 name=desc)
1861 tr.changes['origrepolen'] = len(self)
1860 tr.changes['origrepolen'] = len(self)
1862 tr.changes['obsmarkers'] = set()
1861 tr.changes['obsmarkers'] = set()
1863 tr.changes['phases'] = {}
1862 tr.changes['phases'] = {}
1864 tr.changes['bookmarks'] = {}
1863 tr.changes['bookmarks'] = {}
1865
1864
1866 tr.hookargs['txnid'] = txnid
1865 tr.hookargs['txnid'] = txnid
1866 tr.hookargs['txnname'] = desc
1867 # note: writing the fncache only during finalize mean that the file is
1867 # note: writing the fncache only during finalize mean that the file is
1868 # outdated when running hooks. As fncache is used for streaming clone,
1868 # outdated when running hooks. As fncache is used for streaming clone,
1869 # this is not expected to break anything that happen during the hooks.
1869 # this is not expected to break anything that happen during the hooks.
1870 tr.addfinalize('flush-fncache', self.store.write)
1870 tr.addfinalize('flush-fncache', self.store.write)
1871 def txnclosehook(tr2):
1871 def txnclosehook(tr2):
1872 """To be run if transaction is successful, will schedule a hook run
1872 """To be run if transaction is successful, will schedule a hook run
1873 """
1873 """
1874 # Don't reference tr2 in hook() so we don't hold a reference.
1874 # Don't reference tr2 in hook() so we don't hold a reference.
1875 # This reduces memory consumption when there are multiple
1875 # This reduces memory consumption when there are multiple
1876 # transactions per lock. This can likely go away if issue5045
1876 # transactions per lock. This can likely go away if issue5045
1877 # fixes the function accumulation.
1877 # fixes the function accumulation.
1878 hookargs = tr2.hookargs
1878 hookargs = tr2.hookargs
1879
1879
1880 def hookfunc():
1880 def hookfunc():
1881 repo = reporef()
1881 repo = reporef()
1882 if hook.hashook(repo.ui, 'txnclose-bookmark'):
1882 if hook.hashook(repo.ui, 'txnclose-bookmark'):
1883 bmchanges = sorted(tr.changes['bookmarks'].items())
1883 bmchanges = sorted(tr.changes['bookmarks'].items())
1884 for name, (old, new) in bmchanges:
1884 for name, (old, new) in bmchanges:
1885 args = tr.hookargs.copy()
1885 args = tr.hookargs.copy()
1886 args.update(bookmarks.preparehookargs(name, old, new))
1886 args.update(bookmarks.preparehookargs(name, old, new))
1887 repo.hook('txnclose-bookmark', throw=False,
1887 repo.hook('txnclose-bookmark', throw=False,
1888 txnname=desc, **pycompat.strkwargs(args))
1888 **pycompat.strkwargs(args))
1889
1889
1890 if hook.hashook(repo.ui, 'txnclose-phase'):
1890 if hook.hashook(repo.ui, 'txnclose-phase'):
1891 cl = repo.unfiltered().changelog
1891 cl = repo.unfiltered().changelog
1892 phasemv = sorted(tr.changes['phases'].items())
1892 phasemv = sorted(tr.changes['phases'].items())
1893 for rev, (old, new) in phasemv:
1893 for rev, (old, new) in phasemv:
1894 args = tr.hookargs.copy()
1894 args = tr.hookargs.copy()
1895 node = hex(cl.node(rev))
1895 node = hex(cl.node(rev))
1896 args.update(phases.preparehookargs(node, old, new))
1896 args.update(phases.preparehookargs(node, old, new))
1897 repo.hook('txnclose-phase', throw=False, txnname=desc,
1897 repo.hook('txnclose-phase', throw=False,
1898 **pycompat.strkwargs(args))
1898 **pycompat.strkwargs(args))
1899
1899
1900 repo.hook('txnclose', throw=False, txnname=desc,
1900 repo.hook('txnclose', throw=False,
1901 **pycompat.strkwargs(hookargs))
1901 **pycompat.strkwargs(hookargs))
1902 reporef()._afterlock(hookfunc)
1902 reporef()._afterlock(hookfunc)
1903 tr.addfinalize('txnclose-hook', txnclosehook)
1903 tr.addfinalize('txnclose-hook', txnclosehook)
1904 # Include a leading "-" to make it happen before the transaction summary
1904 # Include a leading "-" to make it happen before the transaction summary
1905 # reports registered via scmutil.registersummarycallback() whose names
1905 # reports registered via scmutil.registersummarycallback() whose names
1906 # are 00-txnreport etc. That way, the caches will be warm when the
1906 # are 00-txnreport etc. That way, the caches will be warm when the
1907 # callbacks run.
1907 # callbacks run.
1908 tr.addpostclose('-warm-cache', self._buildcacheupdater(tr))
1908 tr.addpostclose('-warm-cache', self._buildcacheupdater(tr))
1909 def txnaborthook(tr2):
1909 def txnaborthook(tr2):
1910 """To be run if transaction is aborted
1910 """To be run if transaction is aborted
1911 """
1911 """
1912 reporef().hook('txnabort', throw=False, txnname=desc,
1912 reporef().hook('txnabort', throw=False,
1913 **pycompat.strkwargs(tr2.hookargs))
1913 **pycompat.strkwargs(tr2.hookargs))
1914 tr.addabort('txnabort-hook', txnaborthook)
1914 tr.addabort('txnabort-hook', txnaborthook)
1915 # avoid eager cache invalidation. in-memory data should be identical
1915 # avoid eager cache invalidation. in-memory data should be identical
1916 # to stored data if transaction has no error.
1916 # to stored data if transaction has no error.
1917 tr.addpostclose('refresh-filecachestats', self._refreshfilecachestats)
1917 tr.addpostclose('refresh-filecachestats', self._refreshfilecachestats)
1918 self._transref = weakref.ref(tr)
1918 self._transref = weakref.ref(tr)
1919 scmutil.registersummarycallback(self, tr, desc)
1919 scmutil.registersummarycallback(self, tr, desc)
1920 return tr
1920 return tr
1921
1921
1922 def _journalfiles(self):
1922 def _journalfiles(self):
1923 return ((self.svfs, 'journal'),
1923 return ((self.svfs, 'journal'),
1924 (self.svfs, 'journal.narrowspec'),
1924 (self.svfs, 'journal.narrowspec'),
1925 (self.vfs, 'journal.narrowspec.dirstate'),
1925 (self.vfs, 'journal.narrowspec.dirstate'),
1926 (self.vfs, 'journal.dirstate'),
1926 (self.vfs, 'journal.dirstate'),
1927 (self.vfs, 'journal.branch'),
1927 (self.vfs, 'journal.branch'),
1928 (self.vfs, 'journal.desc'),
1928 (self.vfs, 'journal.desc'),
1929 (self.vfs, 'journal.bookmarks'),
1929 (self.vfs, 'journal.bookmarks'),
1930 (self.svfs, 'journal.phaseroots'))
1930 (self.svfs, 'journal.phaseroots'))
1931
1931
1932 def undofiles(self):
1932 def undofiles(self):
1933 return [(vfs, undoname(x)) for vfs, x in self._journalfiles()]
1933 return [(vfs, undoname(x)) for vfs, x in self._journalfiles()]
1934
1934
1935 @unfilteredmethod
1935 @unfilteredmethod
1936 def _writejournal(self, desc):
1936 def _writejournal(self, desc):
1937 self.dirstate.savebackup(None, 'journal.dirstate')
1937 self.dirstate.savebackup(None, 'journal.dirstate')
1938 narrowspec.savewcbackup(self, 'journal.narrowspec.dirstate')
1938 narrowspec.savewcbackup(self, 'journal.narrowspec.dirstate')
1939 narrowspec.savebackup(self, 'journal.narrowspec')
1939 narrowspec.savebackup(self, 'journal.narrowspec')
1940 self.vfs.write("journal.branch",
1940 self.vfs.write("journal.branch",
1941 encoding.fromlocal(self.dirstate.branch()))
1941 encoding.fromlocal(self.dirstate.branch()))
1942 self.vfs.write("journal.desc",
1942 self.vfs.write("journal.desc",
1943 "%d\n%s\n" % (len(self), desc))
1943 "%d\n%s\n" % (len(self), desc))
1944 self.vfs.write("journal.bookmarks",
1944 self.vfs.write("journal.bookmarks",
1945 self.vfs.tryread("bookmarks"))
1945 self.vfs.tryread("bookmarks"))
1946 self.svfs.write("journal.phaseroots",
1946 self.svfs.write("journal.phaseroots",
1947 self.svfs.tryread("phaseroots"))
1947 self.svfs.tryread("phaseroots"))
1948
1948
1949 def recover(self):
1949 def recover(self):
1950 with self.lock():
1950 with self.lock():
1951 if self.svfs.exists("journal"):
1951 if self.svfs.exists("journal"):
1952 self.ui.status(_("rolling back interrupted transaction\n"))
1952 self.ui.status(_("rolling back interrupted transaction\n"))
1953 vfsmap = {'': self.svfs,
1953 vfsmap = {'': self.svfs,
1954 'plain': self.vfs,}
1954 'plain': self.vfs,}
1955 transaction.rollback(self.svfs, vfsmap, "journal",
1955 transaction.rollback(self.svfs, vfsmap, "journal",
1956 self.ui.warn,
1956 self.ui.warn,
1957 checkambigfiles=_cachedfiles)
1957 checkambigfiles=_cachedfiles)
1958 self.invalidate()
1958 self.invalidate()
1959 return True
1959 return True
1960 else:
1960 else:
1961 self.ui.warn(_("no interrupted transaction available\n"))
1961 self.ui.warn(_("no interrupted transaction available\n"))
1962 return False
1962 return False
1963
1963
1964 def rollback(self, dryrun=False, force=False):
1964 def rollback(self, dryrun=False, force=False):
1965 wlock = lock = dsguard = None
1965 wlock = lock = dsguard = None
1966 try:
1966 try:
1967 wlock = self.wlock()
1967 wlock = self.wlock()
1968 lock = self.lock()
1968 lock = self.lock()
1969 if self.svfs.exists("undo"):
1969 if self.svfs.exists("undo"):
1970 dsguard = dirstateguard.dirstateguard(self, 'rollback')
1970 dsguard = dirstateguard.dirstateguard(self, 'rollback')
1971
1971
1972 return self._rollback(dryrun, force, dsguard)
1972 return self._rollback(dryrun, force, dsguard)
1973 else:
1973 else:
1974 self.ui.warn(_("no rollback information available\n"))
1974 self.ui.warn(_("no rollback information available\n"))
1975 return 1
1975 return 1
1976 finally:
1976 finally:
1977 release(dsguard, lock, wlock)
1977 release(dsguard, lock, wlock)
1978
1978
1979 @unfilteredmethod # Until we get smarter cache management
1979 @unfilteredmethod # Until we get smarter cache management
1980 def _rollback(self, dryrun, force, dsguard):
1980 def _rollback(self, dryrun, force, dsguard):
1981 ui = self.ui
1981 ui = self.ui
1982 try:
1982 try:
1983 args = self.vfs.read('undo.desc').splitlines()
1983 args = self.vfs.read('undo.desc').splitlines()
1984 (oldlen, desc, detail) = (int(args[0]), args[1], None)
1984 (oldlen, desc, detail) = (int(args[0]), args[1], None)
1985 if len(args) >= 3:
1985 if len(args) >= 3:
1986 detail = args[2]
1986 detail = args[2]
1987 oldtip = oldlen - 1
1987 oldtip = oldlen - 1
1988
1988
1989 if detail and ui.verbose:
1989 if detail and ui.verbose:
1990 msg = (_('repository tip rolled back to revision %d'
1990 msg = (_('repository tip rolled back to revision %d'
1991 ' (undo %s: %s)\n')
1991 ' (undo %s: %s)\n')
1992 % (oldtip, desc, detail))
1992 % (oldtip, desc, detail))
1993 else:
1993 else:
1994 msg = (_('repository tip rolled back to revision %d'
1994 msg = (_('repository tip rolled back to revision %d'
1995 ' (undo %s)\n')
1995 ' (undo %s)\n')
1996 % (oldtip, desc))
1996 % (oldtip, desc))
1997 except IOError:
1997 except IOError:
1998 msg = _('rolling back unknown transaction\n')
1998 msg = _('rolling back unknown transaction\n')
1999 desc = None
1999 desc = None
2000
2000
2001 if not force and self['.'] != self['tip'] and desc == 'commit':
2001 if not force and self['.'] != self['tip'] and desc == 'commit':
2002 raise error.Abort(
2002 raise error.Abort(
2003 _('rollback of last commit while not checked out '
2003 _('rollback of last commit while not checked out '
2004 'may lose data'), hint=_('use -f to force'))
2004 'may lose data'), hint=_('use -f to force'))
2005
2005
2006 ui.status(msg)
2006 ui.status(msg)
2007 if dryrun:
2007 if dryrun:
2008 return 0
2008 return 0
2009
2009
2010 parents = self.dirstate.parents()
2010 parents = self.dirstate.parents()
2011 self.destroying()
2011 self.destroying()
2012 vfsmap = {'plain': self.vfs, '': self.svfs}
2012 vfsmap = {'plain': self.vfs, '': self.svfs}
2013 transaction.rollback(self.svfs, vfsmap, 'undo', ui.warn,
2013 transaction.rollback(self.svfs, vfsmap, 'undo', ui.warn,
2014 checkambigfiles=_cachedfiles)
2014 checkambigfiles=_cachedfiles)
2015 if self.vfs.exists('undo.bookmarks'):
2015 if self.vfs.exists('undo.bookmarks'):
2016 self.vfs.rename('undo.bookmarks', 'bookmarks', checkambig=True)
2016 self.vfs.rename('undo.bookmarks', 'bookmarks', checkambig=True)
2017 if self.svfs.exists('undo.phaseroots'):
2017 if self.svfs.exists('undo.phaseroots'):
2018 self.svfs.rename('undo.phaseroots', 'phaseroots', checkambig=True)
2018 self.svfs.rename('undo.phaseroots', 'phaseroots', checkambig=True)
2019 self.invalidate()
2019 self.invalidate()
2020
2020
2021 parentgone = any(p not in self.changelog.nodemap for p in parents)
2021 parentgone = any(p not in self.changelog.nodemap for p in parents)
2022 if parentgone:
2022 if parentgone:
2023 # prevent dirstateguard from overwriting already restored one
2023 # prevent dirstateguard from overwriting already restored one
2024 dsguard.close()
2024 dsguard.close()
2025
2025
2026 narrowspec.restorebackup(self, 'undo.narrowspec')
2026 narrowspec.restorebackup(self, 'undo.narrowspec')
2027 narrowspec.restorewcbackup(self, 'undo.narrowspec.dirstate')
2027 narrowspec.restorewcbackup(self, 'undo.narrowspec.dirstate')
2028 self.dirstate.restorebackup(None, 'undo.dirstate')
2028 self.dirstate.restorebackup(None, 'undo.dirstate')
2029 try:
2029 try:
2030 branch = self.vfs.read('undo.branch')
2030 branch = self.vfs.read('undo.branch')
2031 self.dirstate.setbranch(encoding.tolocal(branch))
2031 self.dirstate.setbranch(encoding.tolocal(branch))
2032 except IOError:
2032 except IOError:
2033 ui.warn(_('named branch could not be reset: '
2033 ui.warn(_('named branch could not be reset: '
2034 'current branch is still \'%s\'\n')
2034 'current branch is still \'%s\'\n')
2035 % self.dirstate.branch())
2035 % self.dirstate.branch())
2036
2036
2037 parents = tuple([p.rev() for p in self[None].parents()])
2037 parents = tuple([p.rev() for p in self[None].parents()])
2038 if len(parents) > 1:
2038 if len(parents) > 1:
2039 ui.status(_('working directory now based on '
2039 ui.status(_('working directory now based on '
2040 'revisions %d and %d\n') % parents)
2040 'revisions %d and %d\n') % parents)
2041 else:
2041 else:
2042 ui.status(_('working directory now based on '
2042 ui.status(_('working directory now based on '
2043 'revision %d\n') % parents)
2043 'revision %d\n') % parents)
2044 mergemod.mergestate.clean(self, self['.'].node())
2044 mergemod.mergestate.clean(self, self['.'].node())
2045
2045
2046 # TODO: if we know which new heads may result from this rollback, pass
2046 # TODO: if we know which new heads may result from this rollback, pass
2047 # them to destroy(), which will prevent the branchhead cache from being
2047 # them to destroy(), which will prevent the branchhead cache from being
2048 # invalidated.
2048 # invalidated.
2049 self.destroyed()
2049 self.destroyed()
2050 return 0
2050 return 0
2051
2051
2052 def _buildcacheupdater(self, newtransaction):
2052 def _buildcacheupdater(self, newtransaction):
2053 """called during transaction to build the callback updating cache
2053 """called during transaction to build the callback updating cache
2054
2054
2055 Lives on the repository to help extension who might want to augment
2055 Lives on the repository to help extension who might want to augment
2056 this logic. For this purpose, the created transaction is passed to the
2056 this logic. For this purpose, the created transaction is passed to the
2057 method.
2057 method.
2058 """
2058 """
2059 # we must avoid cyclic reference between repo and transaction.
2059 # we must avoid cyclic reference between repo and transaction.
2060 reporef = weakref.ref(self)
2060 reporef = weakref.ref(self)
2061 def updater(tr):
2061 def updater(tr):
2062 repo = reporef()
2062 repo = reporef()
2063 repo.updatecaches(tr)
2063 repo.updatecaches(tr)
2064 return updater
2064 return updater
2065
2065
2066 @unfilteredmethod
2066 @unfilteredmethod
2067 def updatecaches(self, tr=None, full=False):
2067 def updatecaches(self, tr=None, full=False):
2068 """warm appropriate caches
2068 """warm appropriate caches
2069
2069
2070 If this function is called after a transaction closed. The transaction
2070 If this function is called after a transaction closed. The transaction
2071 will be available in the 'tr' argument. This can be used to selectively
2071 will be available in the 'tr' argument. This can be used to selectively
2072 update caches relevant to the changes in that transaction.
2072 update caches relevant to the changes in that transaction.
2073
2073
2074 If 'full' is set, make sure all caches the function knows about have
2074 If 'full' is set, make sure all caches the function knows about have
2075 up-to-date data. Even the ones usually loaded more lazily.
2075 up-to-date data. Even the ones usually loaded more lazily.
2076 """
2076 """
2077 if tr is not None and tr.hookargs.get('source') == 'strip':
2077 if tr is not None and tr.hookargs.get('source') == 'strip':
2078 # During strip, many caches are invalid but
2078 # During strip, many caches are invalid but
2079 # later call to `destroyed` will refresh them.
2079 # later call to `destroyed` will refresh them.
2080 return
2080 return
2081
2081
2082 if tr is None or tr.changes['origrepolen'] < len(self):
2082 if tr is None or tr.changes['origrepolen'] < len(self):
2083 # accessing the 'ser ved' branchmap should refresh all the others,
2083 # accessing the 'ser ved' branchmap should refresh all the others,
2084 self.ui.debug('updating the branch cache\n')
2084 self.ui.debug('updating the branch cache\n')
2085 self.filtered('served').branchmap()
2085 self.filtered('served').branchmap()
2086
2086
2087 if full:
2087 if full:
2088 rbc = self.revbranchcache()
2088 rbc = self.revbranchcache()
2089 for r in self.changelog:
2089 for r in self.changelog:
2090 rbc.branchinfo(r)
2090 rbc.branchinfo(r)
2091 rbc.write()
2091 rbc.write()
2092
2092
2093 # ensure the working copy parents are in the manifestfulltextcache
2093 # ensure the working copy parents are in the manifestfulltextcache
2094 for ctx in self['.'].parents():
2094 for ctx in self['.'].parents():
2095 ctx.manifest() # accessing the manifest is enough
2095 ctx.manifest() # accessing the manifest is enough
2096
2096
2097 def invalidatecaches(self):
2097 def invalidatecaches(self):
2098
2098
2099 if r'_tagscache' in vars(self):
2099 if r'_tagscache' in vars(self):
2100 # can't use delattr on proxy
2100 # can't use delattr on proxy
2101 del self.__dict__[r'_tagscache']
2101 del self.__dict__[r'_tagscache']
2102
2102
2103 self._branchcaches.clear()
2103 self._branchcaches.clear()
2104 self.invalidatevolatilesets()
2104 self.invalidatevolatilesets()
2105 self._sparsesignaturecache.clear()
2105 self._sparsesignaturecache.clear()
2106
2106
2107 def invalidatevolatilesets(self):
2107 def invalidatevolatilesets(self):
2108 self.filteredrevcache.clear()
2108 self.filteredrevcache.clear()
2109 obsolete.clearobscaches(self)
2109 obsolete.clearobscaches(self)
2110
2110
2111 def invalidatedirstate(self):
2111 def invalidatedirstate(self):
2112 '''Invalidates the dirstate, causing the next call to dirstate
2112 '''Invalidates the dirstate, causing the next call to dirstate
2113 to check if it was modified since the last time it was read,
2113 to check if it was modified since the last time it was read,
2114 rereading it if it has.
2114 rereading it if it has.
2115
2115
2116 This is different to dirstate.invalidate() that it doesn't always
2116 This is different to dirstate.invalidate() that it doesn't always
2117 rereads the dirstate. Use dirstate.invalidate() if you want to
2117 rereads the dirstate. Use dirstate.invalidate() if you want to
2118 explicitly read the dirstate again (i.e. restoring it to a previous
2118 explicitly read the dirstate again (i.e. restoring it to a previous
2119 known good state).'''
2119 known good state).'''
2120 if hasunfilteredcache(self, r'dirstate'):
2120 if hasunfilteredcache(self, r'dirstate'):
2121 for k in self.dirstate._filecache:
2121 for k in self.dirstate._filecache:
2122 try:
2122 try:
2123 delattr(self.dirstate, k)
2123 delattr(self.dirstate, k)
2124 except AttributeError:
2124 except AttributeError:
2125 pass
2125 pass
2126 delattr(self.unfiltered(), r'dirstate')
2126 delattr(self.unfiltered(), r'dirstate')
2127
2127
2128 def invalidate(self, clearfilecache=False):
2128 def invalidate(self, clearfilecache=False):
2129 '''Invalidates both store and non-store parts other than dirstate
2129 '''Invalidates both store and non-store parts other than dirstate
2130
2130
2131 If a transaction is running, invalidation of store is omitted,
2131 If a transaction is running, invalidation of store is omitted,
2132 because discarding in-memory changes might cause inconsistency
2132 because discarding in-memory changes might cause inconsistency
2133 (e.g. incomplete fncache causes unintentional failure, but
2133 (e.g. incomplete fncache causes unintentional failure, but
2134 redundant one doesn't).
2134 redundant one doesn't).
2135 '''
2135 '''
2136 unfiltered = self.unfiltered() # all file caches are stored unfiltered
2136 unfiltered = self.unfiltered() # all file caches are stored unfiltered
2137 for k in list(self._filecache.keys()):
2137 for k in list(self._filecache.keys()):
2138 # dirstate is invalidated separately in invalidatedirstate()
2138 # dirstate is invalidated separately in invalidatedirstate()
2139 if k == 'dirstate':
2139 if k == 'dirstate':
2140 continue
2140 continue
2141 if (k == 'changelog' and
2141 if (k == 'changelog' and
2142 self.currenttransaction() and
2142 self.currenttransaction() and
2143 self.changelog._delayed):
2143 self.changelog._delayed):
2144 # The changelog object may store unwritten revisions. We don't
2144 # The changelog object may store unwritten revisions. We don't
2145 # want to lose them.
2145 # want to lose them.
2146 # TODO: Solve the problem instead of working around it.
2146 # TODO: Solve the problem instead of working around it.
2147 continue
2147 continue
2148
2148
2149 if clearfilecache:
2149 if clearfilecache:
2150 del self._filecache[k]
2150 del self._filecache[k]
2151 try:
2151 try:
2152 delattr(unfiltered, k)
2152 delattr(unfiltered, k)
2153 except AttributeError:
2153 except AttributeError:
2154 pass
2154 pass
2155 self.invalidatecaches()
2155 self.invalidatecaches()
2156 if not self.currenttransaction():
2156 if not self.currenttransaction():
2157 # TODO: Changing contents of store outside transaction
2157 # TODO: Changing contents of store outside transaction
2158 # causes inconsistency. We should make in-memory store
2158 # causes inconsistency. We should make in-memory store
2159 # changes detectable, and abort if changed.
2159 # changes detectable, and abort if changed.
2160 self.store.invalidatecaches()
2160 self.store.invalidatecaches()
2161
2161
2162 def invalidateall(self):
2162 def invalidateall(self):
2163 '''Fully invalidates both store and non-store parts, causing the
2163 '''Fully invalidates both store and non-store parts, causing the
2164 subsequent operation to reread any outside changes.'''
2164 subsequent operation to reread any outside changes.'''
2165 # extension should hook this to invalidate its caches
2165 # extension should hook this to invalidate its caches
2166 self.invalidate()
2166 self.invalidate()
2167 self.invalidatedirstate()
2167 self.invalidatedirstate()
2168
2168
2169 @unfilteredmethod
2169 @unfilteredmethod
2170 def _refreshfilecachestats(self, tr):
2170 def _refreshfilecachestats(self, tr):
2171 """Reload stats of cached files so that they are flagged as valid"""
2171 """Reload stats of cached files so that they are flagged as valid"""
2172 for k, ce in self._filecache.items():
2172 for k, ce in self._filecache.items():
2173 k = pycompat.sysstr(k)
2173 k = pycompat.sysstr(k)
2174 if k == r'dirstate' or k not in self.__dict__:
2174 if k == r'dirstate' or k not in self.__dict__:
2175 continue
2175 continue
2176 ce.refresh()
2176 ce.refresh()
2177
2177
2178 def _lock(self, vfs, lockname, wait, releasefn, acquirefn, desc,
2178 def _lock(self, vfs, lockname, wait, releasefn, acquirefn, desc,
2179 inheritchecker=None, parentenvvar=None):
2179 inheritchecker=None, parentenvvar=None):
2180 parentlock = None
2180 parentlock = None
2181 # the contents of parentenvvar are used by the underlying lock to
2181 # the contents of parentenvvar are used by the underlying lock to
2182 # determine whether it can be inherited
2182 # determine whether it can be inherited
2183 if parentenvvar is not None:
2183 if parentenvvar is not None:
2184 parentlock = encoding.environ.get(parentenvvar)
2184 parentlock = encoding.environ.get(parentenvvar)
2185
2185
2186 timeout = 0
2186 timeout = 0
2187 warntimeout = 0
2187 warntimeout = 0
2188 if wait:
2188 if wait:
2189 timeout = self.ui.configint("ui", "timeout")
2189 timeout = self.ui.configint("ui", "timeout")
2190 warntimeout = self.ui.configint("ui", "timeout.warn")
2190 warntimeout = self.ui.configint("ui", "timeout.warn")
2191 # internal config: ui.signal-safe-lock
2191 # internal config: ui.signal-safe-lock
2192 signalsafe = self.ui.configbool('ui', 'signal-safe-lock')
2192 signalsafe = self.ui.configbool('ui', 'signal-safe-lock')
2193
2193
2194 l = lockmod.trylock(self.ui, vfs, lockname, timeout, warntimeout,
2194 l = lockmod.trylock(self.ui, vfs, lockname, timeout, warntimeout,
2195 releasefn=releasefn,
2195 releasefn=releasefn,
2196 acquirefn=acquirefn, desc=desc,
2196 acquirefn=acquirefn, desc=desc,
2197 inheritchecker=inheritchecker,
2197 inheritchecker=inheritchecker,
2198 parentlock=parentlock,
2198 parentlock=parentlock,
2199 signalsafe=signalsafe)
2199 signalsafe=signalsafe)
2200 return l
2200 return l
2201
2201
2202 def _afterlock(self, callback):
2202 def _afterlock(self, callback):
2203 """add a callback to be run when the repository is fully unlocked
2203 """add a callback to be run when the repository is fully unlocked
2204
2204
2205 The callback will be executed when the outermost lock is released
2205 The callback will be executed when the outermost lock is released
2206 (with wlock being higher level than 'lock')."""
2206 (with wlock being higher level than 'lock')."""
2207 for ref in (self._wlockref, self._lockref):
2207 for ref in (self._wlockref, self._lockref):
2208 l = ref and ref()
2208 l = ref and ref()
2209 if l and l.held:
2209 if l and l.held:
2210 l.postrelease.append(callback)
2210 l.postrelease.append(callback)
2211 break
2211 break
2212 else: # no lock have been found.
2212 else: # no lock have been found.
2213 callback()
2213 callback()
2214
2214
2215 def lock(self, wait=True):
2215 def lock(self, wait=True):
2216 '''Lock the repository store (.hg/store) and return a weak reference
2216 '''Lock the repository store (.hg/store) and return a weak reference
2217 to the lock. Use this before modifying the store (e.g. committing or
2217 to the lock. Use this before modifying the store (e.g. committing or
2218 stripping). If you are opening a transaction, get a lock as well.)
2218 stripping). If you are opening a transaction, get a lock as well.)
2219
2219
2220 If both 'lock' and 'wlock' must be acquired, ensure you always acquires
2220 If both 'lock' and 'wlock' must be acquired, ensure you always acquires
2221 'wlock' first to avoid a dead-lock hazard.'''
2221 'wlock' first to avoid a dead-lock hazard.'''
2222 l = self._currentlock(self._lockref)
2222 l = self._currentlock(self._lockref)
2223 if l is not None:
2223 if l is not None:
2224 l.lock()
2224 l.lock()
2225 return l
2225 return l
2226
2226
2227 l = self._lock(vfs=self.svfs,
2227 l = self._lock(vfs=self.svfs,
2228 lockname="lock",
2228 lockname="lock",
2229 wait=wait,
2229 wait=wait,
2230 releasefn=None,
2230 releasefn=None,
2231 acquirefn=self.invalidate,
2231 acquirefn=self.invalidate,
2232 desc=_('repository %s') % self.origroot)
2232 desc=_('repository %s') % self.origroot)
2233 self._lockref = weakref.ref(l)
2233 self._lockref = weakref.ref(l)
2234 return l
2234 return l
2235
2235
2236 def _wlockchecktransaction(self):
2236 def _wlockchecktransaction(self):
2237 if self.currenttransaction() is not None:
2237 if self.currenttransaction() is not None:
2238 raise error.LockInheritanceContractViolation(
2238 raise error.LockInheritanceContractViolation(
2239 'wlock cannot be inherited in the middle of a transaction')
2239 'wlock cannot be inherited in the middle of a transaction')
2240
2240
2241 def wlock(self, wait=True):
2241 def wlock(self, wait=True):
2242 '''Lock the non-store parts of the repository (everything under
2242 '''Lock the non-store parts of the repository (everything under
2243 .hg except .hg/store) and return a weak reference to the lock.
2243 .hg except .hg/store) and return a weak reference to the lock.
2244
2244
2245 Use this before modifying files in .hg.
2245 Use this before modifying files in .hg.
2246
2246
2247 If both 'lock' and 'wlock' must be acquired, ensure you always acquires
2247 If both 'lock' and 'wlock' must be acquired, ensure you always acquires
2248 'wlock' first to avoid a dead-lock hazard.'''
2248 'wlock' first to avoid a dead-lock hazard.'''
2249 l = self._wlockref and self._wlockref()
2249 l = self._wlockref and self._wlockref()
2250 if l is not None and l.held:
2250 if l is not None and l.held:
2251 l.lock()
2251 l.lock()
2252 return l
2252 return l
2253
2253
2254 # We do not need to check for non-waiting lock acquisition. Such
2254 # We do not need to check for non-waiting lock acquisition. Such
2255 # acquisition would not cause dead-lock as they would just fail.
2255 # acquisition would not cause dead-lock as they would just fail.
2256 if wait and (self.ui.configbool('devel', 'all-warnings')
2256 if wait and (self.ui.configbool('devel', 'all-warnings')
2257 or self.ui.configbool('devel', 'check-locks')):
2257 or self.ui.configbool('devel', 'check-locks')):
2258 if self._currentlock(self._lockref) is not None:
2258 if self._currentlock(self._lockref) is not None:
2259 self.ui.develwarn('"wlock" acquired after "lock"')
2259 self.ui.develwarn('"wlock" acquired after "lock"')
2260
2260
2261 def unlock():
2261 def unlock():
2262 if self.dirstate.pendingparentchange():
2262 if self.dirstate.pendingparentchange():
2263 self.dirstate.invalidate()
2263 self.dirstate.invalidate()
2264 else:
2264 else:
2265 self.dirstate.write(None)
2265 self.dirstate.write(None)
2266
2266
2267 self._filecache['dirstate'].refresh()
2267 self._filecache['dirstate'].refresh()
2268
2268
2269 l = self._lock(self.vfs, "wlock", wait, unlock,
2269 l = self._lock(self.vfs, "wlock", wait, unlock,
2270 self.invalidatedirstate, _('working directory of %s') %
2270 self.invalidatedirstate, _('working directory of %s') %
2271 self.origroot,
2271 self.origroot,
2272 inheritchecker=self._wlockchecktransaction,
2272 inheritchecker=self._wlockchecktransaction,
2273 parentenvvar='HG_WLOCK_LOCKER')
2273 parentenvvar='HG_WLOCK_LOCKER')
2274 self._wlockref = weakref.ref(l)
2274 self._wlockref = weakref.ref(l)
2275 return l
2275 return l
2276
2276
2277 def _currentlock(self, lockref):
2277 def _currentlock(self, lockref):
2278 """Returns the lock if it's held, or None if it's not."""
2278 """Returns the lock if it's held, or None if it's not."""
2279 if lockref is None:
2279 if lockref is None:
2280 return None
2280 return None
2281 l = lockref()
2281 l = lockref()
2282 if l is None or not l.held:
2282 if l is None or not l.held:
2283 return None
2283 return None
2284 return l
2284 return l
2285
2285
2286 def currentwlock(self):
2286 def currentwlock(self):
2287 """Returns the wlock if it's held, or None if it's not."""
2287 """Returns the wlock if it's held, or None if it's not."""
2288 return self._currentlock(self._wlockref)
2288 return self._currentlock(self._wlockref)
2289
2289
2290 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
2290 def _filecommit(self, fctx, manifest1, manifest2, linkrev, tr, changelist):
2291 """
2291 """
2292 commit an individual file as part of a larger transaction
2292 commit an individual file as part of a larger transaction
2293 """
2293 """
2294
2294
2295 fname = fctx.path()
2295 fname = fctx.path()
2296 fparent1 = manifest1.get(fname, nullid)
2296 fparent1 = manifest1.get(fname, nullid)
2297 fparent2 = manifest2.get(fname, nullid)
2297 fparent2 = manifest2.get(fname, nullid)
2298 if isinstance(fctx, context.filectx):
2298 if isinstance(fctx, context.filectx):
2299 node = fctx.filenode()
2299 node = fctx.filenode()
2300 if node in [fparent1, fparent2]:
2300 if node in [fparent1, fparent2]:
2301 self.ui.debug('reusing %s filelog entry\n' % fname)
2301 self.ui.debug('reusing %s filelog entry\n' % fname)
2302 if manifest1.flags(fname) != fctx.flags():
2302 if manifest1.flags(fname) != fctx.flags():
2303 changelist.append(fname)
2303 changelist.append(fname)
2304 return node
2304 return node
2305
2305
2306 flog = self.file(fname)
2306 flog = self.file(fname)
2307 meta = {}
2307 meta = {}
2308 cfname = fctx.copysource()
2308 cfname = fctx.copysource()
2309 if cfname and cfname != fname:
2309 if cfname and cfname != fname:
2310 # Mark the new revision of this file as a copy of another
2310 # Mark the new revision of this file as a copy of another
2311 # file. This copy data will effectively act as a parent
2311 # file. This copy data will effectively act as a parent
2312 # of this new revision. If this is a merge, the first
2312 # of this new revision. If this is a merge, the first
2313 # parent will be the nullid (meaning "look up the copy data")
2313 # parent will be the nullid (meaning "look up the copy data")
2314 # and the second one will be the other parent. For example:
2314 # and the second one will be the other parent. For example:
2315 #
2315 #
2316 # 0 --- 1 --- 3 rev1 changes file foo
2316 # 0 --- 1 --- 3 rev1 changes file foo
2317 # \ / rev2 renames foo to bar and changes it
2317 # \ / rev2 renames foo to bar and changes it
2318 # \- 2 -/ rev3 should have bar with all changes and
2318 # \- 2 -/ rev3 should have bar with all changes and
2319 # should record that bar descends from
2319 # should record that bar descends from
2320 # bar in rev2 and foo in rev1
2320 # bar in rev2 and foo in rev1
2321 #
2321 #
2322 # this allows this merge to succeed:
2322 # this allows this merge to succeed:
2323 #
2323 #
2324 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
2324 # 0 --- 1 --- 3 rev4 reverts the content change from rev2
2325 # \ / merging rev3 and rev4 should use bar@rev2
2325 # \ / merging rev3 and rev4 should use bar@rev2
2326 # \- 2 --- 4 as the merge base
2326 # \- 2 --- 4 as the merge base
2327 #
2327 #
2328
2328
2329 crev = manifest1.get(cfname)
2329 crev = manifest1.get(cfname)
2330 newfparent = fparent2
2330 newfparent = fparent2
2331
2331
2332 if manifest2: # branch merge
2332 if manifest2: # branch merge
2333 if fparent2 == nullid or crev is None: # copied on remote side
2333 if fparent2 == nullid or crev is None: # copied on remote side
2334 if cfname in manifest2:
2334 if cfname in manifest2:
2335 crev = manifest2[cfname]
2335 crev = manifest2[cfname]
2336 newfparent = fparent1
2336 newfparent = fparent1
2337
2337
2338 # Here, we used to search backwards through history to try to find
2338 # Here, we used to search backwards through history to try to find
2339 # where the file copy came from if the source of a copy was not in
2339 # where the file copy came from if the source of a copy was not in
2340 # the parent directory. However, this doesn't actually make sense to
2340 # the parent directory. However, this doesn't actually make sense to
2341 # do (what does a copy from something not in your working copy even
2341 # do (what does a copy from something not in your working copy even
2342 # mean?) and it causes bugs (eg, issue4476). Instead, we will warn
2342 # mean?) and it causes bugs (eg, issue4476). Instead, we will warn
2343 # the user that copy information was dropped, so if they didn't
2343 # the user that copy information was dropped, so if they didn't
2344 # expect this outcome it can be fixed, but this is the correct
2344 # expect this outcome it can be fixed, but this is the correct
2345 # behavior in this circumstance.
2345 # behavior in this circumstance.
2346
2346
2347 if crev:
2347 if crev:
2348 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
2348 self.ui.debug(" %s: copy %s:%s\n" % (fname, cfname, hex(crev)))
2349 meta["copy"] = cfname
2349 meta["copy"] = cfname
2350 meta["copyrev"] = hex(crev)
2350 meta["copyrev"] = hex(crev)
2351 fparent1, fparent2 = nullid, newfparent
2351 fparent1, fparent2 = nullid, newfparent
2352 else:
2352 else:
2353 self.ui.warn(_("warning: can't find ancestor for '%s' "
2353 self.ui.warn(_("warning: can't find ancestor for '%s' "
2354 "copied from '%s'!\n") % (fname, cfname))
2354 "copied from '%s'!\n") % (fname, cfname))
2355
2355
2356 elif fparent1 == nullid:
2356 elif fparent1 == nullid:
2357 fparent1, fparent2 = fparent2, nullid
2357 fparent1, fparent2 = fparent2, nullid
2358 elif fparent2 != nullid:
2358 elif fparent2 != nullid:
2359 # is one parent an ancestor of the other?
2359 # is one parent an ancestor of the other?
2360 fparentancestors = flog.commonancestorsheads(fparent1, fparent2)
2360 fparentancestors = flog.commonancestorsheads(fparent1, fparent2)
2361 if fparent1 in fparentancestors:
2361 if fparent1 in fparentancestors:
2362 fparent1, fparent2 = fparent2, nullid
2362 fparent1, fparent2 = fparent2, nullid
2363 elif fparent2 in fparentancestors:
2363 elif fparent2 in fparentancestors:
2364 fparent2 = nullid
2364 fparent2 = nullid
2365
2365
2366 # is the file changed?
2366 # is the file changed?
2367 text = fctx.data()
2367 text = fctx.data()
2368 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
2368 if fparent2 != nullid or flog.cmp(fparent1, text) or meta:
2369 changelist.append(fname)
2369 changelist.append(fname)
2370 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
2370 return flog.add(text, meta, tr, linkrev, fparent1, fparent2)
2371 # are just the flags changed during merge?
2371 # are just the flags changed during merge?
2372 elif fname in manifest1 and manifest1.flags(fname) != fctx.flags():
2372 elif fname in manifest1 and manifest1.flags(fname) != fctx.flags():
2373 changelist.append(fname)
2373 changelist.append(fname)
2374
2374
2375 return fparent1
2375 return fparent1
2376
2376
2377 def checkcommitpatterns(self, wctx, vdirs, match, status, fail):
2377 def checkcommitpatterns(self, wctx, vdirs, match, status, fail):
2378 """check for commit arguments that aren't committable"""
2378 """check for commit arguments that aren't committable"""
2379 if match.isexact() or match.prefix():
2379 if match.isexact() or match.prefix():
2380 matched = set(status.modified + status.added + status.removed)
2380 matched = set(status.modified + status.added + status.removed)
2381
2381
2382 for f in match.files():
2382 for f in match.files():
2383 f = self.dirstate.normalize(f)
2383 f = self.dirstate.normalize(f)
2384 if f == '.' or f in matched or f in wctx.substate:
2384 if f == '.' or f in matched or f in wctx.substate:
2385 continue
2385 continue
2386 if f in status.deleted:
2386 if f in status.deleted:
2387 fail(f, _('file not found!'))
2387 fail(f, _('file not found!'))
2388 if f in vdirs: # visited directory
2388 if f in vdirs: # visited directory
2389 d = f + '/'
2389 d = f + '/'
2390 for mf in matched:
2390 for mf in matched:
2391 if mf.startswith(d):
2391 if mf.startswith(d):
2392 break
2392 break
2393 else:
2393 else:
2394 fail(f, _("no match under directory!"))
2394 fail(f, _("no match under directory!"))
2395 elif f not in self.dirstate:
2395 elif f not in self.dirstate:
2396 fail(f, _("file not tracked!"))
2396 fail(f, _("file not tracked!"))
2397
2397
2398 @unfilteredmethod
2398 @unfilteredmethod
2399 def commit(self, text="", user=None, date=None, match=None, force=False,
2399 def commit(self, text="", user=None, date=None, match=None, force=False,
2400 editor=False, extra=None):
2400 editor=False, extra=None):
2401 """Add a new revision to current repository.
2401 """Add a new revision to current repository.
2402
2402
2403 Revision information is gathered from the working directory,
2403 Revision information is gathered from the working directory,
2404 match can be used to filter the committed files. If editor is
2404 match can be used to filter the committed files. If editor is
2405 supplied, it is called to get a commit message.
2405 supplied, it is called to get a commit message.
2406 """
2406 """
2407 if extra is None:
2407 if extra is None:
2408 extra = {}
2408 extra = {}
2409
2409
2410 def fail(f, msg):
2410 def fail(f, msg):
2411 raise error.Abort('%s: %s' % (f, msg))
2411 raise error.Abort('%s: %s' % (f, msg))
2412
2412
2413 if not match:
2413 if not match:
2414 match = matchmod.always()
2414 match = matchmod.always()
2415
2415
2416 if not force:
2416 if not force:
2417 vdirs = []
2417 vdirs = []
2418 match.explicitdir = vdirs.append
2418 match.explicitdir = vdirs.append
2419 match.bad = fail
2419 match.bad = fail
2420
2420
2421 # lock() for recent changelog (see issue4368)
2421 # lock() for recent changelog (see issue4368)
2422 with self.wlock(), self.lock():
2422 with self.wlock(), self.lock():
2423 wctx = self[None]
2423 wctx = self[None]
2424 merge = len(wctx.parents()) > 1
2424 merge = len(wctx.parents()) > 1
2425
2425
2426 if not force and merge and not match.always():
2426 if not force and merge and not match.always():
2427 raise error.Abort(_('cannot partially commit a merge '
2427 raise error.Abort(_('cannot partially commit a merge '
2428 '(do not specify files or patterns)'))
2428 '(do not specify files or patterns)'))
2429
2429
2430 status = self.status(match=match, clean=force)
2430 status = self.status(match=match, clean=force)
2431 if force:
2431 if force:
2432 status.modified.extend(status.clean) # mq may commit clean files
2432 status.modified.extend(status.clean) # mq may commit clean files
2433
2433
2434 # check subrepos
2434 # check subrepos
2435 subs, commitsubs, newstate = subrepoutil.precommit(
2435 subs, commitsubs, newstate = subrepoutil.precommit(
2436 self.ui, wctx, status, match, force=force)
2436 self.ui, wctx, status, match, force=force)
2437
2437
2438 # make sure all explicit patterns are matched
2438 # make sure all explicit patterns are matched
2439 if not force:
2439 if not force:
2440 self.checkcommitpatterns(wctx, vdirs, match, status, fail)
2440 self.checkcommitpatterns(wctx, vdirs, match, status, fail)
2441
2441
2442 cctx = context.workingcommitctx(self, status,
2442 cctx = context.workingcommitctx(self, status,
2443 text, user, date, extra)
2443 text, user, date, extra)
2444
2444
2445 # internal config: ui.allowemptycommit
2445 # internal config: ui.allowemptycommit
2446 allowemptycommit = (wctx.branch() != wctx.p1().branch()
2446 allowemptycommit = (wctx.branch() != wctx.p1().branch()
2447 or extra.get('close') or merge or cctx.files()
2447 or extra.get('close') or merge or cctx.files()
2448 or self.ui.configbool('ui', 'allowemptycommit'))
2448 or self.ui.configbool('ui', 'allowemptycommit'))
2449 if not allowemptycommit:
2449 if not allowemptycommit:
2450 return None
2450 return None
2451
2451
2452 if merge and cctx.deleted():
2452 if merge and cctx.deleted():
2453 raise error.Abort(_("cannot commit merge with missing files"))
2453 raise error.Abort(_("cannot commit merge with missing files"))
2454
2454
2455 ms = mergemod.mergestate.read(self)
2455 ms = mergemod.mergestate.read(self)
2456 mergeutil.checkunresolved(ms)
2456 mergeutil.checkunresolved(ms)
2457
2457
2458 if editor:
2458 if editor:
2459 cctx._text = editor(self, cctx, subs)
2459 cctx._text = editor(self, cctx, subs)
2460 edited = (text != cctx._text)
2460 edited = (text != cctx._text)
2461
2461
2462 # Save commit message in case this transaction gets rolled back
2462 # Save commit message in case this transaction gets rolled back
2463 # (e.g. by a pretxncommit hook). Leave the content alone on
2463 # (e.g. by a pretxncommit hook). Leave the content alone on
2464 # the assumption that the user will use the same editor again.
2464 # the assumption that the user will use the same editor again.
2465 msgfn = self.savecommitmessage(cctx._text)
2465 msgfn = self.savecommitmessage(cctx._text)
2466
2466
2467 # commit subs and write new state
2467 # commit subs and write new state
2468 if subs:
2468 if subs:
2469 uipathfn = scmutil.getuipathfn(self)
2469 uipathfn = scmutil.getuipathfn(self)
2470 for s in sorted(commitsubs):
2470 for s in sorted(commitsubs):
2471 sub = wctx.sub(s)
2471 sub = wctx.sub(s)
2472 self.ui.status(_('committing subrepository %s\n') %
2472 self.ui.status(_('committing subrepository %s\n') %
2473 uipathfn(subrepoutil.subrelpath(sub)))
2473 uipathfn(subrepoutil.subrelpath(sub)))
2474 sr = sub.commit(cctx._text, user, date)
2474 sr = sub.commit(cctx._text, user, date)
2475 newstate[s] = (newstate[s][0], sr)
2475 newstate[s] = (newstate[s][0], sr)
2476 subrepoutil.writestate(self, newstate)
2476 subrepoutil.writestate(self, newstate)
2477
2477
2478 p1, p2 = self.dirstate.parents()
2478 p1, p2 = self.dirstate.parents()
2479 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
2479 hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
2480 try:
2480 try:
2481 self.hook("precommit", throw=True, parent1=hookp1,
2481 self.hook("precommit", throw=True, parent1=hookp1,
2482 parent2=hookp2)
2482 parent2=hookp2)
2483 with self.transaction('commit'):
2483 with self.transaction('commit'):
2484 ret = self.commitctx(cctx, True)
2484 ret = self.commitctx(cctx, True)
2485 # update bookmarks, dirstate and mergestate
2485 # update bookmarks, dirstate and mergestate
2486 bookmarks.update(self, [p1, p2], ret)
2486 bookmarks.update(self, [p1, p2], ret)
2487 cctx.markcommitted(ret)
2487 cctx.markcommitted(ret)
2488 ms.reset()
2488 ms.reset()
2489 except: # re-raises
2489 except: # re-raises
2490 if edited:
2490 if edited:
2491 self.ui.write(
2491 self.ui.write(
2492 _('note: commit message saved in %s\n') % msgfn)
2492 _('note: commit message saved in %s\n') % msgfn)
2493 raise
2493 raise
2494
2494
2495 def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2):
2495 def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2):
2496 # hack for command that use a temporary commit (eg: histedit)
2496 # hack for command that use a temporary commit (eg: histedit)
2497 # temporary commit got stripped before hook release
2497 # temporary commit got stripped before hook release
2498 if self.changelog.hasnode(ret):
2498 if self.changelog.hasnode(ret):
2499 self.hook("commit", node=node, parent1=parent1,
2499 self.hook("commit", node=node, parent1=parent1,
2500 parent2=parent2)
2500 parent2=parent2)
2501 self._afterlock(commithook)
2501 self._afterlock(commithook)
2502 return ret
2502 return ret
2503
2503
2504 @unfilteredmethod
2504 @unfilteredmethod
2505 def commitctx(self, ctx, error=False):
2505 def commitctx(self, ctx, error=False):
2506 """Add a new revision to current repository.
2506 """Add a new revision to current repository.
2507 Revision information is passed via the context argument.
2507 Revision information is passed via the context argument.
2508
2508
2509 ctx.files() should list all files involved in this commit, i.e.
2509 ctx.files() should list all files involved in this commit, i.e.
2510 modified/added/removed files. On merge, it may be wider than the
2510 modified/added/removed files. On merge, it may be wider than the
2511 ctx.files() to be committed, since any file nodes derived directly
2511 ctx.files() to be committed, since any file nodes derived directly
2512 from p1 or p2 are excluded from the committed ctx.files().
2512 from p1 or p2 are excluded from the committed ctx.files().
2513 """
2513 """
2514
2514
2515 p1, p2 = ctx.p1(), ctx.p2()
2515 p1, p2 = ctx.p1(), ctx.p2()
2516 user = ctx.user()
2516 user = ctx.user()
2517
2517
2518 with self.lock(), self.transaction("commit") as tr:
2518 with self.lock(), self.transaction("commit") as tr:
2519 trp = weakref.proxy(tr)
2519 trp = weakref.proxy(tr)
2520
2520
2521 if ctx.manifestnode():
2521 if ctx.manifestnode():
2522 # reuse an existing manifest revision
2522 # reuse an existing manifest revision
2523 self.ui.debug('reusing known manifest\n')
2523 self.ui.debug('reusing known manifest\n')
2524 mn = ctx.manifestnode()
2524 mn = ctx.manifestnode()
2525 files = ctx.files()
2525 files = ctx.files()
2526 elif ctx.files():
2526 elif ctx.files():
2527 m1ctx = p1.manifestctx()
2527 m1ctx = p1.manifestctx()
2528 m2ctx = p2.manifestctx()
2528 m2ctx = p2.manifestctx()
2529 mctx = m1ctx.copy()
2529 mctx = m1ctx.copy()
2530
2530
2531 m = mctx.read()
2531 m = mctx.read()
2532 m1 = m1ctx.read()
2532 m1 = m1ctx.read()
2533 m2 = m2ctx.read()
2533 m2 = m2ctx.read()
2534
2534
2535 # check in files
2535 # check in files
2536 added = []
2536 added = []
2537 changed = []
2537 changed = []
2538 removed = list(ctx.removed())
2538 removed = list(ctx.removed())
2539 linkrev = len(self)
2539 linkrev = len(self)
2540 self.ui.note(_("committing files:\n"))
2540 self.ui.note(_("committing files:\n"))
2541 uipathfn = scmutil.getuipathfn(self)
2541 uipathfn = scmutil.getuipathfn(self)
2542 for f in sorted(ctx.modified() + ctx.added()):
2542 for f in sorted(ctx.modified() + ctx.added()):
2543 self.ui.note(uipathfn(f) + "\n")
2543 self.ui.note(uipathfn(f) + "\n")
2544 try:
2544 try:
2545 fctx = ctx[f]
2545 fctx = ctx[f]
2546 if fctx is None:
2546 if fctx is None:
2547 removed.append(f)
2547 removed.append(f)
2548 else:
2548 else:
2549 added.append(f)
2549 added.append(f)
2550 m[f] = self._filecommit(fctx, m1, m2, linkrev,
2550 m[f] = self._filecommit(fctx, m1, m2, linkrev,
2551 trp, changed)
2551 trp, changed)
2552 m.setflag(f, fctx.flags())
2552 m.setflag(f, fctx.flags())
2553 except OSError:
2553 except OSError:
2554 self.ui.warn(_("trouble committing %s!\n") %
2554 self.ui.warn(_("trouble committing %s!\n") %
2555 uipathfn(f))
2555 uipathfn(f))
2556 raise
2556 raise
2557 except IOError as inst:
2557 except IOError as inst:
2558 errcode = getattr(inst, 'errno', errno.ENOENT)
2558 errcode = getattr(inst, 'errno', errno.ENOENT)
2559 if error or errcode and errcode != errno.ENOENT:
2559 if error or errcode and errcode != errno.ENOENT:
2560 self.ui.warn(_("trouble committing %s!\n") %
2560 self.ui.warn(_("trouble committing %s!\n") %
2561 uipathfn(f))
2561 uipathfn(f))
2562 raise
2562 raise
2563
2563
2564 # update manifest
2564 # update manifest
2565 removed = [f for f in sorted(removed) if f in m1 or f in m2]
2565 removed = [f for f in sorted(removed) if f in m1 or f in m2]
2566 drop = [f for f in removed if f in m]
2566 drop = [f for f in removed if f in m]
2567 for f in drop:
2567 for f in drop:
2568 del m[f]
2568 del m[f]
2569 files = changed + removed
2569 files = changed + removed
2570 md = None
2570 md = None
2571 if not files:
2571 if not files:
2572 # if no "files" actually changed in terms of the changelog,
2572 # if no "files" actually changed in terms of the changelog,
2573 # try hard to detect unmodified manifest entry so that the
2573 # try hard to detect unmodified manifest entry so that the
2574 # exact same commit can be reproduced later on convert.
2574 # exact same commit can be reproduced later on convert.
2575 md = m1.diff(m, scmutil.matchfiles(self, ctx.files()))
2575 md = m1.diff(m, scmutil.matchfiles(self, ctx.files()))
2576 if not files and md:
2576 if not files and md:
2577 self.ui.debug('not reusing manifest (no file change in '
2577 self.ui.debug('not reusing manifest (no file change in '
2578 'changelog, but manifest differs)\n')
2578 'changelog, but manifest differs)\n')
2579 if files or md:
2579 if files or md:
2580 self.ui.note(_("committing manifest\n"))
2580 self.ui.note(_("committing manifest\n"))
2581 # we're using narrowmatch here since it's already applied at
2581 # we're using narrowmatch here since it's already applied at
2582 # other stages (such as dirstate.walk), so we're already
2582 # other stages (such as dirstate.walk), so we're already
2583 # ignoring things outside of narrowspec in most cases. The
2583 # ignoring things outside of narrowspec in most cases. The
2584 # one case where we might have files outside the narrowspec
2584 # one case where we might have files outside the narrowspec
2585 # at this point is merges, and we already error out in the
2585 # at this point is merges, and we already error out in the
2586 # case where the merge has files outside of the narrowspec,
2586 # case where the merge has files outside of the narrowspec,
2587 # so this is safe.
2587 # so this is safe.
2588 mn = mctx.write(trp, linkrev,
2588 mn = mctx.write(trp, linkrev,
2589 p1.manifestnode(), p2.manifestnode(),
2589 p1.manifestnode(), p2.manifestnode(),
2590 added, drop, match=self.narrowmatch())
2590 added, drop, match=self.narrowmatch())
2591 else:
2591 else:
2592 self.ui.debug('reusing manifest form p1 (listed files '
2592 self.ui.debug('reusing manifest form p1 (listed files '
2593 'actually unchanged)\n')
2593 'actually unchanged)\n')
2594 mn = p1.manifestnode()
2594 mn = p1.manifestnode()
2595 else:
2595 else:
2596 self.ui.debug('reusing manifest from p1 (no file change)\n')
2596 self.ui.debug('reusing manifest from p1 (no file change)\n')
2597 mn = p1.manifestnode()
2597 mn = p1.manifestnode()
2598 files = []
2598 files = []
2599
2599
2600 # update changelog
2600 # update changelog
2601 self.ui.note(_("committing changelog\n"))
2601 self.ui.note(_("committing changelog\n"))
2602 self.changelog.delayupdate(tr)
2602 self.changelog.delayupdate(tr)
2603 n = self.changelog.add(mn, files, ctx.description(),
2603 n = self.changelog.add(mn, files, ctx.description(),
2604 trp, p1.node(), p2.node(),
2604 trp, p1.node(), p2.node(),
2605 user, ctx.date(), ctx.extra().copy())
2605 user, ctx.date(), ctx.extra().copy())
2606 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
2606 xp1, xp2 = p1.hex(), p2 and p2.hex() or ''
2607 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
2607 self.hook('pretxncommit', throw=True, node=hex(n), parent1=xp1,
2608 parent2=xp2)
2608 parent2=xp2)
2609 # set the new commit is proper phase
2609 # set the new commit is proper phase
2610 targetphase = subrepoutil.newcommitphase(self.ui, ctx)
2610 targetphase = subrepoutil.newcommitphase(self.ui, ctx)
2611 if targetphase:
2611 if targetphase:
2612 # retract boundary do not alter parent changeset.
2612 # retract boundary do not alter parent changeset.
2613 # if a parent have higher the resulting phase will
2613 # if a parent have higher the resulting phase will
2614 # be compliant anyway
2614 # be compliant anyway
2615 #
2615 #
2616 # if minimal phase was 0 we don't need to retract anything
2616 # if minimal phase was 0 we don't need to retract anything
2617 phases.registernew(self, tr, targetphase, [n])
2617 phases.registernew(self, tr, targetphase, [n])
2618 return n
2618 return n
2619
2619
2620 @unfilteredmethod
2620 @unfilteredmethod
2621 def destroying(self):
2621 def destroying(self):
2622 '''Inform the repository that nodes are about to be destroyed.
2622 '''Inform the repository that nodes are about to be destroyed.
2623 Intended for use by strip and rollback, so there's a common
2623 Intended for use by strip and rollback, so there's a common
2624 place for anything that has to be done before destroying history.
2624 place for anything that has to be done before destroying history.
2625
2625
2626 This is mostly useful for saving state that is in memory and waiting
2626 This is mostly useful for saving state that is in memory and waiting
2627 to be flushed when the current lock is released. Because a call to
2627 to be flushed when the current lock is released. Because a call to
2628 destroyed is imminent, the repo will be invalidated causing those
2628 destroyed is imminent, the repo will be invalidated causing those
2629 changes to stay in memory (waiting for the next unlock), or vanish
2629 changes to stay in memory (waiting for the next unlock), or vanish
2630 completely.
2630 completely.
2631 '''
2631 '''
2632 # When using the same lock to commit and strip, the phasecache is left
2632 # When using the same lock to commit and strip, the phasecache is left
2633 # dirty after committing. Then when we strip, the repo is invalidated,
2633 # dirty after committing. Then when we strip, the repo is invalidated,
2634 # causing those changes to disappear.
2634 # causing those changes to disappear.
2635 if '_phasecache' in vars(self):
2635 if '_phasecache' in vars(self):
2636 self._phasecache.write()
2636 self._phasecache.write()
2637
2637
2638 @unfilteredmethod
2638 @unfilteredmethod
2639 def destroyed(self):
2639 def destroyed(self):
2640 '''Inform the repository that nodes have been destroyed.
2640 '''Inform the repository that nodes have been destroyed.
2641 Intended for use by strip and rollback, so there's a common
2641 Intended for use by strip and rollback, so there's a common
2642 place for anything that has to be done after destroying history.
2642 place for anything that has to be done after destroying history.
2643 '''
2643 '''
2644 # When one tries to:
2644 # When one tries to:
2645 # 1) destroy nodes thus calling this method (e.g. strip)
2645 # 1) destroy nodes thus calling this method (e.g. strip)
2646 # 2) use phasecache somewhere (e.g. commit)
2646 # 2) use phasecache somewhere (e.g. commit)
2647 #
2647 #
2648 # then 2) will fail because the phasecache contains nodes that were
2648 # then 2) will fail because the phasecache contains nodes that were
2649 # removed. We can either remove phasecache from the filecache,
2649 # removed. We can either remove phasecache from the filecache,
2650 # causing it to reload next time it is accessed, or simply filter
2650 # causing it to reload next time it is accessed, or simply filter
2651 # the removed nodes now and write the updated cache.
2651 # the removed nodes now and write the updated cache.
2652 self._phasecache.filterunknown(self)
2652 self._phasecache.filterunknown(self)
2653 self._phasecache.write()
2653 self._phasecache.write()
2654
2654
2655 # refresh all repository caches
2655 # refresh all repository caches
2656 self.updatecaches()
2656 self.updatecaches()
2657
2657
2658 # Ensure the persistent tag cache is updated. Doing it now
2658 # Ensure the persistent tag cache is updated. Doing it now
2659 # means that the tag cache only has to worry about destroyed
2659 # means that the tag cache only has to worry about destroyed
2660 # heads immediately after a strip/rollback. That in turn
2660 # heads immediately after a strip/rollback. That in turn
2661 # guarantees that "cachetip == currenttip" (comparing both rev
2661 # guarantees that "cachetip == currenttip" (comparing both rev
2662 # and node) always means no nodes have been added or destroyed.
2662 # and node) always means no nodes have been added or destroyed.
2663
2663
2664 # XXX this is suboptimal when qrefresh'ing: we strip the current
2664 # XXX this is suboptimal when qrefresh'ing: we strip the current
2665 # head, refresh the tag cache, then immediately add a new head.
2665 # head, refresh the tag cache, then immediately add a new head.
2666 # But I think doing it this way is necessary for the "instant
2666 # But I think doing it this way is necessary for the "instant
2667 # tag cache retrieval" case to work.
2667 # tag cache retrieval" case to work.
2668 self.invalidate()
2668 self.invalidate()
2669
2669
2670 def status(self, node1='.', node2=None, match=None,
2670 def status(self, node1='.', node2=None, match=None,
2671 ignored=False, clean=False, unknown=False,
2671 ignored=False, clean=False, unknown=False,
2672 listsubrepos=False):
2672 listsubrepos=False):
2673 '''a convenience method that calls node1.status(node2)'''
2673 '''a convenience method that calls node1.status(node2)'''
2674 return self[node1].status(node2, match, ignored, clean, unknown,
2674 return self[node1].status(node2, match, ignored, clean, unknown,
2675 listsubrepos)
2675 listsubrepos)
2676
2676
2677 def addpostdsstatus(self, ps):
2677 def addpostdsstatus(self, ps):
2678 """Add a callback to run within the wlock, at the point at which status
2678 """Add a callback to run within the wlock, at the point at which status
2679 fixups happen.
2679 fixups happen.
2680
2680
2681 On status completion, callback(wctx, status) will be called with the
2681 On status completion, callback(wctx, status) will be called with the
2682 wlock held, unless the dirstate has changed from underneath or the wlock
2682 wlock held, unless the dirstate has changed from underneath or the wlock
2683 couldn't be grabbed.
2683 couldn't be grabbed.
2684
2684
2685 Callbacks should not capture and use a cached copy of the dirstate --
2685 Callbacks should not capture and use a cached copy of the dirstate --
2686 it might change in the meanwhile. Instead, they should access the
2686 it might change in the meanwhile. Instead, they should access the
2687 dirstate via wctx.repo().dirstate.
2687 dirstate via wctx.repo().dirstate.
2688
2688
2689 This list is emptied out after each status run -- extensions should
2689 This list is emptied out after each status run -- extensions should
2690 make sure it adds to this list each time dirstate.status is called.
2690 make sure it adds to this list each time dirstate.status is called.
2691 Extensions should also make sure they don't call this for statuses
2691 Extensions should also make sure they don't call this for statuses
2692 that don't involve the dirstate.
2692 that don't involve the dirstate.
2693 """
2693 """
2694
2694
2695 # The list is located here for uniqueness reasons -- it is actually
2695 # The list is located here for uniqueness reasons -- it is actually
2696 # managed by the workingctx, but that isn't unique per-repo.
2696 # managed by the workingctx, but that isn't unique per-repo.
2697 self._postdsstatus.append(ps)
2697 self._postdsstatus.append(ps)
2698
2698
2699 def postdsstatus(self):
2699 def postdsstatus(self):
2700 """Used by workingctx to get the list of post-dirstate-status hooks."""
2700 """Used by workingctx to get the list of post-dirstate-status hooks."""
2701 return self._postdsstatus
2701 return self._postdsstatus
2702
2702
2703 def clearpostdsstatus(self):
2703 def clearpostdsstatus(self):
2704 """Used by workingctx to clear post-dirstate-status hooks."""
2704 """Used by workingctx to clear post-dirstate-status hooks."""
2705 del self._postdsstatus[:]
2705 del self._postdsstatus[:]
2706
2706
2707 def heads(self, start=None):
2707 def heads(self, start=None):
2708 if start is None:
2708 if start is None:
2709 cl = self.changelog
2709 cl = self.changelog
2710 headrevs = reversed(cl.headrevs())
2710 headrevs = reversed(cl.headrevs())
2711 return [cl.node(rev) for rev in headrevs]
2711 return [cl.node(rev) for rev in headrevs]
2712
2712
2713 heads = self.changelog.heads(start)
2713 heads = self.changelog.heads(start)
2714 # sort the output in rev descending order
2714 # sort the output in rev descending order
2715 return sorted(heads, key=self.changelog.rev, reverse=True)
2715 return sorted(heads, key=self.changelog.rev, reverse=True)
2716
2716
2717 def branchheads(self, branch=None, start=None, closed=False):
2717 def branchheads(self, branch=None, start=None, closed=False):
2718 '''return a (possibly filtered) list of heads for the given branch
2718 '''return a (possibly filtered) list of heads for the given branch
2719
2719
2720 Heads are returned in topological order, from newest to oldest.
2720 Heads are returned in topological order, from newest to oldest.
2721 If branch is None, use the dirstate branch.
2721 If branch is None, use the dirstate branch.
2722 If start is not None, return only heads reachable from start.
2722 If start is not None, return only heads reachable from start.
2723 If closed is True, return heads that are marked as closed as well.
2723 If closed is True, return heads that are marked as closed as well.
2724 '''
2724 '''
2725 if branch is None:
2725 if branch is None:
2726 branch = self[None].branch()
2726 branch = self[None].branch()
2727 branches = self.branchmap()
2727 branches = self.branchmap()
2728 if branch not in branches:
2728 if branch not in branches:
2729 return []
2729 return []
2730 # the cache returns heads ordered lowest to highest
2730 # the cache returns heads ordered lowest to highest
2731 bheads = list(reversed(branches.branchheads(branch, closed=closed)))
2731 bheads = list(reversed(branches.branchheads(branch, closed=closed)))
2732 if start is not None:
2732 if start is not None:
2733 # filter out the heads that cannot be reached from startrev
2733 # filter out the heads that cannot be reached from startrev
2734 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
2734 fbheads = set(self.changelog.nodesbetween([start], bheads)[2])
2735 bheads = [h for h in bheads if h in fbheads]
2735 bheads = [h for h in bheads if h in fbheads]
2736 return bheads
2736 return bheads
2737
2737
2738 def branches(self, nodes):
2738 def branches(self, nodes):
2739 if not nodes:
2739 if not nodes:
2740 nodes = [self.changelog.tip()]
2740 nodes = [self.changelog.tip()]
2741 b = []
2741 b = []
2742 for n in nodes:
2742 for n in nodes:
2743 t = n
2743 t = n
2744 while True:
2744 while True:
2745 p = self.changelog.parents(n)
2745 p = self.changelog.parents(n)
2746 if p[1] != nullid or p[0] == nullid:
2746 if p[1] != nullid or p[0] == nullid:
2747 b.append((t, n, p[0], p[1]))
2747 b.append((t, n, p[0], p[1]))
2748 break
2748 break
2749 n = p[0]
2749 n = p[0]
2750 return b
2750 return b
2751
2751
2752 def between(self, pairs):
2752 def between(self, pairs):
2753 r = []
2753 r = []
2754
2754
2755 for top, bottom in pairs:
2755 for top, bottom in pairs:
2756 n, l, i = top, [], 0
2756 n, l, i = top, [], 0
2757 f = 1
2757 f = 1
2758
2758
2759 while n != bottom and n != nullid:
2759 while n != bottom and n != nullid:
2760 p = self.changelog.parents(n)[0]
2760 p = self.changelog.parents(n)[0]
2761 if i == f:
2761 if i == f:
2762 l.append(n)
2762 l.append(n)
2763 f = f * 2
2763 f = f * 2
2764 n = p
2764 n = p
2765 i += 1
2765 i += 1
2766
2766
2767 r.append(l)
2767 r.append(l)
2768
2768
2769 return r
2769 return r
2770
2770
2771 def checkpush(self, pushop):
2771 def checkpush(self, pushop):
2772 """Extensions can override this function if additional checks have
2772 """Extensions can override this function if additional checks have
2773 to be performed before pushing, or call it if they override push
2773 to be performed before pushing, or call it if they override push
2774 command.
2774 command.
2775 """
2775 """
2776
2776
2777 @unfilteredpropertycache
2777 @unfilteredpropertycache
2778 def prepushoutgoinghooks(self):
2778 def prepushoutgoinghooks(self):
2779 """Return util.hooks consists of a pushop with repo, remote, outgoing
2779 """Return util.hooks consists of a pushop with repo, remote, outgoing
2780 methods, which are called before pushing changesets.
2780 methods, which are called before pushing changesets.
2781 """
2781 """
2782 return util.hooks()
2782 return util.hooks()
2783
2783
2784 def pushkey(self, namespace, key, old, new):
2784 def pushkey(self, namespace, key, old, new):
2785 try:
2785 try:
2786 tr = self.currenttransaction()
2786 tr = self.currenttransaction()
2787 hookargs = {}
2787 hookargs = {}
2788 if tr is not None:
2788 if tr is not None:
2789 hookargs.update(tr.hookargs)
2789 hookargs.update(tr.hookargs)
2790 hookargs = pycompat.strkwargs(hookargs)
2790 hookargs = pycompat.strkwargs(hookargs)
2791 hookargs[r'namespace'] = namespace
2791 hookargs[r'namespace'] = namespace
2792 hookargs[r'key'] = key
2792 hookargs[r'key'] = key
2793 hookargs[r'old'] = old
2793 hookargs[r'old'] = old
2794 hookargs[r'new'] = new
2794 hookargs[r'new'] = new
2795 self.hook('prepushkey', throw=True, **hookargs)
2795 self.hook('prepushkey', throw=True, **hookargs)
2796 except error.HookAbort as exc:
2796 except error.HookAbort as exc:
2797 self.ui.write_err(_("pushkey-abort: %s\n") % exc)
2797 self.ui.write_err(_("pushkey-abort: %s\n") % exc)
2798 if exc.hint:
2798 if exc.hint:
2799 self.ui.write_err(_("(%s)\n") % exc.hint)
2799 self.ui.write_err(_("(%s)\n") % exc.hint)
2800 return False
2800 return False
2801 self.ui.debug('pushing key for "%s:%s"\n' % (namespace, key))
2801 self.ui.debug('pushing key for "%s:%s"\n' % (namespace, key))
2802 ret = pushkey.push(self, namespace, key, old, new)
2802 ret = pushkey.push(self, namespace, key, old, new)
2803 def runhook():
2803 def runhook():
2804 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2804 self.hook('pushkey', namespace=namespace, key=key, old=old, new=new,
2805 ret=ret)
2805 ret=ret)
2806 self._afterlock(runhook)
2806 self._afterlock(runhook)
2807 return ret
2807 return ret
2808
2808
2809 def listkeys(self, namespace):
2809 def listkeys(self, namespace):
2810 self.hook('prelistkeys', throw=True, namespace=namespace)
2810 self.hook('prelistkeys', throw=True, namespace=namespace)
2811 self.ui.debug('listing keys for "%s"\n' % namespace)
2811 self.ui.debug('listing keys for "%s"\n' % namespace)
2812 values = pushkey.list(self, namespace)
2812 values = pushkey.list(self, namespace)
2813 self.hook('listkeys', namespace=namespace, values=values)
2813 self.hook('listkeys', namespace=namespace, values=values)
2814 return values
2814 return values
2815
2815
2816 def debugwireargs(self, one, two, three=None, four=None, five=None):
2816 def debugwireargs(self, one, two, three=None, four=None, five=None):
2817 '''used to test argument passing over the wire'''
2817 '''used to test argument passing over the wire'''
2818 return "%s %s %s %s %s" % (one, two, pycompat.bytestr(three),
2818 return "%s %s %s %s %s" % (one, two, pycompat.bytestr(three),
2819 pycompat.bytestr(four),
2819 pycompat.bytestr(four),
2820 pycompat.bytestr(five))
2820 pycompat.bytestr(five))
2821
2821
2822 def savecommitmessage(self, text):
2822 def savecommitmessage(self, text):
2823 fp = self.vfs('last-message.txt', 'wb')
2823 fp = self.vfs('last-message.txt', 'wb')
2824 try:
2824 try:
2825 fp.write(text)
2825 fp.write(text)
2826 finally:
2826 finally:
2827 fp.close()
2827 fp.close()
2828 return self.pathto(fp.name[len(self.root) + 1:])
2828 return self.pathto(fp.name[len(self.root) + 1:])
2829
2829
2830 # used to avoid circular references so destructors work
2830 # used to avoid circular references so destructors work
2831 def aftertrans(files):
2831 def aftertrans(files):
2832 renamefiles = [tuple(t) for t in files]
2832 renamefiles = [tuple(t) for t in files]
2833 def a():
2833 def a():
2834 for vfs, src, dest in renamefiles:
2834 for vfs, src, dest in renamefiles:
2835 # if src and dest refer to a same file, vfs.rename is a no-op,
2835 # if src and dest refer to a same file, vfs.rename is a no-op,
2836 # leaving both src and dest on disk. delete dest to make sure
2836 # leaving both src and dest on disk. delete dest to make sure
2837 # the rename couldn't be such a no-op.
2837 # the rename couldn't be such a no-op.
2838 vfs.tryunlink(dest)
2838 vfs.tryunlink(dest)
2839 try:
2839 try:
2840 vfs.rename(src, dest)
2840 vfs.rename(src, dest)
2841 except OSError: # journal file does not yet exist
2841 except OSError: # journal file does not yet exist
2842 pass
2842 pass
2843 return a
2843 return a
2844
2844
2845 def undoname(fn):
2845 def undoname(fn):
2846 base, name = os.path.split(fn)
2846 base, name = os.path.split(fn)
2847 assert name.startswith('journal')
2847 assert name.startswith('journal')
2848 return os.path.join(base, name.replace('journal', 'undo', 1))
2848 return os.path.join(base, name.replace('journal', 'undo', 1))
2849
2849
2850 def instance(ui, path, create, intents=None, createopts=None):
2850 def instance(ui, path, create, intents=None, createopts=None):
2851 localpath = util.urllocalpath(path)
2851 localpath = util.urllocalpath(path)
2852 if create:
2852 if create:
2853 createrepository(ui, localpath, createopts=createopts)
2853 createrepository(ui, localpath, createopts=createopts)
2854
2854
2855 return makelocalrepository(ui, localpath, intents=intents)
2855 return makelocalrepository(ui, localpath, intents=intents)
2856
2856
2857 def islocal(path):
2857 def islocal(path):
2858 return True
2858 return True
2859
2859
2860 def defaultcreateopts(ui, createopts=None):
2860 def defaultcreateopts(ui, createopts=None):
2861 """Populate the default creation options for a repository.
2861 """Populate the default creation options for a repository.
2862
2862
2863 A dictionary of explicitly requested creation options can be passed
2863 A dictionary of explicitly requested creation options can be passed
2864 in. Missing keys will be populated.
2864 in. Missing keys will be populated.
2865 """
2865 """
2866 createopts = dict(createopts or {})
2866 createopts = dict(createopts or {})
2867
2867
2868 if 'backend' not in createopts:
2868 if 'backend' not in createopts:
2869 # experimental config: storage.new-repo-backend
2869 # experimental config: storage.new-repo-backend
2870 createopts['backend'] = ui.config('storage', 'new-repo-backend')
2870 createopts['backend'] = ui.config('storage', 'new-repo-backend')
2871
2871
2872 return createopts
2872 return createopts
2873
2873
2874 def newreporequirements(ui, createopts):
2874 def newreporequirements(ui, createopts):
2875 """Determine the set of requirements for a new local repository.
2875 """Determine the set of requirements for a new local repository.
2876
2876
2877 Extensions can wrap this function to specify custom requirements for
2877 Extensions can wrap this function to specify custom requirements for
2878 new repositories.
2878 new repositories.
2879 """
2879 """
2880 # If the repo is being created from a shared repository, we copy
2880 # If the repo is being created from a shared repository, we copy
2881 # its requirements.
2881 # its requirements.
2882 if 'sharedrepo' in createopts:
2882 if 'sharedrepo' in createopts:
2883 requirements = set(createopts['sharedrepo'].requirements)
2883 requirements = set(createopts['sharedrepo'].requirements)
2884 if createopts.get('sharedrelative'):
2884 if createopts.get('sharedrelative'):
2885 requirements.add('relshared')
2885 requirements.add('relshared')
2886 else:
2886 else:
2887 requirements.add('shared')
2887 requirements.add('shared')
2888
2888
2889 return requirements
2889 return requirements
2890
2890
2891 if 'backend' not in createopts:
2891 if 'backend' not in createopts:
2892 raise error.ProgrammingError('backend key not present in createopts; '
2892 raise error.ProgrammingError('backend key not present in createopts; '
2893 'was defaultcreateopts() called?')
2893 'was defaultcreateopts() called?')
2894
2894
2895 if createopts['backend'] != 'revlogv1':
2895 if createopts['backend'] != 'revlogv1':
2896 raise error.Abort(_('unable to determine repository requirements for '
2896 raise error.Abort(_('unable to determine repository requirements for '
2897 'storage backend: %s') % createopts['backend'])
2897 'storage backend: %s') % createopts['backend'])
2898
2898
2899 requirements = {'revlogv1'}
2899 requirements = {'revlogv1'}
2900 if ui.configbool('format', 'usestore'):
2900 if ui.configbool('format', 'usestore'):
2901 requirements.add('store')
2901 requirements.add('store')
2902 if ui.configbool('format', 'usefncache'):
2902 if ui.configbool('format', 'usefncache'):
2903 requirements.add('fncache')
2903 requirements.add('fncache')
2904 if ui.configbool('format', 'dotencode'):
2904 if ui.configbool('format', 'dotencode'):
2905 requirements.add('dotencode')
2905 requirements.add('dotencode')
2906
2906
2907 compengine = ui.config('experimental', 'format.compression')
2907 compengine = ui.config('experimental', 'format.compression')
2908 if compengine not in util.compengines:
2908 if compengine not in util.compengines:
2909 raise error.Abort(_('compression engine %s defined by '
2909 raise error.Abort(_('compression engine %s defined by '
2910 'experimental.format.compression not available') %
2910 'experimental.format.compression not available') %
2911 compengine,
2911 compengine,
2912 hint=_('run "hg debuginstall" to list available '
2912 hint=_('run "hg debuginstall" to list available '
2913 'compression engines'))
2913 'compression engines'))
2914
2914
2915 # zlib is the historical default and doesn't need an explicit requirement.
2915 # zlib is the historical default and doesn't need an explicit requirement.
2916 if compengine != 'zlib':
2916 if compengine != 'zlib':
2917 requirements.add('exp-compression-%s' % compengine)
2917 requirements.add('exp-compression-%s' % compengine)
2918
2918
2919 if scmutil.gdinitconfig(ui):
2919 if scmutil.gdinitconfig(ui):
2920 requirements.add('generaldelta')
2920 requirements.add('generaldelta')
2921 if ui.configbool('format', 'sparse-revlog'):
2921 if ui.configbool('format', 'sparse-revlog'):
2922 requirements.add(SPARSEREVLOG_REQUIREMENT)
2922 requirements.add(SPARSEREVLOG_REQUIREMENT)
2923 if ui.configbool('experimental', 'treemanifest'):
2923 if ui.configbool('experimental', 'treemanifest'):
2924 requirements.add('treemanifest')
2924 requirements.add('treemanifest')
2925
2925
2926 revlogv2 = ui.config('experimental', 'revlogv2')
2926 revlogv2 = ui.config('experimental', 'revlogv2')
2927 if revlogv2 == 'enable-unstable-format-and-corrupt-my-data':
2927 if revlogv2 == 'enable-unstable-format-and-corrupt-my-data':
2928 requirements.remove('revlogv1')
2928 requirements.remove('revlogv1')
2929 # generaldelta is implied by revlogv2.
2929 # generaldelta is implied by revlogv2.
2930 requirements.discard('generaldelta')
2930 requirements.discard('generaldelta')
2931 requirements.add(REVLOGV2_REQUIREMENT)
2931 requirements.add(REVLOGV2_REQUIREMENT)
2932 # experimental config: format.internal-phase
2932 # experimental config: format.internal-phase
2933 if ui.configbool('format', 'internal-phase'):
2933 if ui.configbool('format', 'internal-phase'):
2934 requirements.add('internal-phase')
2934 requirements.add('internal-phase')
2935
2935
2936 if createopts.get('narrowfiles'):
2936 if createopts.get('narrowfiles'):
2937 requirements.add(repository.NARROW_REQUIREMENT)
2937 requirements.add(repository.NARROW_REQUIREMENT)
2938
2938
2939 if createopts.get('lfs'):
2939 if createopts.get('lfs'):
2940 requirements.add('lfs')
2940 requirements.add('lfs')
2941
2941
2942 return requirements
2942 return requirements
2943
2943
2944 def filterknowncreateopts(ui, createopts):
2944 def filterknowncreateopts(ui, createopts):
2945 """Filters a dict of repo creation options against options that are known.
2945 """Filters a dict of repo creation options against options that are known.
2946
2946
2947 Receives a dict of repo creation options and returns a dict of those
2947 Receives a dict of repo creation options and returns a dict of those
2948 options that we don't know how to handle.
2948 options that we don't know how to handle.
2949
2949
2950 This function is called as part of repository creation. If the
2950 This function is called as part of repository creation. If the
2951 returned dict contains any items, repository creation will not
2951 returned dict contains any items, repository creation will not
2952 be allowed, as it means there was a request to create a repository
2952 be allowed, as it means there was a request to create a repository
2953 with options not recognized by loaded code.
2953 with options not recognized by loaded code.
2954
2954
2955 Extensions can wrap this function to filter out creation options
2955 Extensions can wrap this function to filter out creation options
2956 they know how to handle.
2956 they know how to handle.
2957 """
2957 """
2958 known = {
2958 known = {
2959 'backend',
2959 'backend',
2960 'lfs',
2960 'lfs',
2961 'narrowfiles',
2961 'narrowfiles',
2962 'sharedrepo',
2962 'sharedrepo',
2963 'sharedrelative',
2963 'sharedrelative',
2964 'shareditems',
2964 'shareditems',
2965 'shallowfilestore',
2965 'shallowfilestore',
2966 }
2966 }
2967
2967
2968 return {k: v for k, v in createopts.items() if k not in known}
2968 return {k: v for k, v in createopts.items() if k not in known}
2969
2969
2970 def createrepository(ui, path, createopts=None):
2970 def createrepository(ui, path, createopts=None):
2971 """Create a new repository in a vfs.
2971 """Create a new repository in a vfs.
2972
2972
2973 ``path`` path to the new repo's working directory.
2973 ``path`` path to the new repo's working directory.
2974 ``createopts`` options for the new repository.
2974 ``createopts`` options for the new repository.
2975
2975
2976 The following keys for ``createopts`` are recognized:
2976 The following keys for ``createopts`` are recognized:
2977
2977
2978 backend
2978 backend
2979 The storage backend to use.
2979 The storage backend to use.
2980 lfs
2980 lfs
2981 Repository will be created with ``lfs`` requirement. The lfs extension
2981 Repository will be created with ``lfs`` requirement. The lfs extension
2982 will automatically be loaded when the repository is accessed.
2982 will automatically be loaded when the repository is accessed.
2983 narrowfiles
2983 narrowfiles
2984 Set up repository to support narrow file storage.
2984 Set up repository to support narrow file storage.
2985 sharedrepo
2985 sharedrepo
2986 Repository object from which storage should be shared.
2986 Repository object from which storage should be shared.
2987 sharedrelative
2987 sharedrelative
2988 Boolean indicating if the path to the shared repo should be
2988 Boolean indicating if the path to the shared repo should be
2989 stored as relative. By default, the pointer to the "parent" repo
2989 stored as relative. By default, the pointer to the "parent" repo
2990 is stored as an absolute path.
2990 is stored as an absolute path.
2991 shareditems
2991 shareditems
2992 Set of items to share to the new repository (in addition to storage).
2992 Set of items to share to the new repository (in addition to storage).
2993 shallowfilestore
2993 shallowfilestore
2994 Indicates that storage for files should be shallow (not all ancestor
2994 Indicates that storage for files should be shallow (not all ancestor
2995 revisions are known).
2995 revisions are known).
2996 """
2996 """
2997 createopts = defaultcreateopts(ui, createopts=createopts)
2997 createopts = defaultcreateopts(ui, createopts=createopts)
2998
2998
2999 unknownopts = filterknowncreateopts(ui, createopts)
2999 unknownopts = filterknowncreateopts(ui, createopts)
3000
3000
3001 if not isinstance(unknownopts, dict):
3001 if not isinstance(unknownopts, dict):
3002 raise error.ProgrammingError('filterknowncreateopts() did not return '
3002 raise error.ProgrammingError('filterknowncreateopts() did not return '
3003 'a dict')
3003 'a dict')
3004
3004
3005 if unknownopts:
3005 if unknownopts:
3006 raise error.Abort(_('unable to create repository because of unknown '
3006 raise error.Abort(_('unable to create repository because of unknown '
3007 'creation option: %s') %
3007 'creation option: %s') %
3008 ', '.join(sorted(unknownopts)),
3008 ', '.join(sorted(unknownopts)),
3009 hint=_('is a required extension not loaded?'))
3009 hint=_('is a required extension not loaded?'))
3010
3010
3011 requirements = newreporequirements(ui, createopts=createopts)
3011 requirements = newreporequirements(ui, createopts=createopts)
3012
3012
3013 wdirvfs = vfsmod.vfs(path, expandpath=True, realpath=True)
3013 wdirvfs = vfsmod.vfs(path, expandpath=True, realpath=True)
3014
3014
3015 hgvfs = vfsmod.vfs(wdirvfs.join(b'.hg'))
3015 hgvfs = vfsmod.vfs(wdirvfs.join(b'.hg'))
3016 if hgvfs.exists():
3016 if hgvfs.exists():
3017 raise error.RepoError(_('repository %s already exists') % path)
3017 raise error.RepoError(_('repository %s already exists') % path)
3018
3018
3019 if 'sharedrepo' in createopts:
3019 if 'sharedrepo' in createopts:
3020 sharedpath = createopts['sharedrepo'].sharedpath
3020 sharedpath = createopts['sharedrepo'].sharedpath
3021
3021
3022 if createopts.get('sharedrelative'):
3022 if createopts.get('sharedrelative'):
3023 try:
3023 try:
3024 sharedpath = os.path.relpath(sharedpath, hgvfs.base)
3024 sharedpath = os.path.relpath(sharedpath, hgvfs.base)
3025 except (IOError, ValueError) as e:
3025 except (IOError, ValueError) as e:
3026 # ValueError is raised on Windows if the drive letters differ
3026 # ValueError is raised on Windows if the drive letters differ
3027 # on each path.
3027 # on each path.
3028 raise error.Abort(_('cannot calculate relative path'),
3028 raise error.Abort(_('cannot calculate relative path'),
3029 hint=stringutil.forcebytestr(e))
3029 hint=stringutil.forcebytestr(e))
3030
3030
3031 if not wdirvfs.exists():
3031 if not wdirvfs.exists():
3032 wdirvfs.makedirs()
3032 wdirvfs.makedirs()
3033
3033
3034 hgvfs.makedir(notindexed=True)
3034 hgvfs.makedir(notindexed=True)
3035 if 'sharedrepo' not in createopts:
3035 if 'sharedrepo' not in createopts:
3036 hgvfs.mkdir(b'cache')
3036 hgvfs.mkdir(b'cache')
3037 hgvfs.mkdir(b'wcache')
3037 hgvfs.mkdir(b'wcache')
3038
3038
3039 if b'store' in requirements and 'sharedrepo' not in createopts:
3039 if b'store' in requirements and 'sharedrepo' not in createopts:
3040 hgvfs.mkdir(b'store')
3040 hgvfs.mkdir(b'store')
3041
3041
3042 # We create an invalid changelog outside the store so very old
3042 # We create an invalid changelog outside the store so very old
3043 # Mercurial versions (which didn't know about the requirements
3043 # Mercurial versions (which didn't know about the requirements
3044 # file) encounter an error on reading the changelog. This
3044 # file) encounter an error on reading the changelog. This
3045 # effectively locks out old clients and prevents them from
3045 # effectively locks out old clients and prevents them from
3046 # mucking with a repo in an unknown format.
3046 # mucking with a repo in an unknown format.
3047 #
3047 #
3048 # The revlog header has version 2, which won't be recognized by
3048 # The revlog header has version 2, which won't be recognized by
3049 # such old clients.
3049 # such old clients.
3050 hgvfs.append(b'00changelog.i',
3050 hgvfs.append(b'00changelog.i',
3051 b'\0\0\0\2 dummy changelog to prevent using the old repo '
3051 b'\0\0\0\2 dummy changelog to prevent using the old repo '
3052 b'layout')
3052 b'layout')
3053
3053
3054 scmutil.writerequires(hgvfs, requirements)
3054 scmutil.writerequires(hgvfs, requirements)
3055
3055
3056 # Write out file telling readers where to find the shared store.
3056 # Write out file telling readers where to find the shared store.
3057 if 'sharedrepo' in createopts:
3057 if 'sharedrepo' in createopts:
3058 hgvfs.write(b'sharedpath', sharedpath)
3058 hgvfs.write(b'sharedpath', sharedpath)
3059
3059
3060 if createopts.get('shareditems'):
3060 if createopts.get('shareditems'):
3061 shared = b'\n'.join(sorted(createopts['shareditems'])) + b'\n'
3061 shared = b'\n'.join(sorted(createopts['shareditems'])) + b'\n'
3062 hgvfs.write(b'shared', shared)
3062 hgvfs.write(b'shared', shared)
3063
3063
3064 def poisonrepository(repo):
3064 def poisonrepository(repo):
3065 """Poison a repository instance so it can no longer be used."""
3065 """Poison a repository instance so it can no longer be used."""
3066 # Perform any cleanup on the instance.
3066 # Perform any cleanup on the instance.
3067 repo.close()
3067 repo.close()
3068
3068
3069 # Our strategy is to replace the type of the object with one that
3069 # Our strategy is to replace the type of the object with one that
3070 # has all attribute lookups result in error.
3070 # has all attribute lookups result in error.
3071 #
3071 #
3072 # But we have to allow the close() method because some constructors
3072 # But we have to allow the close() method because some constructors
3073 # of repos call close() on repo references.
3073 # of repos call close() on repo references.
3074 class poisonedrepository(object):
3074 class poisonedrepository(object):
3075 def __getattribute__(self, item):
3075 def __getattribute__(self, item):
3076 if item == r'close':
3076 if item == r'close':
3077 return object.__getattribute__(self, item)
3077 return object.__getattribute__(self, item)
3078
3078
3079 raise error.ProgrammingError('repo instances should not be used '
3079 raise error.ProgrammingError('repo instances should not be used '
3080 'after unshare')
3080 'after unshare')
3081
3081
3082 def close(self):
3082 def close(self):
3083 pass
3083 pass
3084
3084
3085 # We may have a repoview, which intercepts __setattr__. So be sure
3085 # We may have a repoview, which intercepts __setattr__. So be sure
3086 # we operate at the lowest level possible.
3086 # we operate at the lowest level possible.
3087 object.__setattr__(repo, r'__class__', poisonedrepository)
3087 object.__setattr__(repo, r'__class__', poisonedrepository)
@@ -1,928 +1,932 b''
1 Setting up test
1 Setting up test
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo 0 > afile
5 $ echo 0 > afile
6 $ hg add afile
6 $ hg add afile
7 $ hg commit -m "0.0"
7 $ hg commit -m "0.0"
8 $ echo 1 >> afile
8 $ echo 1 >> afile
9 $ hg commit -m "0.1"
9 $ hg commit -m "0.1"
10 $ echo 2 >> afile
10 $ echo 2 >> afile
11 $ hg commit -m "0.2"
11 $ hg commit -m "0.2"
12 $ echo 3 >> afile
12 $ echo 3 >> afile
13 $ hg commit -m "0.3"
13 $ hg commit -m "0.3"
14 $ hg update -C 0
14 $ hg update -C 0
15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
15 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
16 $ echo 1 >> afile
16 $ echo 1 >> afile
17 $ hg commit -m "1.1"
17 $ hg commit -m "1.1"
18 created new head
18 created new head
19 $ echo 2 >> afile
19 $ echo 2 >> afile
20 $ hg commit -m "1.2"
20 $ hg commit -m "1.2"
21 $ echo "a line" > fred
21 $ echo "a line" > fred
22 $ echo 3 >> afile
22 $ echo 3 >> afile
23 $ hg add fred
23 $ hg add fred
24 $ hg commit -m "1.3"
24 $ hg commit -m "1.3"
25 $ hg mv afile adifferentfile
25 $ hg mv afile adifferentfile
26 $ hg commit -m "1.3m"
26 $ hg commit -m "1.3m"
27 $ hg update -C 3
27 $ hg update -C 3
28 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
28 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
29 $ hg mv afile anotherfile
29 $ hg mv afile anotherfile
30 $ hg commit -m "0.3m"
30 $ hg commit -m "0.3m"
31 $ hg verify
31 $ hg verify
32 checking changesets
32 checking changesets
33 checking manifests
33 checking manifests
34 crosschecking files in changesets and manifests
34 crosschecking files in changesets and manifests
35 checking files
35 checking files
36 checked 9 changesets with 7 changes to 4 files
36 checked 9 changesets with 7 changes to 4 files
37 $ cd ..
37 $ cd ..
38 $ hg init empty
38 $ hg init empty
39
39
40 Bundle and phase
40 Bundle and phase
41
41
42 $ hg -R test phase --force --secret 0
42 $ hg -R test phase --force --secret 0
43 $ hg -R test bundle phase.hg empty
43 $ hg -R test bundle phase.hg empty
44 searching for changes
44 searching for changes
45 no changes found (ignored 9 secret changesets)
45 no changes found (ignored 9 secret changesets)
46 [1]
46 [1]
47 $ hg -R test phase --draft -r 'head()'
47 $ hg -R test phase --draft -r 'head()'
48
48
49 Bundle --all
49 Bundle --all
50
50
51 $ hg -R test bundle --all all.hg
51 $ hg -R test bundle --all all.hg
52 9 changesets found
52 9 changesets found
53
53
54 Bundle test to full.hg
54 Bundle test to full.hg
55
55
56 $ hg -R test bundle full.hg empty
56 $ hg -R test bundle full.hg empty
57 searching for changes
57 searching for changes
58 9 changesets found
58 9 changesets found
59
59
60 Unbundle full.hg in test
60 Unbundle full.hg in test
61
61
62 $ hg -R test unbundle full.hg
62 $ hg -R test unbundle full.hg
63 adding changesets
63 adding changesets
64 adding manifests
64 adding manifests
65 adding file changes
65 adding file changes
66 added 0 changesets with 0 changes to 4 files
66 added 0 changesets with 0 changes to 4 files
67 (run 'hg update' to get a working copy)
67 (run 'hg update' to get a working copy)
68
68
69 Verify empty
69 Verify empty
70
70
71 $ hg -R empty heads
71 $ hg -R empty heads
72 [1]
72 [1]
73 $ hg -R empty verify
73 $ hg -R empty verify
74 checking changesets
74 checking changesets
75 checking manifests
75 checking manifests
76 crosschecking files in changesets and manifests
76 crosschecking files in changesets and manifests
77 checking files
77 checking files
78 checked 0 changesets with 0 changes to 0 files
78 checked 0 changesets with 0 changes to 0 files
79
79
80 #if repobundlerepo
80 #if repobundlerepo
81
81
82 Pull full.hg into test (using --cwd)
82 Pull full.hg into test (using --cwd)
83
83
84 $ hg --cwd test pull ../full.hg
84 $ hg --cwd test pull ../full.hg
85 pulling from ../full.hg
85 pulling from ../full.hg
86 searching for changes
86 searching for changes
87 no changes found
87 no changes found
88
88
89 Verify that there are no leaked temporary files after pull (issue2797)
89 Verify that there are no leaked temporary files after pull (issue2797)
90
90
91 $ ls test/.hg | grep .hg10un
91 $ ls test/.hg | grep .hg10un
92 [1]
92 [1]
93
93
94 Pull full.hg into empty (using --cwd)
94 Pull full.hg into empty (using --cwd)
95
95
96 $ hg --cwd empty pull ../full.hg
96 $ hg --cwd empty pull ../full.hg
97 pulling from ../full.hg
97 pulling from ../full.hg
98 requesting all changes
98 requesting all changes
99 adding changesets
99 adding changesets
100 adding manifests
100 adding manifests
101 adding file changes
101 adding file changes
102 added 9 changesets with 7 changes to 4 files (+1 heads)
102 added 9 changesets with 7 changes to 4 files (+1 heads)
103 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
103 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
104 (run 'hg heads' to see heads, 'hg merge' to merge)
104 (run 'hg heads' to see heads, 'hg merge' to merge)
105
105
106 Rollback empty
106 Rollback empty
107
107
108 $ hg -R empty rollback
108 $ hg -R empty rollback
109 repository tip rolled back to revision -1 (undo pull)
109 repository tip rolled back to revision -1 (undo pull)
110
110
111 Pull full.hg into empty again (using --cwd)
111 Pull full.hg into empty again (using --cwd)
112
112
113 $ hg --cwd empty pull ../full.hg
113 $ hg --cwd empty pull ../full.hg
114 pulling from ../full.hg
114 pulling from ../full.hg
115 requesting all changes
115 requesting all changes
116 adding changesets
116 adding changesets
117 adding manifests
117 adding manifests
118 adding file changes
118 adding file changes
119 added 9 changesets with 7 changes to 4 files (+1 heads)
119 added 9 changesets with 7 changes to 4 files (+1 heads)
120 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
120 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
121 (run 'hg heads' to see heads, 'hg merge' to merge)
121 (run 'hg heads' to see heads, 'hg merge' to merge)
122
122
123 Pull full.hg into test (using -R)
123 Pull full.hg into test (using -R)
124
124
125 $ hg -R test pull full.hg
125 $ hg -R test pull full.hg
126 pulling from full.hg
126 pulling from full.hg
127 searching for changes
127 searching for changes
128 no changes found
128 no changes found
129
129
130 Pull full.hg into empty (using -R)
130 Pull full.hg into empty (using -R)
131
131
132 $ hg -R empty pull full.hg
132 $ hg -R empty pull full.hg
133 pulling from full.hg
133 pulling from full.hg
134 searching for changes
134 searching for changes
135 no changes found
135 no changes found
136
136
137 Rollback empty
137 Rollback empty
138
138
139 $ hg -R empty rollback
139 $ hg -R empty rollback
140 repository tip rolled back to revision -1 (undo pull)
140 repository tip rolled back to revision -1 (undo pull)
141
141
142 Pull full.hg into empty again (using -R)
142 Pull full.hg into empty again (using -R)
143
143
144 $ hg -R empty pull full.hg
144 $ hg -R empty pull full.hg
145 pulling from full.hg
145 pulling from full.hg
146 requesting all changes
146 requesting all changes
147 adding changesets
147 adding changesets
148 adding manifests
148 adding manifests
149 adding file changes
149 adding file changes
150 added 9 changesets with 7 changes to 4 files (+1 heads)
150 added 9 changesets with 7 changes to 4 files (+1 heads)
151 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
151 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
152 (run 'hg heads' to see heads, 'hg merge' to merge)
152 (run 'hg heads' to see heads, 'hg merge' to merge)
153
153
154 Log -R full.hg in fresh empty
154 Log -R full.hg in fresh empty
155
155
156 $ rm -r empty
156 $ rm -r empty
157 $ hg init empty
157 $ hg init empty
158 $ cd empty
158 $ cd empty
159 $ hg -R bundle://../full.hg log
159 $ hg -R bundle://../full.hg log
160 changeset: 8:aa35859c02ea
160 changeset: 8:aa35859c02ea
161 tag: tip
161 tag: tip
162 parent: 3:eebf5a27f8ca
162 parent: 3:eebf5a27f8ca
163 user: test
163 user: test
164 date: Thu Jan 01 00:00:00 1970 +0000
164 date: Thu Jan 01 00:00:00 1970 +0000
165 summary: 0.3m
165 summary: 0.3m
166
166
167 changeset: 7:a6a34bfa0076
167 changeset: 7:a6a34bfa0076
168 user: test
168 user: test
169 date: Thu Jan 01 00:00:00 1970 +0000
169 date: Thu Jan 01 00:00:00 1970 +0000
170 summary: 1.3m
170 summary: 1.3m
171
171
172 changeset: 6:7373c1169842
172 changeset: 6:7373c1169842
173 user: test
173 user: test
174 date: Thu Jan 01 00:00:00 1970 +0000
174 date: Thu Jan 01 00:00:00 1970 +0000
175 summary: 1.3
175 summary: 1.3
176
176
177 changeset: 5:1bb50a9436a7
177 changeset: 5:1bb50a9436a7
178 user: test
178 user: test
179 date: Thu Jan 01 00:00:00 1970 +0000
179 date: Thu Jan 01 00:00:00 1970 +0000
180 summary: 1.2
180 summary: 1.2
181
181
182 changeset: 4:095197eb4973
182 changeset: 4:095197eb4973
183 parent: 0:f9ee2f85a263
183 parent: 0:f9ee2f85a263
184 user: test
184 user: test
185 date: Thu Jan 01 00:00:00 1970 +0000
185 date: Thu Jan 01 00:00:00 1970 +0000
186 summary: 1.1
186 summary: 1.1
187
187
188 changeset: 3:eebf5a27f8ca
188 changeset: 3:eebf5a27f8ca
189 user: test
189 user: test
190 date: Thu Jan 01 00:00:00 1970 +0000
190 date: Thu Jan 01 00:00:00 1970 +0000
191 summary: 0.3
191 summary: 0.3
192
192
193 changeset: 2:e38ba6f5b7e0
193 changeset: 2:e38ba6f5b7e0
194 user: test
194 user: test
195 date: Thu Jan 01 00:00:00 1970 +0000
195 date: Thu Jan 01 00:00:00 1970 +0000
196 summary: 0.2
196 summary: 0.2
197
197
198 changeset: 1:34c2bf6b0626
198 changeset: 1:34c2bf6b0626
199 user: test
199 user: test
200 date: Thu Jan 01 00:00:00 1970 +0000
200 date: Thu Jan 01 00:00:00 1970 +0000
201 summary: 0.1
201 summary: 0.1
202
202
203 changeset: 0:f9ee2f85a263
203 changeset: 0:f9ee2f85a263
204 user: test
204 user: test
205 date: Thu Jan 01 00:00:00 1970 +0000
205 date: Thu Jan 01 00:00:00 1970 +0000
206 summary: 0.0
206 summary: 0.0
207
207
208 Make sure bundlerepo doesn't leak tempfiles (issue2491)
208 Make sure bundlerepo doesn't leak tempfiles (issue2491)
209
209
210 $ ls .hg
210 $ ls .hg
211 00changelog.i
211 00changelog.i
212 cache
212 cache
213 requires
213 requires
214 store
214 store
215 wcache
215 wcache
216
216
217 Pull ../full.hg into empty (with hook)
217 Pull ../full.hg into empty (with hook)
218
218
219 $ cat >> .hg/hgrc <<EOF
219 $ cat >> .hg/hgrc <<EOF
220 > [hooks]
220 > [hooks]
221 > changegroup = sh -c "printenv.py --line changegroup"
221 > changegroup = sh -c "printenv.py --line changegroup"
222 > EOF
222 > EOF
223
223
224 doesn't work (yet ?)
224 doesn't work (yet ?)
225 NOTE: msys is mangling the URL below
225 NOTE: msys is mangling the URL below
226
226
227 hg -R bundle://../full.hg verify
227 hg -R bundle://../full.hg verify
228
228
229 $ hg pull bundle://../full.hg
229 $ hg pull bundle://../full.hg
230 pulling from bundle:../full.hg
230 pulling from bundle:../full.hg
231 requesting all changes
231 requesting all changes
232 adding changesets
232 adding changesets
233 adding manifests
233 adding manifests
234 adding file changes
234 adding file changes
235 added 9 changesets with 7 changes to 4 files (+1 heads)
235 added 9 changesets with 7 changes to 4 files (+1 heads)
236 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
236 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
237 changegroup hook: HG_HOOKNAME=changegroup
237 changegroup hook: HG_HOOKNAME=changegroup
238 HG_HOOKTYPE=changegroup
238 HG_HOOKTYPE=changegroup
239 HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735
239 HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735
240 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf
240 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf
241 HG_SOURCE=pull
241 HG_SOURCE=pull
242 HG_TXNID=TXN:$ID$
242 HG_TXNID=TXN:$ID$
243 HG_TXNNAME=pull
244 bundle:../full.hg
243 HG_URL=bundle:../full.hg (no-msys !)
245 HG_URL=bundle:../full.hg (no-msys !)
244 HG_URL=bundle;../full.hg (msys !)
246 HG_URL=bundle;../full.hg (msys !)
245
247
246 (run 'hg heads' to see heads, 'hg merge' to merge)
248 (run 'hg heads' to see heads, 'hg merge' to merge)
247
249
248 Rollback empty
250 Rollback empty
249
251
250 $ hg rollback
252 $ hg rollback
251 repository tip rolled back to revision -1 (undo pull)
253 repository tip rolled back to revision -1 (undo pull)
252 $ cd ..
254 $ cd ..
253
255
254 Log -R bundle:empty+full.hg
256 Log -R bundle:empty+full.hg
255
257
256 $ hg -R bundle:empty+full.hg log --template="{rev} "; echo ""
258 $ hg -R bundle:empty+full.hg log --template="{rev} "; echo ""
257 8 7 6 5 4 3 2 1 0
259 8 7 6 5 4 3 2 1 0
258
260
259 Pull full.hg into empty again (using -R; with hook)
261 Pull full.hg into empty again (using -R; with hook)
260
262
261 $ hg -R empty pull full.hg
263 $ hg -R empty pull full.hg
262 pulling from full.hg
264 pulling from full.hg
263 requesting all changes
265 requesting all changes
264 adding changesets
266 adding changesets
265 adding manifests
267 adding manifests
266 adding file changes
268 adding file changes
267 added 9 changesets with 7 changes to 4 files (+1 heads)
269 added 9 changesets with 7 changes to 4 files (+1 heads)
268 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
270 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
269 changegroup hook: HG_HOOKNAME=changegroup
271 changegroup hook: HG_HOOKNAME=changegroup
270 HG_HOOKTYPE=changegroup
272 HG_HOOKTYPE=changegroup
271 HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735
273 HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735
272 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf
274 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf
273 HG_SOURCE=pull
275 HG_SOURCE=pull
274 HG_TXNID=TXN:$ID$
276 HG_TXNID=TXN:$ID$
277 HG_TXNNAME=pull
278 bundle:empty+full.hg
275 HG_URL=bundle:empty+full.hg
279 HG_URL=bundle:empty+full.hg
276
280
277 (run 'hg heads' to see heads, 'hg merge' to merge)
281 (run 'hg heads' to see heads, 'hg merge' to merge)
278
282
279 #endif
283 #endif
280
284
281 Cannot produce streaming clone bundles with "hg bundle"
285 Cannot produce streaming clone bundles with "hg bundle"
282
286
283 $ hg -R test bundle -t packed1 packed.hg
287 $ hg -R test bundle -t packed1 packed.hg
284 abort: packed bundles cannot be produced by "hg bundle"
288 abort: packed bundles cannot be produced by "hg bundle"
285 (use 'hg debugcreatestreamclonebundle')
289 (use 'hg debugcreatestreamclonebundle')
286 [255]
290 [255]
287
291
288 packed1 is produced properly
292 packed1 is produced properly
289
293
290 #if reporevlogstore
294 #if reporevlogstore
291
295
292 $ hg -R test debugcreatestreamclonebundle packed.hg
296 $ hg -R test debugcreatestreamclonebundle packed.hg
293 writing 2664 bytes for 6 files
297 writing 2664 bytes for 6 files
294 bundle requirements: generaldelta, revlogv1, sparserevlog
298 bundle requirements: generaldelta, revlogv1, sparserevlog
295
299
296 $ f -B 64 --size --sha1 --hexdump packed.hg
300 $ f -B 64 --size --sha1 --hexdump packed.hg
297 packed.hg: size=2840, sha1=12bf3eee3eb8a04c503ce2d29b48f0135c7edff5
301 packed.hg: size=2840, sha1=12bf3eee3eb8a04c503ce2d29b48f0135c7edff5
298 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 06 00 00 |HGS1UN..........|
302 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 06 00 00 |HGS1UN..........|
299 0010: 00 00 00 00 0a 68 00 23 67 65 6e 65 72 61 6c 64 |.....h.#generald|
303 0010: 00 00 00 00 0a 68 00 23 67 65 6e 65 72 61 6c 64 |.....h.#generald|
300 0020: 65 6c 74 61 2c 72 65 76 6c 6f 67 76 31 2c 73 70 |elta,revlogv1,sp|
304 0020: 65 6c 74 61 2c 72 65 76 6c 6f 67 76 31 2c 73 70 |elta,revlogv1,sp|
301 0030: 61 72 73 65 72 65 76 6c 6f 67 00 64 61 74 61 2f |arserevlog.data/|
305 0030: 61 72 73 65 72 65 76 6c 6f 67 00 64 61 74 61 2f |arserevlog.data/|
302
306
303 $ hg debugbundle --spec packed.hg
307 $ hg debugbundle --spec packed.hg
304 none-packed1;requirements%3Dgeneraldelta%2Crevlogv1%2Csparserevlog
308 none-packed1;requirements%3Dgeneraldelta%2Crevlogv1%2Csparserevlog
305
309
306 generaldelta requirement is not listed in stream clone bundles unless used
310 generaldelta requirement is not listed in stream clone bundles unless used
307
311
308 $ hg --config format.usegeneraldelta=false init testnongd
312 $ hg --config format.usegeneraldelta=false init testnongd
309 $ cd testnongd
313 $ cd testnongd
310 $ touch foo
314 $ touch foo
311 $ hg -q commit -A -m initial
315 $ hg -q commit -A -m initial
312 $ cd ..
316 $ cd ..
313 $ hg -R testnongd debugcreatestreamclonebundle packednongd.hg
317 $ hg -R testnongd debugcreatestreamclonebundle packednongd.hg
314 writing 301 bytes for 3 files
318 writing 301 bytes for 3 files
315 bundle requirements: revlogv1
319 bundle requirements: revlogv1
316
320
317 $ f -B 64 --size --sha1 --hexdump packednongd.hg
321 $ f -B 64 --size --sha1 --hexdump packednongd.hg
318 packednongd.hg: size=383, sha1=1d9c230238edd5d38907100b729ba72b1831fe6f
322 packednongd.hg: size=383, sha1=1d9c230238edd5d38907100b729ba72b1831fe6f
319 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 03 00 00 |HGS1UN..........|
323 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 03 00 00 |HGS1UN..........|
320 0010: 00 00 00 00 01 2d 00 09 72 65 76 6c 6f 67 76 31 |.....-..revlogv1|
324 0010: 00 00 00 00 01 2d 00 09 72 65 76 6c 6f 67 76 31 |.....-..revlogv1|
321 0020: 00 64 61 74 61 2f 66 6f 6f 2e 69 00 36 34 0a 00 |.data/foo.i.64..|
325 0020: 00 64 61 74 61 2f 66 6f 6f 2e 69 00 36 34 0a 00 |.data/foo.i.64..|
322 0030: 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
326 0030: 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
323
327
324 $ hg debugbundle --spec packednongd.hg
328 $ hg debugbundle --spec packednongd.hg
325 none-packed1;requirements%3Drevlogv1
329 none-packed1;requirements%3Drevlogv1
326
330
327 Warning emitted when packed bundles contain secret changesets
331 Warning emitted when packed bundles contain secret changesets
328
332
329 $ hg init testsecret
333 $ hg init testsecret
330 $ cd testsecret
334 $ cd testsecret
331 $ touch foo
335 $ touch foo
332 $ hg -q commit -A -m initial
336 $ hg -q commit -A -m initial
333 $ hg phase --force --secret -r .
337 $ hg phase --force --secret -r .
334 $ cd ..
338 $ cd ..
335
339
336 $ hg -R testsecret debugcreatestreamclonebundle packedsecret.hg
340 $ hg -R testsecret debugcreatestreamclonebundle packedsecret.hg
337 (warning: stream clone bundle will contain secret revisions)
341 (warning: stream clone bundle will contain secret revisions)
338 writing 301 bytes for 3 files
342 writing 301 bytes for 3 files
339 bundle requirements: generaldelta, revlogv1, sparserevlog
343 bundle requirements: generaldelta, revlogv1, sparserevlog
340
344
341 Unpacking packed1 bundles with "hg unbundle" isn't allowed
345 Unpacking packed1 bundles with "hg unbundle" isn't allowed
342
346
343 $ hg init packed
347 $ hg init packed
344 $ hg -R packed unbundle packed.hg
348 $ hg -R packed unbundle packed.hg
345 abort: packed bundles cannot be applied with "hg unbundle"
349 abort: packed bundles cannot be applied with "hg unbundle"
346 (use "hg debugapplystreamclonebundle")
350 (use "hg debugapplystreamclonebundle")
347 [255]
351 [255]
348
352
349 packed1 can be consumed from debug command
353 packed1 can be consumed from debug command
350
354
351 (this also confirms that streamclone-ed changes are visible via
355 (this also confirms that streamclone-ed changes are visible via
352 @filecache properties to in-process procedures before closing
356 @filecache properties to in-process procedures before closing
353 transaction)
357 transaction)
354
358
355 $ cat > $TESTTMP/showtip.py <<EOF
359 $ cat > $TESTTMP/showtip.py <<EOF
356 > from __future__ import absolute_import
360 > from __future__ import absolute_import
357 >
361 >
358 > def showtip(ui, repo, hooktype, **kwargs):
362 > def showtip(ui, repo, hooktype, **kwargs):
359 > ui.warn(b'%s: %s\n' % (hooktype, repo[b'tip'].hex()[:12]))
363 > ui.warn(b'%s: %s\n' % (hooktype, repo[b'tip'].hex()[:12]))
360 >
364 >
361 > def reposetup(ui, repo):
365 > def reposetup(ui, repo):
362 > # this confirms (and ensures) that (empty) 00changelog.i
366 > # this confirms (and ensures) that (empty) 00changelog.i
363 > # before streamclone is already cached as repo.changelog
367 > # before streamclone is already cached as repo.changelog
364 > ui.setconfig(b'hooks', b'pretxnopen.showtip', showtip)
368 > ui.setconfig(b'hooks', b'pretxnopen.showtip', showtip)
365 >
369 >
366 > # this confirms that streamclone-ed changes are visible to
370 > # this confirms that streamclone-ed changes are visible to
367 > # in-process procedures before closing transaction
371 > # in-process procedures before closing transaction
368 > ui.setconfig(b'hooks', b'pretxnclose.showtip', showtip)
372 > ui.setconfig(b'hooks', b'pretxnclose.showtip', showtip)
369 >
373 >
370 > # this confirms that streamclone-ed changes are still visible
374 > # this confirms that streamclone-ed changes are still visible
371 > # after closing transaction
375 > # after closing transaction
372 > ui.setconfig(b'hooks', b'txnclose.showtip', showtip)
376 > ui.setconfig(b'hooks', b'txnclose.showtip', showtip)
373 > EOF
377 > EOF
374 $ cat >> $HGRCPATH <<EOF
378 $ cat >> $HGRCPATH <<EOF
375 > [extensions]
379 > [extensions]
376 > showtip = $TESTTMP/showtip.py
380 > showtip = $TESTTMP/showtip.py
377 > EOF
381 > EOF
378
382
379 $ hg -R packed debugapplystreamclonebundle packed.hg
383 $ hg -R packed debugapplystreamclonebundle packed.hg
380 6 files to transfer, 2.60 KB of data
384 6 files to transfer, 2.60 KB of data
381 pretxnopen: 000000000000
385 pretxnopen: 000000000000
382 pretxnclose: aa35859c02ea
386 pretxnclose: aa35859c02ea
383 transferred 2.60 KB in *.* seconds (* */sec) (glob)
387 transferred 2.60 KB in *.* seconds (* */sec) (glob)
384 txnclose: aa35859c02ea
388 txnclose: aa35859c02ea
385
389
386 (for safety, confirm visibility of streamclone-ed changes by another
390 (for safety, confirm visibility of streamclone-ed changes by another
387 process, too)
391 process, too)
388
392
389 $ hg -R packed tip -T "{node|short}\n"
393 $ hg -R packed tip -T "{node|short}\n"
390 aa35859c02ea
394 aa35859c02ea
391
395
392 $ cat >> $HGRCPATH <<EOF
396 $ cat >> $HGRCPATH <<EOF
393 > [extensions]
397 > [extensions]
394 > showtip = !
398 > showtip = !
395 > EOF
399 > EOF
396
400
397 Does not work on non-empty repo
401 Does not work on non-empty repo
398
402
399 $ hg -R packed debugapplystreamclonebundle packed.hg
403 $ hg -R packed debugapplystreamclonebundle packed.hg
400 abort: cannot apply stream clone bundle on non-empty repo
404 abort: cannot apply stream clone bundle on non-empty repo
401 [255]
405 [255]
402
406
403 #endif
407 #endif
404
408
405 Create partial clones
409 Create partial clones
406
410
407 $ rm -r empty
411 $ rm -r empty
408 $ hg init empty
412 $ hg init empty
409 $ hg clone -r 3 test partial
413 $ hg clone -r 3 test partial
410 adding changesets
414 adding changesets
411 adding manifests
415 adding manifests
412 adding file changes
416 adding file changes
413 added 4 changesets with 4 changes to 1 files
417 added 4 changesets with 4 changes to 1 files
414 new changesets f9ee2f85a263:eebf5a27f8ca
418 new changesets f9ee2f85a263:eebf5a27f8ca
415 updating to branch default
419 updating to branch default
416 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
417 $ hg clone partial partial2
421 $ hg clone partial partial2
418 updating to branch default
422 updating to branch default
419 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
423 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
420 $ cd partial
424 $ cd partial
421
425
422 #if repobundlerepo
426 #if repobundlerepo
423
427
424 Log -R full.hg in partial
428 Log -R full.hg in partial
425
429
426 $ hg -R bundle://../full.hg log -T phases
430 $ hg -R bundle://../full.hg log -T phases
427 changeset: 8:aa35859c02ea
431 changeset: 8:aa35859c02ea
428 tag: tip
432 tag: tip
429 phase: draft
433 phase: draft
430 parent: 3:eebf5a27f8ca
434 parent: 3:eebf5a27f8ca
431 user: test
435 user: test
432 date: Thu Jan 01 00:00:00 1970 +0000
436 date: Thu Jan 01 00:00:00 1970 +0000
433 summary: 0.3m
437 summary: 0.3m
434
438
435 changeset: 7:a6a34bfa0076
439 changeset: 7:a6a34bfa0076
436 phase: draft
440 phase: draft
437 user: test
441 user: test
438 date: Thu Jan 01 00:00:00 1970 +0000
442 date: Thu Jan 01 00:00:00 1970 +0000
439 summary: 1.3m
443 summary: 1.3m
440
444
441 changeset: 6:7373c1169842
445 changeset: 6:7373c1169842
442 phase: draft
446 phase: draft
443 user: test
447 user: test
444 date: Thu Jan 01 00:00:00 1970 +0000
448 date: Thu Jan 01 00:00:00 1970 +0000
445 summary: 1.3
449 summary: 1.3
446
450
447 changeset: 5:1bb50a9436a7
451 changeset: 5:1bb50a9436a7
448 phase: draft
452 phase: draft
449 user: test
453 user: test
450 date: Thu Jan 01 00:00:00 1970 +0000
454 date: Thu Jan 01 00:00:00 1970 +0000
451 summary: 1.2
455 summary: 1.2
452
456
453 changeset: 4:095197eb4973
457 changeset: 4:095197eb4973
454 phase: draft
458 phase: draft
455 parent: 0:f9ee2f85a263
459 parent: 0:f9ee2f85a263
456 user: test
460 user: test
457 date: Thu Jan 01 00:00:00 1970 +0000
461 date: Thu Jan 01 00:00:00 1970 +0000
458 summary: 1.1
462 summary: 1.1
459
463
460 changeset: 3:eebf5a27f8ca
464 changeset: 3:eebf5a27f8ca
461 phase: public
465 phase: public
462 user: test
466 user: test
463 date: Thu Jan 01 00:00:00 1970 +0000
467 date: Thu Jan 01 00:00:00 1970 +0000
464 summary: 0.3
468 summary: 0.3
465
469
466 changeset: 2:e38ba6f5b7e0
470 changeset: 2:e38ba6f5b7e0
467 phase: public
471 phase: public
468 user: test
472 user: test
469 date: Thu Jan 01 00:00:00 1970 +0000
473 date: Thu Jan 01 00:00:00 1970 +0000
470 summary: 0.2
474 summary: 0.2
471
475
472 changeset: 1:34c2bf6b0626
476 changeset: 1:34c2bf6b0626
473 phase: public
477 phase: public
474 user: test
478 user: test
475 date: Thu Jan 01 00:00:00 1970 +0000
479 date: Thu Jan 01 00:00:00 1970 +0000
476 summary: 0.1
480 summary: 0.1
477
481
478 changeset: 0:f9ee2f85a263
482 changeset: 0:f9ee2f85a263
479 phase: public
483 phase: public
480 user: test
484 user: test
481 date: Thu Jan 01 00:00:00 1970 +0000
485 date: Thu Jan 01 00:00:00 1970 +0000
482 summary: 0.0
486 summary: 0.0
483
487
484
488
485 Incoming full.hg in partial
489 Incoming full.hg in partial
486
490
487 $ hg incoming bundle://../full.hg
491 $ hg incoming bundle://../full.hg
488 comparing with bundle:../full.hg
492 comparing with bundle:../full.hg
489 searching for changes
493 searching for changes
490 changeset: 4:095197eb4973
494 changeset: 4:095197eb4973
491 parent: 0:f9ee2f85a263
495 parent: 0:f9ee2f85a263
492 user: test
496 user: test
493 date: Thu Jan 01 00:00:00 1970 +0000
497 date: Thu Jan 01 00:00:00 1970 +0000
494 summary: 1.1
498 summary: 1.1
495
499
496 changeset: 5:1bb50a9436a7
500 changeset: 5:1bb50a9436a7
497 user: test
501 user: test
498 date: Thu Jan 01 00:00:00 1970 +0000
502 date: Thu Jan 01 00:00:00 1970 +0000
499 summary: 1.2
503 summary: 1.2
500
504
501 changeset: 6:7373c1169842
505 changeset: 6:7373c1169842
502 user: test
506 user: test
503 date: Thu Jan 01 00:00:00 1970 +0000
507 date: Thu Jan 01 00:00:00 1970 +0000
504 summary: 1.3
508 summary: 1.3
505
509
506 changeset: 7:a6a34bfa0076
510 changeset: 7:a6a34bfa0076
507 user: test
511 user: test
508 date: Thu Jan 01 00:00:00 1970 +0000
512 date: Thu Jan 01 00:00:00 1970 +0000
509 summary: 1.3m
513 summary: 1.3m
510
514
511 changeset: 8:aa35859c02ea
515 changeset: 8:aa35859c02ea
512 tag: tip
516 tag: tip
513 parent: 3:eebf5a27f8ca
517 parent: 3:eebf5a27f8ca
514 user: test
518 user: test
515 date: Thu Jan 01 00:00:00 1970 +0000
519 date: Thu Jan 01 00:00:00 1970 +0000
516 summary: 0.3m
520 summary: 0.3m
517
521
518
522
519 Outgoing -R full.hg vs partial2 in partial
523 Outgoing -R full.hg vs partial2 in partial
520
524
521 $ hg -R bundle://../full.hg outgoing ../partial2
525 $ hg -R bundle://../full.hg outgoing ../partial2
522 comparing with ../partial2
526 comparing with ../partial2
523 searching for changes
527 searching for changes
524 changeset: 4:095197eb4973
528 changeset: 4:095197eb4973
525 parent: 0:f9ee2f85a263
529 parent: 0:f9ee2f85a263
526 user: test
530 user: test
527 date: Thu Jan 01 00:00:00 1970 +0000
531 date: Thu Jan 01 00:00:00 1970 +0000
528 summary: 1.1
532 summary: 1.1
529
533
530 changeset: 5:1bb50a9436a7
534 changeset: 5:1bb50a9436a7
531 user: test
535 user: test
532 date: Thu Jan 01 00:00:00 1970 +0000
536 date: Thu Jan 01 00:00:00 1970 +0000
533 summary: 1.2
537 summary: 1.2
534
538
535 changeset: 6:7373c1169842
539 changeset: 6:7373c1169842
536 user: test
540 user: test
537 date: Thu Jan 01 00:00:00 1970 +0000
541 date: Thu Jan 01 00:00:00 1970 +0000
538 summary: 1.3
542 summary: 1.3
539
543
540 changeset: 7:a6a34bfa0076
544 changeset: 7:a6a34bfa0076
541 user: test
545 user: test
542 date: Thu Jan 01 00:00:00 1970 +0000
546 date: Thu Jan 01 00:00:00 1970 +0000
543 summary: 1.3m
547 summary: 1.3m
544
548
545 changeset: 8:aa35859c02ea
549 changeset: 8:aa35859c02ea
546 tag: tip
550 tag: tip
547 parent: 3:eebf5a27f8ca
551 parent: 3:eebf5a27f8ca
548 user: test
552 user: test
549 date: Thu Jan 01 00:00:00 1970 +0000
553 date: Thu Jan 01 00:00:00 1970 +0000
550 summary: 0.3m
554 summary: 0.3m
551
555
552
556
553 Outgoing -R does-not-exist.hg vs partial2 in partial
557 Outgoing -R does-not-exist.hg vs partial2 in partial
554
558
555 $ hg -R bundle://../does-not-exist.hg outgoing ../partial2
559 $ hg -R bundle://../does-not-exist.hg outgoing ../partial2
556 abort: *../does-not-exist.hg* (glob)
560 abort: *../does-not-exist.hg* (glob)
557 [255]
561 [255]
558
562
559 #endif
563 #endif
560
564
561 $ cd ..
565 $ cd ..
562
566
563 hide outer repo
567 hide outer repo
564 $ hg init
568 $ hg init
565
569
566 Direct clone from bundle (all-history)
570 Direct clone from bundle (all-history)
567
571
568 #if repobundlerepo
572 #if repobundlerepo
569
573
570 $ hg clone full.hg full-clone
574 $ hg clone full.hg full-clone
571 requesting all changes
575 requesting all changes
572 adding changesets
576 adding changesets
573 adding manifests
577 adding manifests
574 adding file changes
578 adding file changes
575 added 9 changesets with 7 changes to 4 files (+1 heads)
579 added 9 changesets with 7 changes to 4 files (+1 heads)
576 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
580 new changesets f9ee2f85a263:aa35859c02ea (9 drafts)
577 updating to branch default
581 updating to branch default
578 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
582 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
579 $ hg -R full-clone heads
583 $ hg -R full-clone heads
580 changeset: 8:aa35859c02ea
584 changeset: 8:aa35859c02ea
581 tag: tip
585 tag: tip
582 parent: 3:eebf5a27f8ca
586 parent: 3:eebf5a27f8ca
583 user: test
587 user: test
584 date: Thu Jan 01 00:00:00 1970 +0000
588 date: Thu Jan 01 00:00:00 1970 +0000
585 summary: 0.3m
589 summary: 0.3m
586
590
587 changeset: 7:a6a34bfa0076
591 changeset: 7:a6a34bfa0076
588 user: test
592 user: test
589 date: Thu Jan 01 00:00:00 1970 +0000
593 date: Thu Jan 01 00:00:00 1970 +0000
590 summary: 1.3m
594 summary: 1.3m
591
595
592 $ rm -r full-clone
596 $ rm -r full-clone
593
597
594 When cloning from a non-copiable repository into '', do not
598 When cloning from a non-copiable repository into '', do not
595 recurse infinitely (issue2528)
599 recurse infinitely (issue2528)
596
600
597 $ hg clone full.hg ''
601 $ hg clone full.hg ''
598 abort: empty destination path is not valid
602 abort: empty destination path is not valid
599 [255]
603 [255]
600
604
601 test for https://bz.mercurial-scm.org/216
605 test for https://bz.mercurial-scm.org/216
602
606
603 Unbundle incremental bundles into fresh empty in one go
607 Unbundle incremental bundles into fresh empty in one go
604
608
605 $ rm -r empty
609 $ rm -r empty
606 $ hg init empty
610 $ hg init empty
607 $ hg -R test bundle --base null -r 0 ../0.hg
611 $ hg -R test bundle --base null -r 0 ../0.hg
608 1 changesets found
612 1 changesets found
609 $ hg -R test bundle --base 0 -r 1 ../1.hg
613 $ hg -R test bundle --base 0 -r 1 ../1.hg
610 1 changesets found
614 1 changesets found
611 $ hg -R empty unbundle -u ../0.hg ../1.hg
615 $ hg -R empty unbundle -u ../0.hg ../1.hg
612 adding changesets
616 adding changesets
613 adding manifests
617 adding manifests
614 adding file changes
618 adding file changes
615 added 1 changesets with 1 changes to 1 files
619 added 1 changesets with 1 changes to 1 files
616 new changesets f9ee2f85a263 (1 drafts)
620 new changesets f9ee2f85a263 (1 drafts)
617 adding changesets
621 adding changesets
618 adding manifests
622 adding manifests
619 adding file changes
623 adding file changes
620 added 1 changesets with 1 changes to 1 files
624 added 1 changesets with 1 changes to 1 files
621 new changesets 34c2bf6b0626 (1 drafts)
625 new changesets 34c2bf6b0626 (1 drafts)
622 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
626 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
623
627
624 View full contents of the bundle
628 View full contents of the bundle
625 $ hg -R test bundle --base null -r 3 ../partial.hg
629 $ hg -R test bundle --base null -r 3 ../partial.hg
626 4 changesets found
630 4 changesets found
627 $ cd test
631 $ cd test
628 $ hg -R ../../partial.hg log -r "bundle()"
632 $ hg -R ../../partial.hg log -r "bundle()"
629 changeset: 0:f9ee2f85a263
633 changeset: 0:f9ee2f85a263
630 user: test
634 user: test
631 date: Thu Jan 01 00:00:00 1970 +0000
635 date: Thu Jan 01 00:00:00 1970 +0000
632 summary: 0.0
636 summary: 0.0
633
637
634 changeset: 1:34c2bf6b0626
638 changeset: 1:34c2bf6b0626
635 user: test
639 user: test
636 date: Thu Jan 01 00:00:00 1970 +0000
640 date: Thu Jan 01 00:00:00 1970 +0000
637 summary: 0.1
641 summary: 0.1
638
642
639 changeset: 2:e38ba6f5b7e0
643 changeset: 2:e38ba6f5b7e0
640 user: test
644 user: test
641 date: Thu Jan 01 00:00:00 1970 +0000
645 date: Thu Jan 01 00:00:00 1970 +0000
642 summary: 0.2
646 summary: 0.2
643
647
644 changeset: 3:eebf5a27f8ca
648 changeset: 3:eebf5a27f8ca
645 user: test
649 user: test
646 date: Thu Jan 01 00:00:00 1970 +0000
650 date: Thu Jan 01 00:00:00 1970 +0000
647 summary: 0.3
651 summary: 0.3
648
652
649 $ cd ..
653 $ cd ..
650
654
651 #endif
655 #endif
652
656
653 test for 540d1059c802
657 test for 540d1059c802
654
658
655 $ hg init orig
659 $ hg init orig
656 $ cd orig
660 $ cd orig
657 $ echo foo > foo
661 $ echo foo > foo
658 $ hg add foo
662 $ hg add foo
659 $ hg ci -m 'add foo'
663 $ hg ci -m 'add foo'
660
664
661 $ hg clone . ../copy
665 $ hg clone . ../copy
662 updating to branch default
666 updating to branch default
663 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
667 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
664 $ hg tag foo
668 $ hg tag foo
665
669
666 $ cd ../copy
670 $ cd ../copy
667 $ echo >> foo
671 $ echo >> foo
668 $ hg ci -m 'change foo'
672 $ hg ci -m 'change foo'
669 $ hg bundle ../bundle.hg ../orig
673 $ hg bundle ../bundle.hg ../orig
670 searching for changes
674 searching for changes
671 1 changesets found
675 1 changesets found
672
676
673 $ cd ..
677 $ cd ..
674
678
675 #if repobundlerepo
679 #if repobundlerepo
676 $ cd orig
680 $ cd orig
677 $ hg incoming ../bundle.hg
681 $ hg incoming ../bundle.hg
678 comparing with ../bundle.hg
682 comparing with ../bundle.hg
679 searching for changes
683 searching for changes
680 changeset: 2:ed1b79f46b9a
684 changeset: 2:ed1b79f46b9a
681 tag: tip
685 tag: tip
682 parent: 0:bbd179dfa0a7
686 parent: 0:bbd179dfa0a7
683 user: test
687 user: test
684 date: Thu Jan 01 00:00:00 1970 +0000
688 date: Thu Jan 01 00:00:00 1970 +0000
685 summary: change foo
689 summary: change foo
686
690
687 $ cd ..
691 $ cd ..
688
692
689 test bundle with # in the filename (issue2154):
693 test bundle with # in the filename (issue2154):
690
694
691 $ cp bundle.hg 'test#bundle.hg'
695 $ cp bundle.hg 'test#bundle.hg'
692 $ cd orig
696 $ cd orig
693 $ hg incoming '../test#bundle.hg'
697 $ hg incoming '../test#bundle.hg'
694 comparing with ../test
698 comparing with ../test
695 abort: unknown revision 'bundle.hg'!
699 abort: unknown revision 'bundle.hg'!
696 [255]
700 [255]
697
701
698 note that percent encoding is not handled:
702 note that percent encoding is not handled:
699
703
700 $ hg incoming ../test%23bundle.hg
704 $ hg incoming ../test%23bundle.hg
701 abort: repository ../test%23bundle.hg not found!
705 abort: repository ../test%23bundle.hg not found!
702 [255]
706 [255]
703 $ cd ..
707 $ cd ..
704
708
705 #endif
709 #endif
706
710
707 test to bundle revisions on the newly created branch (issue3828):
711 test to bundle revisions on the newly created branch (issue3828):
708
712
709 $ hg -q clone -U test test-clone
713 $ hg -q clone -U test test-clone
710 $ cd test
714 $ cd test
711
715
712 $ hg -q branch foo
716 $ hg -q branch foo
713 $ hg commit -m "create foo branch"
717 $ hg commit -m "create foo branch"
714 $ hg -q outgoing ../test-clone
718 $ hg -q outgoing ../test-clone
715 9:b4f5acb1ee27
719 9:b4f5acb1ee27
716 $ hg -q bundle --branch foo foo.hg ../test-clone
720 $ hg -q bundle --branch foo foo.hg ../test-clone
717 #if repobundlerepo
721 #if repobundlerepo
718 $ hg -R foo.hg -q log -r "bundle()"
722 $ hg -R foo.hg -q log -r "bundle()"
719 9:b4f5acb1ee27
723 9:b4f5acb1ee27
720 #endif
724 #endif
721
725
722 $ cd ..
726 $ cd ..
723
727
724 test for https://bz.mercurial-scm.org/1144
728 test for https://bz.mercurial-scm.org/1144
725
729
726 test that verify bundle does not traceback
730 test that verify bundle does not traceback
727
731
728 partial history bundle, fails w/ unknown parent
732 partial history bundle, fails w/ unknown parent
729
733
730 $ hg -R bundle.hg verify
734 $ hg -R bundle.hg verify
731 abort: 00changelog.i@bbd179dfa0a7: unknown parent!
735 abort: 00changelog.i@bbd179dfa0a7: unknown parent!
732 [255]
736 [255]
733
737
734 full history bundle, refuses to verify non-local repo
738 full history bundle, refuses to verify non-local repo
735
739
736 #if repobundlerepo
740 #if repobundlerepo
737 $ hg -R all.hg verify
741 $ hg -R all.hg verify
738 abort: cannot verify bundle or remote repos
742 abort: cannot verify bundle or remote repos
739 [255]
743 [255]
740 #endif
744 #endif
741
745
742 but, regular verify must continue to work
746 but, regular verify must continue to work
743
747
744 $ hg -R orig verify
748 $ hg -R orig verify
745 checking changesets
749 checking changesets
746 checking manifests
750 checking manifests
747 crosschecking files in changesets and manifests
751 crosschecking files in changesets and manifests
748 checking files
752 checking files
749 checked 2 changesets with 2 changes to 2 files
753 checked 2 changesets with 2 changes to 2 files
750
754
751 #if repobundlerepo
755 #if repobundlerepo
752 diff against bundle
756 diff against bundle
753
757
754 $ hg init b
758 $ hg init b
755 $ cd b
759 $ cd b
756 $ hg -R ../all.hg diff -r tip
760 $ hg -R ../all.hg diff -r tip
757 diff -r aa35859c02ea anotherfile
761 diff -r aa35859c02ea anotherfile
758 --- a/anotherfile Thu Jan 01 00:00:00 1970 +0000
762 --- a/anotherfile Thu Jan 01 00:00:00 1970 +0000
759 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
763 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
760 @@ -1,4 +0,0 @@
764 @@ -1,4 +0,0 @@
761 -0
765 -0
762 -1
766 -1
763 -2
767 -2
764 -3
768 -3
765 $ cd ..
769 $ cd ..
766 #endif
770 #endif
767
771
768 bundle single branch
772 bundle single branch
769
773
770 $ hg init branchy
774 $ hg init branchy
771 $ cd branchy
775 $ cd branchy
772 $ echo a >a
776 $ echo a >a
773 $ echo x >x
777 $ echo x >x
774 $ hg ci -Ama
778 $ hg ci -Ama
775 adding a
779 adding a
776 adding x
780 adding x
777 $ echo c >c
781 $ echo c >c
778 $ echo xx >x
782 $ echo xx >x
779 $ hg ci -Amc
783 $ hg ci -Amc
780 adding c
784 adding c
781 $ echo c1 >c1
785 $ echo c1 >c1
782 $ hg ci -Amc1
786 $ hg ci -Amc1
783 adding c1
787 adding c1
784 $ hg up 0
788 $ hg up 0
785 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
789 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
786 $ echo b >b
790 $ echo b >b
787 $ hg ci -Amb
791 $ hg ci -Amb
788 adding b
792 adding b
789 created new head
793 created new head
790 $ echo b1 >b1
794 $ echo b1 >b1
791 $ echo xx >x
795 $ echo xx >x
792 $ hg ci -Amb1
796 $ hg ci -Amb1
793 adding b1
797 adding b1
794 $ hg clone -q -r2 . part
798 $ hg clone -q -r2 . part
795
799
796 == bundling via incoming
800 == bundling via incoming
797
801
798 $ hg in -R part --bundle incoming.hg --template "{node}\n" .
802 $ hg in -R part --bundle incoming.hg --template "{node}\n" .
799 comparing with .
803 comparing with .
800 searching for changes
804 searching for changes
801 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
805 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
802 057f4db07f61970e1c11e83be79e9d08adc4dc31
806 057f4db07f61970e1c11e83be79e9d08adc4dc31
803
807
804 == bundling
808 == bundling
805
809
806 $ hg bundle bundle.hg part --debug --config progress.debug=true
810 $ hg bundle bundle.hg part --debug --config progress.debug=true
807 query 1; heads
811 query 1; heads
808 searching for changes
812 searching for changes
809 all remote heads known locally
813 all remote heads known locally
810 2 changesets found
814 2 changesets found
811 list of changesets:
815 list of changesets:
812 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
816 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
813 057f4db07f61970e1c11e83be79e9d08adc4dc31
817 057f4db07f61970e1c11e83be79e9d08adc4dc31
814 bundle2-output-bundle: "HG20", (1 params) 2 parts total
818 bundle2-output-bundle: "HG20", (1 params) 2 parts total
815 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
819 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
816 changesets: 1/2 chunks (50.00%)
820 changesets: 1/2 chunks (50.00%)
817 changesets: 2/2 chunks (100.00%)
821 changesets: 2/2 chunks (100.00%)
818 manifests: 1/2 chunks (50.00%)
822 manifests: 1/2 chunks (50.00%)
819 manifests: 2/2 chunks (100.00%)
823 manifests: 2/2 chunks (100.00%)
820 files: b 1/3 files (33.33%)
824 files: b 1/3 files (33.33%)
821 files: b1 2/3 files (66.67%)
825 files: b1 2/3 files (66.67%)
822 files: x 3/3 files (100.00%)
826 files: x 3/3 files (100.00%)
823 bundle2-output-part: "cache:rev-branch-cache" (advisory) streamed payload
827 bundle2-output-part: "cache:rev-branch-cache" (advisory) streamed payload
824
828
825 #if repobundlerepo
829 #if repobundlerepo
826 == Test for issue3441
830 == Test for issue3441
827
831
828 $ hg clone -q -r0 . part2
832 $ hg clone -q -r0 . part2
829 $ hg -q -R part2 pull bundle.hg
833 $ hg -q -R part2 pull bundle.hg
830 $ hg -R part2 verify
834 $ hg -R part2 verify
831 checking changesets
835 checking changesets
832 checking manifests
836 checking manifests
833 crosschecking files in changesets and manifests
837 crosschecking files in changesets and manifests
834 checking files
838 checking files
835 checked 3 changesets with 5 changes to 4 files
839 checked 3 changesets with 5 changes to 4 files
836 #endif
840 #endif
837
841
838 == Test bundling no commits
842 == Test bundling no commits
839
843
840 $ hg bundle -r 'public()' no-output.hg
844 $ hg bundle -r 'public()' no-output.hg
841 abort: no commits to bundle
845 abort: no commits to bundle
842 [255]
846 [255]
843
847
844 $ cd ..
848 $ cd ..
845
849
846 When user merges to the revision existing only in the bundle,
850 When user merges to the revision existing only in the bundle,
847 it should show warning that second parent of the working
851 it should show warning that second parent of the working
848 directory does not exist
852 directory does not exist
849
853
850 $ hg init update2bundled
854 $ hg init update2bundled
851 $ cd update2bundled
855 $ cd update2bundled
852 $ cat <<EOF >> .hg/hgrc
856 $ cat <<EOF >> .hg/hgrc
853 > [extensions]
857 > [extensions]
854 > strip =
858 > strip =
855 > EOF
859 > EOF
856 $ echo "aaa" >> a
860 $ echo "aaa" >> a
857 $ hg commit -A -m 0
861 $ hg commit -A -m 0
858 adding a
862 adding a
859 $ echo "bbb" >> b
863 $ echo "bbb" >> b
860 $ hg commit -A -m 1
864 $ hg commit -A -m 1
861 adding b
865 adding b
862 $ echo "ccc" >> c
866 $ echo "ccc" >> c
863 $ hg commit -A -m 2
867 $ hg commit -A -m 2
864 adding c
868 adding c
865 $ hg update -r 1
869 $ hg update -r 1
866 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
870 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
867 $ echo "ddd" >> d
871 $ echo "ddd" >> d
868 $ hg commit -A -m 3
872 $ hg commit -A -m 3
869 adding d
873 adding d
870 created new head
874 created new head
871 $ hg update -r 2
875 $ hg update -r 2
872 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
876 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
873 $ hg log -G
877 $ hg log -G
874 o changeset: 3:8bd3e1f196af
878 o changeset: 3:8bd3e1f196af
875 | tag: tip
879 | tag: tip
876 | parent: 1:a01eca7af26d
880 | parent: 1:a01eca7af26d
877 | user: test
881 | user: test
878 | date: Thu Jan 01 00:00:00 1970 +0000
882 | date: Thu Jan 01 00:00:00 1970 +0000
879 | summary: 3
883 | summary: 3
880 |
884 |
881 | @ changeset: 2:4652c276ac4f
885 | @ changeset: 2:4652c276ac4f
882 |/ user: test
886 |/ user: test
883 | date: Thu Jan 01 00:00:00 1970 +0000
887 | date: Thu Jan 01 00:00:00 1970 +0000
884 | summary: 2
888 | summary: 2
885 |
889 |
886 o changeset: 1:a01eca7af26d
890 o changeset: 1:a01eca7af26d
887 | user: test
891 | user: test
888 | date: Thu Jan 01 00:00:00 1970 +0000
892 | date: Thu Jan 01 00:00:00 1970 +0000
889 | summary: 1
893 | summary: 1
890 |
894 |
891 o changeset: 0:4fe08cd4693e
895 o changeset: 0:4fe08cd4693e
892 user: test
896 user: test
893 date: Thu Jan 01 00:00:00 1970 +0000
897 date: Thu Jan 01 00:00:00 1970 +0000
894 summary: 0
898 summary: 0
895
899
896
900
897 #if repobundlerepo
901 #if repobundlerepo
898 $ hg bundle --base 1 -r 3 ../update2bundled.hg
902 $ hg bundle --base 1 -r 3 ../update2bundled.hg
899 1 changesets found
903 1 changesets found
900 $ hg strip -r 3
904 $ hg strip -r 3
901 saved backup bundle to $TESTTMP/update2bundled/.hg/strip-backup/8bd3e1f196af-017e56d8-backup.hg
905 saved backup bundle to $TESTTMP/update2bundled/.hg/strip-backup/8bd3e1f196af-017e56d8-backup.hg
902 $ hg merge -R ../update2bundled.hg -r 3
906 $ hg merge -R ../update2bundled.hg -r 3
903 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
907 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
904 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
908 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
905 (branch merge, don't forget to commit)
909 (branch merge, don't forget to commit)
906
910
907 When user updates to the revision existing only in the bundle,
911 When user updates to the revision existing only in the bundle,
908 it should show warning
912 it should show warning
909
913
910 $ hg update -R ../update2bundled.hg --clean -r 3
914 $ hg update -R ../update2bundled.hg --clean -r 3
911 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
915 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
912 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
916 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
913
917
914 When user updates to the revision existing in the local repository
918 When user updates to the revision existing in the local repository
915 the warning shouldn't be emitted
919 the warning shouldn't be emitted
916
920
917 $ hg update -R ../update2bundled.hg -r 0
921 $ hg update -R ../update2bundled.hg -r 0
918 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
922 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
919 #endif
923 #endif
920
924
921 Test the option that create slim bundle
925 Test the option that create slim bundle
922
926
923 $ hg bundle -a --config devel.bundle.delta=p1 ./slim.hg
927 $ hg bundle -a --config devel.bundle.delta=p1 ./slim.hg
924 3 changesets found
928 3 changesets found
925
929
926 Test the option that create and no-delta's bundle
930 Test the option that create and no-delta's bundle
927 $ hg bundle -a --config devel.bundle.delta=full ./full.hg
931 $ hg bundle -a --config devel.bundle.delta=full ./full.hg
928 3 changesets found
932 3 changesets found
@@ -1,418 +1,460 b''
1 Create an extension to test bundle2 with multiple changegroups
1 Create an extension to test bundle2 with multiple changegroups
2
2
3 $ cat > bundle2.py <<EOF
3 $ cat > bundle2.py <<EOF
4 > """
4 > """
5 > """
5 > """
6 > from mercurial import changegroup, discovery, exchange
6 > from mercurial import changegroup, discovery, exchange
7 >
7 >
8 > def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
8 > def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
9 > b2caps=None, heads=None, common=None,
9 > b2caps=None, heads=None, common=None,
10 > **kwargs):
10 > **kwargs):
11 > # Create two changegroups given the common changesets and heads for the
11 > # Create two changegroups given the common changesets and heads for the
12 > # changegroup part we are being requested. Use the parent of each head
12 > # changegroup part we are being requested. Use the parent of each head
13 > # in 'heads' as intermediate heads for the first changegroup.
13 > # in 'heads' as intermediate heads for the first changegroup.
14 > intermediates = [repo[r].p1().node() for r in heads]
14 > intermediates = [repo[r].p1().node() for r in heads]
15 > outgoing = discovery.outgoing(repo, common, intermediates)
15 > outgoing = discovery.outgoing(repo, common, intermediates)
16 > cg = changegroup.makechangegroup(repo, outgoing, b'01',
16 > cg = changegroup.makechangegroup(repo, outgoing, b'01',
17 > source, bundlecaps=bundlecaps)
17 > source, bundlecaps=bundlecaps)
18 > bundler.newpart(b'output', data=b'changegroup1')
18 > bundler.newpart(b'output', data=b'changegroup1')
19 > bundler.newpart(b'changegroup', data=cg.getchunks())
19 > bundler.newpart(b'changegroup', data=cg.getchunks())
20 > outgoing = discovery.outgoing(repo, common + intermediates, heads)
20 > outgoing = discovery.outgoing(repo, common + intermediates, heads)
21 > cg = changegroup.makechangegroup(repo, outgoing, b'01',
21 > cg = changegroup.makechangegroup(repo, outgoing, b'01',
22 > source, bundlecaps=bundlecaps)
22 > source, bundlecaps=bundlecaps)
23 > bundler.newpart(b'output', data=b'changegroup2')
23 > bundler.newpart(b'output', data=b'changegroup2')
24 > bundler.newpart(b'changegroup', data=cg.getchunks())
24 > bundler.newpart(b'changegroup', data=cg.getchunks())
25 >
25 >
26 > def _pull(repo, *args, **kwargs):
26 > def _pull(repo, *args, **kwargs):
27 > pullop = _orig_pull(repo, *args, **kwargs)
27 > pullop = _orig_pull(repo, *args, **kwargs)
28 > repo.ui.write(b'pullop.cgresult is %d\n' % pullop.cgresult)
28 > repo.ui.write(b'pullop.cgresult is %d\n' % pullop.cgresult)
29 > return pullop
29 > return pullop
30 >
30 >
31 > _orig_pull = exchange.pull
31 > _orig_pull = exchange.pull
32 > exchange.pull = _pull
32 > exchange.pull = _pull
33 > exchange.getbundle2partsmapping[b'changegroup'] = _getbundlechangegrouppart
33 > exchange.getbundle2partsmapping[b'changegroup'] = _getbundlechangegrouppart
34 > EOF
34 > EOF
35
35
36 $ cat >> $HGRCPATH << EOF
36 $ cat >> $HGRCPATH << EOF
37 > [ui]
37 > [ui]
38 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
38 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
39 > EOF
39 > EOF
40
40
41 Start with a simple repository with a single commit
41 Start with a simple repository with a single commit
42
42
43 $ hg init repo
43 $ hg init repo
44 $ cd repo
44 $ cd repo
45 $ cat > .hg/hgrc << EOF
45 $ cat > .hg/hgrc << EOF
46 > [extensions]
46 > [extensions]
47 > bundle2=$TESTTMP/bundle2.py
47 > bundle2=$TESTTMP/bundle2.py
48 > EOF
48 > EOF
49
49
50 $ echo A > A
50 $ echo A > A
51 $ hg commit -A -m A -q
51 $ hg commit -A -m A -q
52 $ cd ..
52 $ cd ..
53
53
54 Clone
54 Clone
55
55
56 $ hg clone -q repo clone
56 $ hg clone -q repo clone
57
57
58 Add two linear commits
58 Add two linear commits
59
59
60 $ cd repo
60 $ cd repo
61 $ echo B > B
61 $ echo B > B
62 $ hg commit -A -m B -q
62 $ hg commit -A -m B -q
63 $ echo C > C
63 $ echo C > C
64 $ hg commit -A -m C -q
64 $ hg commit -A -m C -q
65
65
66 $ cd ../clone
66 $ cd ../clone
67 $ cat >> .hg/hgrc <<EOF
67 $ cat >> .hg/hgrc <<EOF
68 > [hooks]
68 > [hooks]
69 > pretxnchangegroup = sh -c "printenv.py --line pretxnchangegroup"
69 > pretxnchangegroup = sh -c "printenv.py --line pretxnchangegroup"
70 > changegroup = sh -c "printenv.py --line changegroup"
70 > changegroup = sh -c "printenv.py --line changegroup"
71 > incoming = sh -c "printenv.py --line incoming"
71 > incoming = sh -c "printenv.py --line incoming"
72 > EOF
72 > EOF
73
73
74 Pull the new commits in the clone
74 Pull the new commits in the clone
75
75
76 $ hg pull
76 $ hg pull
77 pulling from $TESTTMP/repo
77 pulling from $TESTTMP/repo
78 searching for changes
78 searching for changes
79 remote: changegroup1
79 remote: changegroup1
80 adding changesets
80 adding changesets
81 adding manifests
81 adding manifests
82 adding file changes
82 adding file changes
83 added 1 changesets with 1 changes to 1 files
83 added 1 changesets with 1 changes to 1 files
84 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
84 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
85 HG_HOOKTYPE=pretxnchangegroup
85 HG_HOOKTYPE=pretxnchangegroup
86 HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56
86 HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56
87 HG_NODE_LAST=27547f69f25460a52fff66ad004e58da7ad3fb56
87 HG_NODE_LAST=27547f69f25460a52fff66ad004e58da7ad3fb56
88 HG_PENDING=$TESTTMP/clone
88 HG_PENDING=$TESTTMP/clone
89 HG_SOURCE=pull
89 HG_SOURCE=pull
90 HG_TXNID=TXN:$ID$
90 HG_TXNID=TXN:$ID$
91 HG_TXNNAME=pull
92 file:/*/$TESTTMP/repo (glob)
91 HG_URL=file:$TESTTMP/repo
93 HG_URL=file:$TESTTMP/repo
92
94
93 remote: changegroup2
95 remote: changegroup2
94 adding changesets
96 adding changesets
95 adding manifests
97 adding manifests
96 adding file changes
98 adding file changes
97 added 1 changesets with 1 changes to 1 files
99 added 1 changesets with 1 changes to 1 files
98 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
100 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
99 HG_HOOKTYPE=pretxnchangegroup
101 HG_HOOKTYPE=pretxnchangegroup
100 HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757
102 HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757
101 HG_NODE_LAST=f838bfaca5c7226600ebcfd84f3c3c13a28d3757
103 HG_NODE_LAST=f838bfaca5c7226600ebcfd84f3c3c13a28d3757
102 HG_PENDING=$TESTTMP/clone
104 HG_PENDING=$TESTTMP/clone
103 HG_PHASES_MOVED=1
105 HG_PHASES_MOVED=1
104 HG_SOURCE=pull
106 HG_SOURCE=pull
105 HG_TXNID=TXN:$ID$
107 HG_TXNID=TXN:$ID$
108 HG_TXNNAME=pull
109 file:/*/$TESTTMP/repo (glob)
106 HG_URL=file:$TESTTMP/repo
110 HG_URL=file:$TESTTMP/repo
107
111
108 new changesets 27547f69f254:f838bfaca5c7
112 new changesets 27547f69f254:f838bfaca5c7
109 changegroup hook: HG_HOOKNAME=changegroup
113 changegroup hook: HG_HOOKNAME=changegroup
110 HG_HOOKTYPE=changegroup
114 HG_HOOKTYPE=changegroup
111 HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56
115 HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56
112 HG_NODE_LAST=27547f69f25460a52fff66ad004e58da7ad3fb56
116 HG_NODE_LAST=27547f69f25460a52fff66ad004e58da7ad3fb56
113 HG_SOURCE=pull
117 HG_SOURCE=pull
114 HG_TXNID=TXN:$ID$
118 HG_TXNID=TXN:$ID$
119 HG_TXNNAME=pull
120 file:/*/$TESTTMP/repo (glob)
115 HG_URL=file:$TESTTMP/repo
121 HG_URL=file:$TESTTMP/repo
116
122
117 incoming hook: HG_HOOKNAME=incoming
123 incoming hook: HG_HOOKNAME=incoming
118 HG_HOOKTYPE=incoming
124 HG_HOOKTYPE=incoming
119 HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56
125 HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56
120 HG_SOURCE=pull
126 HG_SOURCE=pull
121 HG_TXNID=TXN:$ID$
127 HG_TXNID=TXN:$ID$
128 HG_TXNNAME=pull
129 file:/*/$TESTTMP/repo (glob)
122 HG_URL=file:$TESTTMP/repo
130 HG_URL=file:$TESTTMP/repo
123
131
124 changegroup hook: HG_HOOKNAME=changegroup
132 changegroup hook: HG_HOOKNAME=changegroup
125 HG_HOOKTYPE=changegroup
133 HG_HOOKTYPE=changegroup
126 HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757
134 HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757
127 HG_NODE_LAST=f838bfaca5c7226600ebcfd84f3c3c13a28d3757
135 HG_NODE_LAST=f838bfaca5c7226600ebcfd84f3c3c13a28d3757
128 HG_PHASES_MOVED=1
136 HG_PHASES_MOVED=1
129 HG_SOURCE=pull
137 HG_SOURCE=pull
130 HG_TXNID=TXN:$ID$
138 HG_TXNID=TXN:$ID$
139 HG_TXNNAME=pull
140 file:/*/$TESTTMP/repo (glob)
131 HG_URL=file:$TESTTMP/repo
141 HG_URL=file:$TESTTMP/repo
132
142
133 incoming hook: HG_HOOKNAME=incoming
143 incoming hook: HG_HOOKNAME=incoming
134 HG_HOOKTYPE=incoming
144 HG_HOOKTYPE=incoming
135 HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757
145 HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757
136 HG_PHASES_MOVED=1
146 HG_PHASES_MOVED=1
137 HG_SOURCE=pull
147 HG_SOURCE=pull
138 HG_TXNID=TXN:$ID$
148 HG_TXNID=TXN:$ID$
149 HG_TXNNAME=pull
150 file:/*/$TESTTMP/repo (glob)
139 HG_URL=file:$TESTTMP/repo
151 HG_URL=file:$TESTTMP/repo
140
152
141 pullop.cgresult is 1
153 pullop.cgresult is 1
142 (run 'hg update' to get a working copy)
154 (run 'hg update' to get a working copy)
143 $ hg update
155 $ hg update
144 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
156 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 $ hg log -G
157 $ hg log -G
146 @ 2:f838bfaca5c7 public test C
158 @ 2:f838bfaca5c7 public test C
147 |
159 |
148 o 1:27547f69f254 public test B
160 o 1:27547f69f254 public test B
149 |
161 |
150 o 0:4a2df7238c3b public test A
162 o 0:4a2df7238c3b public test A
151
163
152 Add more changesets with multiple heads to the original repository
164 Add more changesets with multiple heads to the original repository
153
165
154 $ cd ../repo
166 $ cd ../repo
155 $ echo D > D
167 $ echo D > D
156 $ hg commit -A -m D -q
168 $ hg commit -A -m D -q
157 $ hg up -r 1
169 $ hg up -r 1
158 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
170 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
159 $ echo E > E
171 $ echo E > E
160 $ hg commit -A -m E -q
172 $ hg commit -A -m E -q
161 $ echo F > F
173 $ echo F > F
162 $ hg commit -A -m F -q
174 $ hg commit -A -m F -q
163 $ hg up -r 1
175 $ hg up -r 1
164 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
176 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
165 $ echo G > G
177 $ echo G > G
166 $ hg commit -A -m G -q
178 $ hg commit -A -m G -q
167 $ hg up -r 3
179 $ hg up -r 3
168 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
180 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
169 $ echo H > H
181 $ echo H > H
170 $ hg commit -A -m H -q
182 $ hg commit -A -m H -q
171 $ hg log -G
183 $ hg log -G
172 @ 7:5cd59d311f65 draft test H
184 @ 7:5cd59d311f65 draft test H
173 |
185 |
174 | o 6:1d14c3ce6ac0 draft test G
186 | o 6:1d14c3ce6ac0 draft test G
175 | |
187 | |
176 | | o 5:7f219660301f draft test F
188 | | o 5:7f219660301f draft test F
177 | | |
189 | | |
178 | | o 4:8a5212ebc852 draft test E
190 | | o 4:8a5212ebc852 draft test E
179 | |/
191 | |/
180 o | 3:b3325c91a4d9 draft test D
192 o | 3:b3325c91a4d9 draft test D
181 | |
193 | |
182 o | 2:f838bfaca5c7 draft test C
194 o | 2:f838bfaca5c7 draft test C
183 |/
195 |/
184 o 1:27547f69f254 draft test B
196 o 1:27547f69f254 draft test B
185 |
197 |
186 o 0:4a2df7238c3b draft test A
198 o 0:4a2df7238c3b draft test A
187
199
188 New heads are reported during transfer and properly accounted for in
200 New heads are reported during transfer and properly accounted for in
189 pullop.cgresult
201 pullop.cgresult
190
202
191 $ cd ../clone
203 $ cd ../clone
192 $ hg pull
204 $ hg pull
193 pulling from $TESTTMP/repo
205 pulling from $TESTTMP/repo
194 searching for changes
206 searching for changes
195 remote: changegroup1
207 remote: changegroup1
196 adding changesets
208 adding changesets
197 adding manifests
209 adding manifests
198 adding file changes
210 adding file changes
199 added 2 changesets with 2 changes to 2 files (+1 heads)
211 added 2 changesets with 2 changes to 2 files (+1 heads)
200 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
212 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
201 HG_HOOKTYPE=pretxnchangegroup
213 HG_HOOKTYPE=pretxnchangegroup
202 HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
214 HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
203 HG_NODE_LAST=8a5212ebc8527f9fb821601504794e3eb11a1ed3
215 HG_NODE_LAST=8a5212ebc8527f9fb821601504794e3eb11a1ed3
204 HG_PENDING=$TESTTMP/clone
216 HG_PENDING=$TESTTMP/clone
205 HG_SOURCE=pull
217 HG_SOURCE=pull
206 HG_TXNID=TXN:$ID$
218 HG_TXNID=TXN:$ID$
219 HG_TXNNAME=pull
220 file:/*/$TESTTMP/repo (glob)
207 HG_URL=file:$TESTTMP/repo
221 HG_URL=file:$TESTTMP/repo
208
222
209 remote: changegroup2
223 remote: changegroup2
210 adding changesets
224 adding changesets
211 adding manifests
225 adding manifests
212 adding file changes
226 adding file changes
213 added 3 changesets with 3 changes to 3 files (+1 heads)
227 added 3 changesets with 3 changes to 3 files (+1 heads)
214 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
228 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
215 HG_HOOKTYPE=pretxnchangegroup
229 HG_HOOKTYPE=pretxnchangegroup
216 HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46
230 HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46
217 HG_NODE_LAST=5cd59d311f6508b8e0ed28a266756c859419c9f1
231 HG_NODE_LAST=5cd59d311f6508b8e0ed28a266756c859419c9f1
218 HG_PENDING=$TESTTMP/clone
232 HG_PENDING=$TESTTMP/clone
219 HG_PHASES_MOVED=1
233 HG_PHASES_MOVED=1
220 HG_SOURCE=pull
234 HG_SOURCE=pull
221 HG_TXNID=TXN:$ID$
235 HG_TXNID=TXN:$ID$
236 HG_TXNNAME=pull
237 file:/*/$TESTTMP/repo (glob)
222 HG_URL=file:$TESTTMP/repo
238 HG_URL=file:$TESTTMP/repo
223
239
224 new changesets b3325c91a4d9:5cd59d311f65
240 new changesets b3325c91a4d9:5cd59d311f65
225 changegroup hook: HG_HOOKNAME=changegroup
241 changegroup hook: HG_HOOKNAME=changegroup
226 HG_HOOKTYPE=changegroup
242 HG_HOOKTYPE=changegroup
227 HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
243 HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
228 HG_NODE_LAST=8a5212ebc8527f9fb821601504794e3eb11a1ed3
244 HG_NODE_LAST=8a5212ebc8527f9fb821601504794e3eb11a1ed3
229 HG_SOURCE=pull
245 HG_SOURCE=pull
230 HG_TXNID=TXN:$ID$
246 HG_TXNID=TXN:$ID$
247 HG_TXNNAME=pull
248 file:/*/$TESTTMP/repo (glob)
231 HG_URL=file:$TESTTMP/repo
249 HG_URL=file:$TESTTMP/repo
232
250
233 incoming hook: HG_HOOKNAME=incoming
251 incoming hook: HG_HOOKNAME=incoming
234 HG_HOOKTYPE=incoming
252 HG_HOOKTYPE=incoming
235 HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
253 HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e
236 HG_SOURCE=pull
254 HG_SOURCE=pull
237 HG_TXNID=TXN:$ID$
255 HG_TXNID=TXN:$ID$
256 HG_TXNNAME=pull
257 file:/*/$TESTTMP/repo (glob)
238 HG_URL=file:$TESTTMP/repo
258 HG_URL=file:$TESTTMP/repo
239
259
240 incoming hook: HG_HOOKNAME=incoming
260 incoming hook: HG_HOOKNAME=incoming
241 HG_HOOKTYPE=incoming
261 HG_HOOKTYPE=incoming
242 HG_NODE=8a5212ebc8527f9fb821601504794e3eb11a1ed3
262 HG_NODE=8a5212ebc8527f9fb821601504794e3eb11a1ed3
243 HG_SOURCE=pull
263 HG_SOURCE=pull
244 HG_TXNID=TXN:$ID$
264 HG_TXNID=TXN:$ID$
265 HG_TXNNAME=pull
266 file:/*/$TESTTMP/repo (glob)
245 HG_URL=file:$TESTTMP/repo
267 HG_URL=file:$TESTTMP/repo
246
268
247 changegroup hook: HG_HOOKNAME=changegroup
269 changegroup hook: HG_HOOKNAME=changegroup
248 HG_HOOKTYPE=changegroup
270 HG_HOOKTYPE=changegroup
249 HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46
271 HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46
250 HG_NODE_LAST=5cd59d311f6508b8e0ed28a266756c859419c9f1
272 HG_NODE_LAST=5cd59d311f6508b8e0ed28a266756c859419c9f1
251 HG_PHASES_MOVED=1
273 HG_PHASES_MOVED=1
252 HG_SOURCE=pull
274 HG_SOURCE=pull
253 HG_TXNID=TXN:$ID$
275 HG_TXNID=TXN:$ID$
276 HG_TXNNAME=pull
277 file:/*/$TESTTMP/repo (glob)
254 HG_URL=file:$TESTTMP/repo
278 HG_URL=file:$TESTTMP/repo
255
279
256 incoming hook: HG_HOOKNAME=incoming
280 incoming hook: HG_HOOKNAME=incoming
257 HG_HOOKTYPE=incoming
281 HG_HOOKTYPE=incoming
258 HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46
282 HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46
259 HG_PHASES_MOVED=1
283 HG_PHASES_MOVED=1
260 HG_SOURCE=pull
284 HG_SOURCE=pull
261 HG_TXNID=TXN:$ID$
285 HG_TXNID=TXN:$ID$
286 HG_TXNNAME=pull
287 file:/*/$TESTTMP/repo (glob)
262 HG_URL=file:$TESTTMP/repo
288 HG_URL=file:$TESTTMP/repo
263
289
264 incoming hook: HG_HOOKNAME=incoming
290 incoming hook: HG_HOOKNAME=incoming
265 HG_HOOKTYPE=incoming
291 HG_HOOKTYPE=incoming
266 HG_NODE=1d14c3ce6ac0582d2809220d33e8cd7a696e0156
292 HG_NODE=1d14c3ce6ac0582d2809220d33e8cd7a696e0156
267 HG_PHASES_MOVED=1
293 HG_PHASES_MOVED=1
268 HG_SOURCE=pull
294 HG_SOURCE=pull
269 HG_TXNID=TXN:$ID$
295 HG_TXNID=TXN:$ID$
296 HG_TXNNAME=pull
297 file:/*/$TESTTMP/repo (glob)
270 HG_URL=file:$TESTTMP/repo
298 HG_URL=file:$TESTTMP/repo
271
299
272 incoming hook: HG_HOOKNAME=incoming
300 incoming hook: HG_HOOKNAME=incoming
273 HG_HOOKTYPE=incoming
301 HG_HOOKTYPE=incoming
274 HG_NODE=5cd59d311f6508b8e0ed28a266756c859419c9f1
302 HG_NODE=5cd59d311f6508b8e0ed28a266756c859419c9f1
275 HG_PHASES_MOVED=1
303 HG_PHASES_MOVED=1
276 HG_SOURCE=pull
304 HG_SOURCE=pull
277 HG_TXNID=TXN:$ID$
305 HG_TXNID=TXN:$ID$
306 HG_TXNNAME=pull
307 file:/*/$TESTTMP/repo (glob)
278 HG_URL=file:$TESTTMP/repo
308 HG_URL=file:$TESTTMP/repo
279
309
280 pullop.cgresult is 3
310 pullop.cgresult is 3
281 (run 'hg heads' to see heads, 'hg merge' to merge)
311 (run 'hg heads' to see heads, 'hg merge' to merge)
282 $ hg log -G
312 $ hg log -G
283 o 7:5cd59d311f65 public test H
313 o 7:5cd59d311f65 public test H
284 |
314 |
285 | o 6:1d14c3ce6ac0 public test G
315 | o 6:1d14c3ce6ac0 public test G
286 | |
316 | |
287 | | o 5:7f219660301f public test F
317 | | o 5:7f219660301f public test F
288 | | |
318 | | |
289 | | o 4:8a5212ebc852 public test E
319 | | o 4:8a5212ebc852 public test E
290 | |/
320 | |/
291 o | 3:b3325c91a4d9 public test D
321 o | 3:b3325c91a4d9 public test D
292 | |
322 | |
293 @ | 2:f838bfaca5c7 public test C
323 @ | 2:f838bfaca5c7 public test C
294 |/
324 |/
295 o 1:27547f69f254 public test B
325 o 1:27547f69f254 public test B
296 |
326 |
297 o 0:4a2df7238c3b public test A
327 o 0:4a2df7238c3b public test A
298
328
299 Removing a head from the original repository by merging it
329 Removing a head from the original repository by merging it
300
330
301 $ cd ../repo
331 $ cd ../repo
302 $ hg merge -r 6 -q
332 $ hg merge -r 6 -q
303 $ hg commit -m Merge
333 $ hg commit -m Merge
304 $ echo I > I
334 $ echo I > I
305 $ hg commit -A -m H -q
335 $ hg commit -A -m H -q
306 $ hg log -G
336 $ hg log -G
307 @ 9:9d18e5bd9ab0 draft test H
337 @ 9:9d18e5bd9ab0 draft test H
308 |
338 |
309 o 8:71bd7b46de72 draft test Merge
339 o 8:71bd7b46de72 draft test Merge
310 |\
340 |\
311 | o 7:5cd59d311f65 draft test H
341 | o 7:5cd59d311f65 draft test H
312 | |
342 | |
313 o | 6:1d14c3ce6ac0 draft test G
343 o | 6:1d14c3ce6ac0 draft test G
314 | |
344 | |
315 | | o 5:7f219660301f draft test F
345 | | o 5:7f219660301f draft test F
316 | | |
346 | | |
317 +---o 4:8a5212ebc852 draft test E
347 +---o 4:8a5212ebc852 draft test E
318 | |
348 | |
319 | o 3:b3325c91a4d9 draft test D
349 | o 3:b3325c91a4d9 draft test D
320 | |
350 | |
321 | o 2:f838bfaca5c7 draft test C
351 | o 2:f838bfaca5c7 draft test C
322 |/
352 |/
323 o 1:27547f69f254 draft test B
353 o 1:27547f69f254 draft test B
324 |
354 |
325 o 0:4a2df7238c3b draft test A
355 o 0:4a2df7238c3b draft test A
326
356
327 Removed heads are reported during transfer and properly accounted for in
357 Removed heads are reported during transfer and properly accounted for in
328 pullop.cgresult
358 pullop.cgresult
329
359
330 $ cd ../clone
360 $ cd ../clone
331 $ hg pull
361 $ hg pull
332 pulling from $TESTTMP/repo
362 pulling from $TESTTMP/repo
333 searching for changes
363 searching for changes
334 remote: changegroup1
364 remote: changegroup1
335 adding changesets
365 adding changesets
336 adding manifests
366 adding manifests
337 adding file changes
367 adding file changes
338 added 1 changesets with 0 changes to 0 files (-1 heads)
368 added 1 changesets with 0 changes to 0 files (-1 heads)
339 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
369 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
340 HG_HOOKTYPE=pretxnchangegroup
370 HG_HOOKTYPE=pretxnchangegroup
341 HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4
371 HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4
342 HG_NODE_LAST=71bd7b46de72e69a32455bf88d04757d542e6cf4
372 HG_NODE_LAST=71bd7b46de72e69a32455bf88d04757d542e6cf4
343 HG_PENDING=$TESTTMP/clone
373 HG_PENDING=$TESTTMP/clone
344 HG_SOURCE=pull
374 HG_SOURCE=pull
345 HG_TXNID=TXN:$ID$
375 HG_TXNID=TXN:$ID$
376 HG_TXNNAME=pull
377 file:/*/$TESTTMP/repo (glob)
346 HG_URL=file:$TESTTMP/repo
378 HG_URL=file:$TESTTMP/repo
347
379
348 remote: changegroup2
380 remote: changegroup2
349 adding changesets
381 adding changesets
350 adding manifests
382 adding manifests
351 adding file changes
383 adding file changes
352 added 1 changesets with 1 changes to 1 files
384 added 1 changesets with 1 changes to 1 files
353 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
385 pretxnchangegroup hook: HG_HOOKNAME=pretxnchangegroup
354 HG_HOOKTYPE=pretxnchangegroup
386 HG_HOOKTYPE=pretxnchangegroup
355 HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84
387 HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84
356 HG_NODE_LAST=9d18e5bd9ab09337802595d49f1dad0c98df4d84
388 HG_NODE_LAST=9d18e5bd9ab09337802595d49f1dad0c98df4d84
357 HG_PENDING=$TESTTMP/clone
389 HG_PENDING=$TESTTMP/clone
358 HG_PHASES_MOVED=1
390 HG_PHASES_MOVED=1
359 HG_SOURCE=pull
391 HG_SOURCE=pull
360 HG_TXNID=TXN:$ID$
392 HG_TXNID=TXN:$ID$
393 HG_TXNNAME=pull
394 file:/*/$TESTTMP/repo (glob)
361 HG_URL=file:$TESTTMP/repo
395 HG_URL=file:$TESTTMP/repo
362
396
363 new changesets 71bd7b46de72:9d18e5bd9ab0
397 new changesets 71bd7b46de72:9d18e5bd9ab0
364 changegroup hook: HG_HOOKNAME=changegroup
398 changegroup hook: HG_HOOKNAME=changegroup
365 HG_HOOKTYPE=changegroup
399 HG_HOOKTYPE=changegroup
366 HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4
400 HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4
367 HG_NODE_LAST=71bd7b46de72e69a32455bf88d04757d542e6cf4
401 HG_NODE_LAST=71bd7b46de72e69a32455bf88d04757d542e6cf4
368 HG_SOURCE=pull
402 HG_SOURCE=pull
369 HG_TXNID=TXN:$ID$
403 HG_TXNID=TXN:$ID$
404 HG_TXNNAME=pull
405 file:/*/$TESTTMP/repo (glob)
370 HG_URL=file:$TESTTMP/repo
406 HG_URL=file:$TESTTMP/repo
371
407
372 incoming hook: HG_HOOKNAME=incoming
408 incoming hook: HG_HOOKNAME=incoming
373 HG_HOOKTYPE=incoming
409 HG_HOOKTYPE=incoming
374 HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4
410 HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4
375 HG_SOURCE=pull
411 HG_SOURCE=pull
376 HG_TXNID=TXN:$ID$
412 HG_TXNID=TXN:$ID$
413 HG_TXNNAME=pull
414 file:/*/$TESTTMP/repo (glob)
377 HG_URL=file:$TESTTMP/repo
415 HG_URL=file:$TESTTMP/repo
378
416
379 changegroup hook: HG_HOOKNAME=changegroup
417 changegroup hook: HG_HOOKNAME=changegroup
380 HG_HOOKTYPE=changegroup
418 HG_HOOKTYPE=changegroup
381 HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84
419 HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84
382 HG_NODE_LAST=9d18e5bd9ab09337802595d49f1dad0c98df4d84
420 HG_NODE_LAST=9d18e5bd9ab09337802595d49f1dad0c98df4d84
383 HG_PHASES_MOVED=1
421 HG_PHASES_MOVED=1
384 HG_SOURCE=pull
422 HG_SOURCE=pull
385 HG_TXNID=TXN:$ID$
423 HG_TXNID=TXN:$ID$
424 HG_TXNNAME=pull
425 file:/*/$TESTTMP/repo (glob)
386 HG_URL=file:$TESTTMP/repo
426 HG_URL=file:$TESTTMP/repo
387
427
388 incoming hook: HG_HOOKNAME=incoming
428 incoming hook: HG_HOOKNAME=incoming
389 HG_HOOKTYPE=incoming
429 HG_HOOKTYPE=incoming
390 HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84
430 HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84
391 HG_PHASES_MOVED=1
431 HG_PHASES_MOVED=1
392 HG_SOURCE=pull
432 HG_SOURCE=pull
393 HG_TXNID=TXN:$ID$
433 HG_TXNID=TXN:$ID$
434 HG_TXNNAME=pull
435 file:/*/$TESTTMP/repo (glob)
394 HG_URL=file:$TESTTMP/repo
436 HG_URL=file:$TESTTMP/repo
395
437
396 pullop.cgresult is -2
438 pullop.cgresult is -2
397 (run 'hg update' to get a working copy)
439 (run 'hg update' to get a working copy)
398 $ hg log -G
440 $ hg log -G
399 o 9:9d18e5bd9ab0 public test H
441 o 9:9d18e5bd9ab0 public test H
400 |
442 |
401 o 8:71bd7b46de72 public test Merge
443 o 8:71bd7b46de72 public test Merge
402 |\
444 |\
403 | o 7:5cd59d311f65 public test H
445 | o 7:5cd59d311f65 public test H
404 | |
446 | |
405 o | 6:1d14c3ce6ac0 public test G
447 o | 6:1d14c3ce6ac0 public test G
406 | |
448 | |
407 | | o 5:7f219660301f public test F
449 | | o 5:7f219660301f public test F
408 | | |
450 | | |
409 +---o 4:8a5212ebc852 public test E
451 +---o 4:8a5212ebc852 public test E
410 | |
452 | |
411 | o 3:b3325c91a4d9 public test D
453 | o 3:b3325c91a4d9 public test D
412 | |
454 | |
413 | @ 2:f838bfaca5c7 public test C
455 | @ 2:f838bfaca5c7 public test C
414 |/
456 |/
415 o 1:27547f69f254 public test B
457 o 1:27547f69f254 public test B
416 |
458 |
417 o 0:4a2df7238c3b public test A
459 o 0:4a2df7238c3b public test A
418
460
@@ -1,1352 +1,1368 b''
1 commit hooks can see env vars
1 commit hooks can see env vars
2 (and post-transaction one are run unlocked)
2 (and post-transaction one are run unlocked)
3
3
4
4
5 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
5 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
6 > from mercurial import pycompat
6 > from mercurial import pycompat
7 > def showargs(ui, repo, hooktype, **kwargs):
7 > def showargs(ui, repo, hooktype, **kwargs):
8 > kwargs = pycompat.byteskwargs(kwargs)
8 > kwargs = pycompat.byteskwargs(kwargs)
9 > ui.write(b'%s Python hook: %s\n' % (hooktype,
9 > ui.write(b'%s Python hook: %s\n' % (hooktype,
10 > b','.join(sorted(kwargs))))
10 > b','.join(sorted(kwargs))))
11 > EOF
11 > EOF
12
12
13 $ hg init a
13 $ hg init a
14 $ cd a
14 $ cd a
15 $ cat > .hg/hgrc <<EOF
15 $ cat > .hg/hgrc <<EOF
16 > [hooks]
16 > [hooks]
17 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py --line commit"
17 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py --line commit"
18 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py --line commit.b"
18 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py --line commit.b"
19 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py --line precommit"
19 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py --line precommit"
20 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxncommit"
20 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxncommit"
21 > pretxncommit.tip = hg -q tip
21 > pretxncommit.tip = hg -q tip
22 > pre-identify = sh -c "printenv.py --line pre-identify 1"
22 > pre-identify = sh -c "printenv.py --line pre-identify 1"
23 > pre-cat = sh -c "printenv.py --line pre-cat"
23 > pre-cat = sh -c "printenv.py --line pre-cat"
24 > post-cat = sh -c "printenv.py --line post-cat"
24 > post-cat = sh -c "printenv.py --line post-cat"
25 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxnopen"
25 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxnopen"
26 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxnclose"
26 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py --line pretxnclose"
27 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py --line txnclose"
27 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py --line txnclose"
28 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
28 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
29 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py --line txnabort"
29 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py --line txnabort"
30 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
30 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
31 > EOF
31 > EOF
32 $ echo a > a
32 $ echo a > a
33 $ hg add a
33 $ hg add a
34 $ hg commit -m a
34 $ hg commit -m a
35 precommit hook: HG_HOOKNAME=precommit
35 precommit hook: HG_HOOKNAME=precommit
36 HG_HOOKTYPE=precommit
36 HG_HOOKTYPE=precommit
37 HG_PARENT1=0000000000000000000000000000000000000000
37 HG_PARENT1=0000000000000000000000000000000000000000
38
38
39 pretxnopen hook: HG_HOOKNAME=pretxnopen
39 pretxnopen hook: HG_HOOKNAME=pretxnopen
40 HG_HOOKTYPE=pretxnopen
40 HG_HOOKTYPE=pretxnopen
41 HG_TXNID=TXN:$ID$
41 HG_TXNID=TXN:$ID$
42 HG_TXNNAME=commit
42 HG_TXNNAME=commit
43
43
44 pretxncommit hook: HG_HOOKNAME=pretxncommit
44 pretxncommit hook: HG_HOOKNAME=pretxncommit
45 HG_HOOKTYPE=pretxncommit
45 HG_HOOKTYPE=pretxncommit
46 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
46 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
47 HG_PARENT1=0000000000000000000000000000000000000000
47 HG_PARENT1=0000000000000000000000000000000000000000
48 HG_PENDING=$TESTTMP/a
48 HG_PENDING=$TESTTMP/a
49
49
50 0:cb9a9f314b8b
50 0:cb9a9f314b8b
51 pretxnclose hook: HG_HOOKNAME=pretxnclose
51 pretxnclose hook: HG_HOOKNAME=pretxnclose
52 HG_HOOKTYPE=pretxnclose
52 HG_HOOKTYPE=pretxnclose
53 HG_PENDING=$TESTTMP/a
53 HG_PENDING=$TESTTMP/a
54 HG_PHASES_MOVED=1
54 HG_PHASES_MOVED=1
55 HG_TXNID=TXN:$ID$
55 HG_TXNID=TXN:$ID$
56 HG_TXNNAME=commit
56 HG_TXNNAME=commit
57
57
58 txnclose hook: HG_HOOKNAME=txnclose
58 txnclose hook: HG_HOOKNAME=txnclose
59 HG_HOOKTYPE=txnclose
59 HG_HOOKTYPE=txnclose
60 HG_PHASES_MOVED=1
60 HG_PHASES_MOVED=1
61 HG_TXNID=TXN:$ID$
61 HG_TXNID=TXN:$ID$
62 HG_TXNNAME=commit
62 HG_TXNNAME=commit
63
63
64 commit hook: HG_HOOKNAME=commit
64 commit hook: HG_HOOKNAME=commit
65 HG_HOOKTYPE=commit
65 HG_HOOKTYPE=commit
66 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
66 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
67 HG_PARENT1=0000000000000000000000000000000000000000
67 HG_PARENT1=0000000000000000000000000000000000000000
68
68
69 commit.b hook: HG_HOOKNAME=commit.b
69 commit.b hook: HG_HOOKNAME=commit.b
70 HG_HOOKTYPE=commit
70 HG_HOOKTYPE=commit
71 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
71 HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
72 HG_PARENT1=0000000000000000000000000000000000000000
72 HG_PARENT1=0000000000000000000000000000000000000000
73
73
74
74
75 $ hg clone . ../b
75 $ hg clone . ../b
76 updating to branch default
76 updating to branch default
77 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 $ cd ../b
78 $ cd ../b
79
79
80 changegroup hooks can see env vars
80 changegroup hooks can see env vars
81
81
82 $ cat > .hg/hgrc <<EOF
82 $ cat > .hg/hgrc <<EOF
83 > [hooks]
83 > [hooks]
84 > prechangegroup = sh -c "printenv.py --line prechangegroup"
84 > prechangegroup = sh -c "printenv.py --line prechangegroup"
85 > changegroup = sh -c "printenv.py --line changegroup"
85 > changegroup = sh -c "printenv.py --line changegroup"
86 > incoming = sh -c "printenv.py --line incoming"
86 > incoming = sh -c "printenv.py --line incoming"
87 > EOF
87 > EOF
88
88
89 pretxncommit and commit hooks can see both parents of merge
89 pretxncommit and commit hooks can see both parents of merge
90
90
91 $ cd ../a
91 $ cd ../a
92 $ echo b >> a
92 $ echo b >> a
93 $ hg commit -m a1 -d "1 0"
93 $ hg commit -m a1 -d "1 0"
94 precommit hook: HG_HOOKNAME=precommit
94 precommit hook: HG_HOOKNAME=precommit
95 HG_HOOKTYPE=precommit
95 HG_HOOKTYPE=precommit
96 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
96 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
97
97
98 pretxnopen hook: HG_HOOKNAME=pretxnopen
98 pretxnopen hook: HG_HOOKNAME=pretxnopen
99 HG_HOOKTYPE=pretxnopen
99 HG_HOOKTYPE=pretxnopen
100 HG_TXNID=TXN:$ID$
100 HG_TXNID=TXN:$ID$
101 HG_TXNNAME=commit
101 HG_TXNNAME=commit
102
102
103 pretxncommit hook: HG_HOOKNAME=pretxncommit
103 pretxncommit hook: HG_HOOKNAME=pretxncommit
104 HG_HOOKTYPE=pretxncommit
104 HG_HOOKTYPE=pretxncommit
105 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
105 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
106 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
106 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
107 HG_PENDING=$TESTTMP/a
107 HG_PENDING=$TESTTMP/a
108
108
109 1:ab228980c14d
109 1:ab228980c14d
110 pretxnclose hook: HG_HOOKNAME=pretxnclose
110 pretxnclose hook: HG_HOOKNAME=pretxnclose
111 HG_HOOKTYPE=pretxnclose
111 HG_HOOKTYPE=pretxnclose
112 HG_PENDING=$TESTTMP/a
112 HG_PENDING=$TESTTMP/a
113 HG_TXNID=TXN:$ID$
113 HG_TXNID=TXN:$ID$
114 HG_TXNNAME=commit
114 HG_TXNNAME=commit
115
115
116 txnclose hook: HG_HOOKNAME=txnclose
116 txnclose hook: HG_HOOKNAME=txnclose
117 HG_HOOKTYPE=txnclose
117 HG_HOOKTYPE=txnclose
118 HG_TXNID=TXN:$ID$
118 HG_TXNID=TXN:$ID$
119 HG_TXNNAME=commit
119 HG_TXNNAME=commit
120
120
121 commit hook: HG_HOOKNAME=commit
121 commit hook: HG_HOOKNAME=commit
122 HG_HOOKTYPE=commit
122 HG_HOOKTYPE=commit
123 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
123 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
124 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
124 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
125
125
126 commit.b hook: HG_HOOKNAME=commit.b
126 commit.b hook: HG_HOOKNAME=commit.b
127 HG_HOOKTYPE=commit
127 HG_HOOKTYPE=commit
128 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
128 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
129 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
129 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
130
130
131 $ hg update -C 0
131 $ hg update -C 0
132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
132 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
133 $ echo b > b
133 $ echo b > b
134 $ hg add b
134 $ hg add b
135 $ hg commit -m b -d '1 0'
135 $ hg commit -m b -d '1 0'
136 precommit hook: HG_HOOKNAME=precommit
136 precommit hook: HG_HOOKNAME=precommit
137 HG_HOOKTYPE=precommit
137 HG_HOOKTYPE=precommit
138 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
138 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
139
139
140 pretxnopen hook: HG_HOOKNAME=pretxnopen
140 pretxnopen hook: HG_HOOKNAME=pretxnopen
141 HG_HOOKTYPE=pretxnopen
141 HG_HOOKTYPE=pretxnopen
142 HG_TXNID=TXN:$ID$
142 HG_TXNID=TXN:$ID$
143 HG_TXNNAME=commit
143 HG_TXNNAME=commit
144
144
145 pretxncommit hook: HG_HOOKNAME=pretxncommit
145 pretxncommit hook: HG_HOOKNAME=pretxncommit
146 HG_HOOKTYPE=pretxncommit
146 HG_HOOKTYPE=pretxncommit
147 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
147 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
148 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
148 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
149 HG_PENDING=$TESTTMP/a
149 HG_PENDING=$TESTTMP/a
150
150
151 2:ee9deb46ab31
151 2:ee9deb46ab31
152 pretxnclose hook: HG_HOOKNAME=pretxnclose
152 pretxnclose hook: HG_HOOKNAME=pretxnclose
153 HG_HOOKTYPE=pretxnclose
153 HG_HOOKTYPE=pretxnclose
154 HG_PENDING=$TESTTMP/a
154 HG_PENDING=$TESTTMP/a
155 HG_TXNID=TXN:$ID$
155 HG_TXNID=TXN:$ID$
156 HG_TXNNAME=commit
156 HG_TXNNAME=commit
157
157
158 created new head
158 created new head
159 txnclose hook: HG_HOOKNAME=txnclose
159 txnclose hook: HG_HOOKNAME=txnclose
160 HG_HOOKTYPE=txnclose
160 HG_HOOKTYPE=txnclose
161 HG_TXNID=TXN:$ID$
161 HG_TXNID=TXN:$ID$
162 HG_TXNNAME=commit
162 HG_TXNNAME=commit
163
163
164 commit hook: HG_HOOKNAME=commit
164 commit hook: HG_HOOKNAME=commit
165 HG_HOOKTYPE=commit
165 HG_HOOKTYPE=commit
166 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
166 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
167 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
167 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
168
168
169 commit.b hook: HG_HOOKNAME=commit.b
169 commit.b hook: HG_HOOKNAME=commit.b
170 HG_HOOKTYPE=commit
170 HG_HOOKTYPE=commit
171 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
171 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
172 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
172 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
173
173
174 $ hg merge 1
174 $ hg merge 1
175 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
175 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
176 (branch merge, don't forget to commit)
176 (branch merge, don't forget to commit)
177 $ hg commit -m merge -d '2 0'
177 $ hg commit -m merge -d '2 0'
178 precommit hook: HG_HOOKNAME=precommit
178 precommit hook: HG_HOOKNAME=precommit
179 HG_HOOKTYPE=precommit
179 HG_HOOKTYPE=precommit
180 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
180 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
181 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
181 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
182
182
183 pretxnopen hook: HG_HOOKNAME=pretxnopen
183 pretxnopen hook: HG_HOOKNAME=pretxnopen
184 HG_HOOKTYPE=pretxnopen
184 HG_HOOKTYPE=pretxnopen
185 HG_TXNID=TXN:$ID$
185 HG_TXNID=TXN:$ID$
186 HG_TXNNAME=commit
186 HG_TXNNAME=commit
187
187
188 pretxncommit hook: HG_HOOKNAME=pretxncommit
188 pretxncommit hook: HG_HOOKNAME=pretxncommit
189 HG_HOOKTYPE=pretxncommit
189 HG_HOOKTYPE=pretxncommit
190 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
190 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
191 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
191 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
192 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
192 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
193 HG_PENDING=$TESTTMP/a
193 HG_PENDING=$TESTTMP/a
194
194
195 3:07f3376c1e65
195 3:07f3376c1e65
196 pretxnclose hook: HG_HOOKNAME=pretxnclose
196 pretxnclose hook: HG_HOOKNAME=pretxnclose
197 HG_HOOKTYPE=pretxnclose
197 HG_HOOKTYPE=pretxnclose
198 HG_PENDING=$TESTTMP/a
198 HG_PENDING=$TESTTMP/a
199 HG_TXNID=TXN:$ID$
199 HG_TXNID=TXN:$ID$
200 HG_TXNNAME=commit
200 HG_TXNNAME=commit
201
201
202 txnclose hook: HG_HOOKNAME=txnclose
202 txnclose hook: HG_HOOKNAME=txnclose
203 HG_HOOKTYPE=txnclose
203 HG_HOOKTYPE=txnclose
204 HG_TXNID=TXN:$ID$
204 HG_TXNID=TXN:$ID$
205 HG_TXNNAME=commit
205 HG_TXNNAME=commit
206
206
207 commit hook: HG_HOOKNAME=commit
207 commit hook: HG_HOOKNAME=commit
208 HG_HOOKTYPE=commit
208 HG_HOOKTYPE=commit
209 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
209 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
210 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
210 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
211 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
211 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
212
212
213 commit.b hook: HG_HOOKNAME=commit.b
213 commit.b hook: HG_HOOKNAME=commit.b
214 HG_HOOKTYPE=commit
214 HG_HOOKTYPE=commit
215 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
215 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
216 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
216 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
217 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
217 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
218
218
219
219
220 test generic hooks
220 test generic hooks
221
221
222 $ hg id
222 $ hg id
223 pre-identify hook: HG_ARGS=id
223 pre-identify hook: HG_ARGS=id
224 HG_HOOKNAME=pre-identify
224 HG_HOOKNAME=pre-identify
225 HG_HOOKTYPE=pre-identify
225 HG_HOOKTYPE=pre-identify
226 HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None, 'template': ''}
226 HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None, 'template': ''}
227 HG_PATS=[]
227 HG_PATS=[]
228
228
229 abort: pre-identify hook exited with status 1
229 abort: pre-identify hook exited with status 1
230 [255]
230 [255]
231 $ hg cat b
231 $ hg cat b
232 pre-cat hook: HG_ARGS=cat b
232 pre-cat hook: HG_ARGS=cat b
233 HG_HOOKNAME=pre-cat
233 HG_HOOKNAME=pre-cat
234 HG_HOOKTYPE=pre-cat
234 HG_HOOKTYPE=pre-cat
235 HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': '', 'template': ''}
235 HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': '', 'template': ''}
236 HG_PATS=['b']
236 HG_PATS=['b']
237
237
238 b
238 b
239 post-cat hook: HG_ARGS=cat b
239 post-cat hook: HG_ARGS=cat b
240 HG_HOOKNAME=post-cat
240 HG_HOOKNAME=post-cat
241 HG_HOOKTYPE=post-cat
241 HG_HOOKTYPE=post-cat
242 HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': '', 'template': ''}
242 HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': '', 'template': ''}
243 HG_PATS=['b']
243 HG_PATS=['b']
244 HG_RESULT=0
244 HG_RESULT=0
245
245
246
246
247 $ cd ../b
247 $ cd ../b
248 $ hg pull ../a
248 $ hg pull ../a
249 pulling from ../a
249 pulling from ../a
250 searching for changes
250 searching for changes
251 prechangegroup hook: HG_HOOKNAME=prechangegroup
251 prechangegroup hook: HG_HOOKNAME=prechangegroup
252 HG_HOOKTYPE=prechangegroup
252 HG_HOOKTYPE=prechangegroup
253 HG_SOURCE=pull
253 HG_SOURCE=pull
254 HG_TXNID=TXN:$ID$
254 HG_TXNID=TXN:$ID$
255 HG_TXNNAME=pull
256 file:/*/$TESTTMP/a (glob)
255 HG_URL=file:$TESTTMP/a
257 HG_URL=file:$TESTTMP/a
256
258
257 adding changesets
259 adding changesets
258 adding manifests
260 adding manifests
259 adding file changes
261 adding file changes
260 added 3 changesets with 2 changes to 2 files
262 added 3 changesets with 2 changes to 2 files
261 new changesets ab228980c14d:07f3376c1e65
263 new changesets ab228980c14d:07f3376c1e65
262 changegroup hook: HG_HOOKNAME=changegroup
264 changegroup hook: HG_HOOKNAME=changegroup
263 HG_HOOKTYPE=changegroup
265 HG_HOOKTYPE=changegroup
264 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
266 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
265 HG_NODE_LAST=07f3376c1e655977439df2a814e3cc14b27abac2
267 HG_NODE_LAST=07f3376c1e655977439df2a814e3cc14b27abac2
266 HG_SOURCE=pull
268 HG_SOURCE=pull
267 HG_TXNID=TXN:$ID$
269 HG_TXNID=TXN:$ID$
270 HG_TXNNAME=pull
271 file:/*/$TESTTMP/a (glob)
268 HG_URL=file:$TESTTMP/a
272 HG_URL=file:$TESTTMP/a
269
273
270 incoming hook: HG_HOOKNAME=incoming
274 incoming hook: HG_HOOKNAME=incoming
271 HG_HOOKTYPE=incoming
275 HG_HOOKTYPE=incoming
272 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
276 HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd
273 HG_SOURCE=pull
277 HG_SOURCE=pull
274 HG_TXNID=TXN:$ID$
278 HG_TXNID=TXN:$ID$
279 HG_TXNNAME=pull
280 file:/*/$TESTTMP/a (glob)
275 HG_URL=file:$TESTTMP/a
281 HG_URL=file:$TESTTMP/a
276
282
277 incoming hook: HG_HOOKNAME=incoming
283 incoming hook: HG_HOOKNAME=incoming
278 HG_HOOKTYPE=incoming
284 HG_HOOKTYPE=incoming
279 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
285 HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2
280 HG_SOURCE=pull
286 HG_SOURCE=pull
281 HG_TXNID=TXN:$ID$
287 HG_TXNID=TXN:$ID$
288 HG_TXNNAME=pull
289 file:/*/$TESTTMP/a (glob)
282 HG_URL=file:$TESTTMP/a
290 HG_URL=file:$TESTTMP/a
283
291
284 incoming hook: HG_HOOKNAME=incoming
292 incoming hook: HG_HOOKNAME=incoming
285 HG_HOOKTYPE=incoming
293 HG_HOOKTYPE=incoming
286 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
294 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
287 HG_SOURCE=pull
295 HG_SOURCE=pull
288 HG_TXNID=TXN:$ID$
296 HG_TXNID=TXN:$ID$
297 HG_TXNNAME=pull
298 file:/*/$TESTTMP/a (glob)
289 HG_URL=file:$TESTTMP/a
299 HG_URL=file:$TESTTMP/a
290
300
291 (run 'hg update' to get a working copy)
301 (run 'hg update' to get a working copy)
292
302
293 tag hooks can see env vars
303 tag hooks can see env vars
294
304
295 $ cd ../a
305 $ cd ../a
296 $ cat >> .hg/hgrc <<EOF
306 $ cat >> .hg/hgrc <<EOF
297 > pretag = sh -c "printenv.py --line pretag"
307 > pretag = sh -c "printenv.py --line pretag"
298 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py --line tag"
308 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py --line tag"
299 > EOF
309 > EOF
300 $ hg tag -d '3 0' a
310 $ hg tag -d '3 0' a
301 pretag hook: HG_HOOKNAME=pretag
311 pretag hook: HG_HOOKNAME=pretag
302 HG_HOOKTYPE=pretag
312 HG_HOOKTYPE=pretag
303 HG_LOCAL=0
313 HG_LOCAL=0
304 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
314 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
305 HG_TAG=a
315 HG_TAG=a
306
316
307 precommit hook: HG_HOOKNAME=precommit
317 precommit hook: HG_HOOKNAME=precommit
308 HG_HOOKTYPE=precommit
318 HG_HOOKTYPE=precommit
309 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
319 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
310
320
311 pretxnopen hook: HG_HOOKNAME=pretxnopen
321 pretxnopen hook: HG_HOOKNAME=pretxnopen
312 HG_HOOKTYPE=pretxnopen
322 HG_HOOKTYPE=pretxnopen
313 HG_TXNID=TXN:$ID$
323 HG_TXNID=TXN:$ID$
314 HG_TXNNAME=commit
324 HG_TXNNAME=commit
315
325
316 pretxncommit hook: HG_HOOKNAME=pretxncommit
326 pretxncommit hook: HG_HOOKNAME=pretxncommit
317 HG_HOOKTYPE=pretxncommit
327 HG_HOOKTYPE=pretxncommit
318 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
328 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
319 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
329 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
320 HG_PENDING=$TESTTMP/a
330 HG_PENDING=$TESTTMP/a
321
331
322 4:539e4b31b6dc
332 4:539e4b31b6dc
323 pretxnclose hook: HG_HOOKNAME=pretxnclose
333 pretxnclose hook: HG_HOOKNAME=pretxnclose
324 HG_HOOKTYPE=pretxnclose
334 HG_HOOKTYPE=pretxnclose
325 HG_PENDING=$TESTTMP/a
335 HG_PENDING=$TESTTMP/a
326 HG_TXNID=TXN:$ID$
336 HG_TXNID=TXN:$ID$
327 HG_TXNNAME=commit
337 HG_TXNNAME=commit
328
338
329 tag hook: HG_HOOKNAME=tag
339 tag hook: HG_HOOKNAME=tag
330 HG_HOOKTYPE=tag
340 HG_HOOKTYPE=tag
331 HG_LOCAL=0
341 HG_LOCAL=0
332 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
342 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2
333 HG_TAG=a
343 HG_TAG=a
334
344
335 txnclose hook: HG_HOOKNAME=txnclose
345 txnclose hook: HG_HOOKNAME=txnclose
336 HG_HOOKTYPE=txnclose
346 HG_HOOKTYPE=txnclose
337 HG_TXNID=TXN:$ID$
347 HG_TXNID=TXN:$ID$
338 HG_TXNNAME=commit
348 HG_TXNNAME=commit
339
349
340 commit hook: HG_HOOKNAME=commit
350 commit hook: HG_HOOKNAME=commit
341 HG_HOOKTYPE=commit
351 HG_HOOKTYPE=commit
342 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
352 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
343 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
353 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
344
354
345 commit.b hook: HG_HOOKNAME=commit.b
355 commit.b hook: HG_HOOKNAME=commit.b
346 HG_HOOKTYPE=commit
356 HG_HOOKTYPE=commit
347 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
357 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
348 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
358 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
349
359
350 $ hg tag -l la
360 $ hg tag -l la
351 pretag hook: HG_HOOKNAME=pretag
361 pretag hook: HG_HOOKNAME=pretag
352 HG_HOOKTYPE=pretag
362 HG_HOOKTYPE=pretag
353 HG_LOCAL=1
363 HG_LOCAL=1
354 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
364 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
355 HG_TAG=la
365 HG_TAG=la
356
366
357 tag hook: HG_HOOKNAME=tag
367 tag hook: HG_HOOKNAME=tag
358 HG_HOOKTYPE=tag
368 HG_HOOKTYPE=tag
359 HG_LOCAL=1
369 HG_LOCAL=1
360 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
370 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
361 HG_TAG=la
371 HG_TAG=la
362
372
363
373
364 pretag hook can forbid tagging
374 pretag hook can forbid tagging
365
375
366 $ cat >> .hg/hgrc <<EOF
376 $ cat >> .hg/hgrc <<EOF
367 > pretag.forbid = sh -c "printenv.py --line pretag.forbid 1"
377 > pretag.forbid = sh -c "printenv.py --line pretag.forbid 1"
368 > EOF
378 > EOF
369 $ hg tag -d '4 0' fa
379 $ hg tag -d '4 0' fa
370 pretag hook: HG_HOOKNAME=pretag
380 pretag hook: HG_HOOKNAME=pretag
371 HG_HOOKTYPE=pretag
381 HG_HOOKTYPE=pretag
372 HG_LOCAL=0
382 HG_LOCAL=0
373 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
383 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
374 HG_TAG=fa
384 HG_TAG=fa
375
385
376 pretag.forbid hook: HG_HOOKNAME=pretag.forbid
386 pretag.forbid hook: HG_HOOKNAME=pretag.forbid
377 HG_HOOKTYPE=pretag
387 HG_HOOKTYPE=pretag
378 HG_LOCAL=0
388 HG_LOCAL=0
379 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
389 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
380 HG_TAG=fa
390 HG_TAG=fa
381
391
382 abort: pretag.forbid hook exited with status 1
392 abort: pretag.forbid hook exited with status 1
383 [255]
393 [255]
384 $ hg tag -l fla
394 $ hg tag -l fla
385 pretag hook: HG_HOOKNAME=pretag
395 pretag hook: HG_HOOKNAME=pretag
386 HG_HOOKTYPE=pretag
396 HG_HOOKTYPE=pretag
387 HG_LOCAL=1
397 HG_LOCAL=1
388 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
398 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
389 HG_TAG=fla
399 HG_TAG=fla
390
400
391 pretag.forbid hook: HG_HOOKNAME=pretag.forbid
401 pretag.forbid hook: HG_HOOKNAME=pretag.forbid
392 HG_HOOKTYPE=pretag
402 HG_HOOKTYPE=pretag
393 HG_LOCAL=1
403 HG_LOCAL=1
394 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
404 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
395 HG_TAG=fla
405 HG_TAG=fla
396
406
397 abort: pretag.forbid hook exited with status 1
407 abort: pretag.forbid hook exited with status 1
398 [255]
408 [255]
399
409
400 pretxncommit hook can see changeset, can roll back txn, changeset no
410 pretxncommit hook can see changeset, can roll back txn, changeset no
401 more there after
411 more there after
402
412
403 $ cat >> .hg/hgrc <<EOF
413 $ cat >> .hg/hgrc <<EOF
404 > pretxncommit.forbid0 = sh -c "hg tip -q"
414 > pretxncommit.forbid0 = sh -c "hg tip -q"
405 > pretxncommit.forbid1 = sh -c "printenv.py --line pretxncommit.forbid 1"
415 > pretxncommit.forbid1 = sh -c "printenv.py --line pretxncommit.forbid 1"
406 > EOF
416 > EOF
407 $ echo z > z
417 $ echo z > z
408 $ hg add z
418 $ hg add z
409 $ hg -q tip
419 $ hg -q tip
410 4:539e4b31b6dc
420 4:539e4b31b6dc
411 $ hg commit -m 'fail' -d '4 0'
421 $ hg commit -m 'fail' -d '4 0'
412 precommit hook: HG_HOOKNAME=precommit
422 precommit hook: HG_HOOKNAME=precommit
413 HG_HOOKTYPE=precommit
423 HG_HOOKTYPE=precommit
414 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
424 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
415
425
416 pretxnopen hook: HG_HOOKNAME=pretxnopen
426 pretxnopen hook: HG_HOOKNAME=pretxnopen
417 HG_HOOKTYPE=pretxnopen
427 HG_HOOKTYPE=pretxnopen
418 HG_TXNID=TXN:$ID$
428 HG_TXNID=TXN:$ID$
419 HG_TXNNAME=commit
429 HG_TXNNAME=commit
420
430
421 pretxncommit hook: HG_HOOKNAME=pretxncommit
431 pretxncommit hook: HG_HOOKNAME=pretxncommit
422 HG_HOOKTYPE=pretxncommit
432 HG_HOOKTYPE=pretxncommit
423 HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567
433 HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567
424 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
434 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
425 HG_PENDING=$TESTTMP/a
435 HG_PENDING=$TESTTMP/a
426
436
427 5:6f611f8018c1
437 5:6f611f8018c1
428 5:6f611f8018c1
438 5:6f611f8018c1
429 pretxncommit.forbid hook: HG_HOOKNAME=pretxncommit.forbid1
439 pretxncommit.forbid hook: HG_HOOKNAME=pretxncommit.forbid1
430 HG_HOOKTYPE=pretxncommit
440 HG_HOOKTYPE=pretxncommit
431 HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567
441 HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567
432 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
442 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
433 HG_PENDING=$TESTTMP/a
443 HG_PENDING=$TESTTMP/a
434
444
435 transaction abort!
445 transaction abort!
436 txnabort Python hook: txnid,txnname
446 txnabort Python hook: txnid,txnname
437 txnabort hook: HG_HOOKNAME=txnabort.1
447 txnabort hook: HG_HOOKNAME=txnabort.1
438 HG_HOOKTYPE=txnabort
448 HG_HOOKTYPE=txnabort
439 HG_TXNID=TXN:$ID$
449 HG_TXNID=TXN:$ID$
440 HG_TXNNAME=commit
450 HG_TXNNAME=commit
441
451
442 rollback completed
452 rollback completed
443 abort: pretxncommit.forbid1 hook exited with status 1
453 abort: pretxncommit.forbid1 hook exited with status 1
444 [255]
454 [255]
445 $ hg -q tip
455 $ hg -q tip
446 4:539e4b31b6dc
456 4:539e4b31b6dc
447
457
448 (Check that no 'changelog.i.a' file were left behind)
458 (Check that no 'changelog.i.a' file were left behind)
449
459
450 $ ls -1 .hg/store/
460 $ ls -1 .hg/store/
451 00changelog.i
461 00changelog.i
452 00manifest.i
462 00manifest.i
453 data
463 data
454 fncache (repofncache !)
464 fncache (repofncache !)
455 journal.phaseroots
465 journal.phaseroots
456 phaseroots
466 phaseroots
457 undo
467 undo
458 undo.backup.fncache (repofncache !)
468 undo.backup.fncache (repofncache !)
459 undo.backupfiles
469 undo.backupfiles
460 undo.phaseroots
470 undo.phaseroots
461
471
462
472
463 precommit hook can prevent commit
473 precommit hook can prevent commit
464
474
465 $ cat >> .hg/hgrc <<EOF
475 $ cat >> .hg/hgrc <<EOF
466 > precommit.forbid = sh -c "printenv.py --line precommit.forbid 1"
476 > precommit.forbid = sh -c "printenv.py --line precommit.forbid 1"
467 > EOF
477 > EOF
468 $ hg commit -m 'fail' -d '4 0'
478 $ hg commit -m 'fail' -d '4 0'
469 precommit hook: HG_HOOKNAME=precommit
479 precommit hook: HG_HOOKNAME=precommit
470 HG_HOOKTYPE=precommit
480 HG_HOOKTYPE=precommit
471 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
481 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
472
482
473 precommit.forbid hook: HG_HOOKNAME=precommit.forbid
483 precommit.forbid hook: HG_HOOKNAME=precommit.forbid
474 HG_HOOKTYPE=precommit
484 HG_HOOKTYPE=precommit
475 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
485 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
476
486
477 abort: precommit.forbid hook exited with status 1
487 abort: precommit.forbid hook exited with status 1
478 [255]
488 [255]
479 $ hg -q tip
489 $ hg -q tip
480 4:539e4b31b6dc
490 4:539e4b31b6dc
481
491
482 preupdate hook can prevent update
492 preupdate hook can prevent update
483
493
484 $ cat >> .hg/hgrc <<EOF
494 $ cat >> .hg/hgrc <<EOF
485 > preupdate = sh -c "printenv.py --line preupdate"
495 > preupdate = sh -c "printenv.py --line preupdate"
486 > EOF
496 > EOF
487 $ hg update 1
497 $ hg update 1
488 preupdate hook: HG_HOOKNAME=preupdate
498 preupdate hook: HG_HOOKNAME=preupdate
489 HG_HOOKTYPE=preupdate
499 HG_HOOKTYPE=preupdate
490 HG_PARENT1=ab228980c14d
500 HG_PARENT1=ab228980c14d
491
501
492 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
502 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
493
503
494 update hook
504 update hook
495
505
496 $ cat >> .hg/hgrc <<EOF
506 $ cat >> .hg/hgrc <<EOF
497 > update = sh -c "printenv.py --line update"
507 > update = sh -c "printenv.py --line update"
498 > EOF
508 > EOF
499 $ hg update
509 $ hg update
500 preupdate hook: HG_HOOKNAME=preupdate
510 preupdate hook: HG_HOOKNAME=preupdate
501 HG_HOOKTYPE=preupdate
511 HG_HOOKTYPE=preupdate
502 HG_PARENT1=539e4b31b6dc
512 HG_PARENT1=539e4b31b6dc
503
513
504 update hook: HG_ERROR=0
514 update hook: HG_ERROR=0
505 HG_HOOKNAME=update
515 HG_HOOKNAME=update
506 HG_HOOKTYPE=update
516 HG_HOOKTYPE=update
507 HG_PARENT1=539e4b31b6dc
517 HG_PARENT1=539e4b31b6dc
508
518
509 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
519 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
510
520
511 pushkey hook
521 pushkey hook
512
522
513 $ cat >> .hg/hgrc <<EOF
523 $ cat >> .hg/hgrc <<EOF
514 > pushkey = sh -c "printenv.py --line pushkey"
524 > pushkey = sh -c "printenv.py --line pushkey"
515 > EOF
525 > EOF
516 $ cd ../b
526 $ cd ../b
517 $ hg bookmark -r null foo
527 $ hg bookmark -r null foo
518 $ hg push -B foo ../a
528 $ hg push -B foo ../a
519 pushing to ../a
529 pushing to ../a
520 searching for changes
530 searching for changes
521 no changes found
531 no changes found
522 pretxnopen hook: HG_HOOKNAME=pretxnopen
532 pretxnopen hook: HG_HOOKNAME=pretxnopen
523 HG_HOOKTYPE=pretxnopen
533 HG_HOOKTYPE=pretxnopen
524 HG_TXNID=TXN:$ID$
534 HG_TXNID=TXN:$ID$
525 HG_TXNNAME=push
535 HG_TXNNAME=push
526
536
527 pretxnclose hook: HG_BOOKMARK_MOVED=1
537 pretxnclose hook: HG_BOOKMARK_MOVED=1
528 HG_BUNDLE2=1
538 HG_BUNDLE2=1
529 HG_HOOKNAME=pretxnclose
539 HG_HOOKNAME=pretxnclose
530 HG_HOOKTYPE=pretxnclose
540 HG_HOOKTYPE=pretxnclose
531 HG_PENDING=$TESTTMP/a
541 HG_PENDING=$TESTTMP/a
532 HG_SOURCE=push
542 HG_SOURCE=push
533 HG_TXNID=TXN:$ID$
543 HG_TXNID=TXN:$ID$
534 HG_TXNNAME=push
544 HG_TXNNAME=push
535 HG_URL=file:$TESTTMP/a
545 HG_URL=file:$TESTTMP/a
536
546
537 pushkey hook: HG_BUNDLE2=1
547 pushkey hook: HG_BUNDLE2=1
538 HG_HOOKNAME=pushkey
548 HG_HOOKNAME=pushkey
539 HG_HOOKTYPE=pushkey
549 HG_HOOKTYPE=pushkey
540 HG_KEY=foo
550 HG_KEY=foo
541 HG_NAMESPACE=bookmarks
551 HG_NAMESPACE=bookmarks
542 HG_NEW=0000000000000000000000000000000000000000
552 HG_NEW=0000000000000000000000000000000000000000
543 HG_PUSHKEYCOMPAT=1
553 HG_PUSHKEYCOMPAT=1
544 HG_SOURCE=push
554 HG_SOURCE=push
545 HG_TXNID=TXN:$ID$
555 HG_TXNID=TXN:$ID$
556 HG_TXNNAME=push
546 HG_URL=file:$TESTTMP/a
557 HG_URL=file:$TESTTMP/a
547
558
548 txnclose hook: HG_BOOKMARK_MOVED=1
559 txnclose hook: HG_BOOKMARK_MOVED=1
549 HG_BUNDLE2=1
560 HG_BUNDLE2=1
550 HG_HOOKNAME=txnclose
561 HG_HOOKNAME=txnclose
551 HG_HOOKTYPE=txnclose
562 HG_HOOKTYPE=txnclose
552 HG_SOURCE=push
563 HG_SOURCE=push
553 HG_TXNID=TXN:$ID$
564 HG_TXNID=TXN:$ID$
554 HG_TXNNAME=push
565 HG_TXNNAME=push
555 HG_URL=file:$TESTTMP/a
566 HG_URL=file:$TESTTMP/a
556
567
557 exporting bookmark foo
568 exporting bookmark foo
558 [1]
569 [1]
559 $ cd ../a
570 $ cd ../a
560
571
561 listkeys hook
572 listkeys hook
562
573
563 $ cat >> .hg/hgrc <<EOF
574 $ cat >> .hg/hgrc <<EOF
564 > listkeys = sh -c "printenv.py --line listkeys"
575 > listkeys = sh -c "printenv.py --line listkeys"
565 > EOF
576 > EOF
566 $ hg bookmark -r null bar
577 $ hg bookmark -r null bar
567 pretxnopen hook: HG_HOOKNAME=pretxnopen
578 pretxnopen hook: HG_HOOKNAME=pretxnopen
568 HG_HOOKTYPE=pretxnopen
579 HG_HOOKTYPE=pretxnopen
569 HG_TXNID=TXN:$ID$
580 HG_TXNID=TXN:$ID$
570 HG_TXNNAME=bookmark
581 HG_TXNNAME=bookmark
571
582
572 pretxnclose hook: HG_BOOKMARK_MOVED=1
583 pretxnclose hook: HG_BOOKMARK_MOVED=1
573 HG_HOOKNAME=pretxnclose
584 HG_HOOKNAME=pretxnclose
574 HG_HOOKTYPE=pretxnclose
585 HG_HOOKTYPE=pretxnclose
575 HG_PENDING=$TESTTMP/a
586 HG_PENDING=$TESTTMP/a
576 HG_TXNID=TXN:$ID$
587 HG_TXNID=TXN:$ID$
577 HG_TXNNAME=bookmark
588 HG_TXNNAME=bookmark
578
589
579 txnclose hook: HG_BOOKMARK_MOVED=1
590 txnclose hook: HG_BOOKMARK_MOVED=1
580 HG_HOOKNAME=txnclose
591 HG_HOOKNAME=txnclose
581 HG_HOOKTYPE=txnclose
592 HG_HOOKTYPE=txnclose
582 HG_TXNID=TXN:$ID$
593 HG_TXNID=TXN:$ID$
583 HG_TXNNAME=bookmark
594 HG_TXNNAME=bookmark
584
595
585 $ cd ../b
596 $ cd ../b
586 $ hg pull -B bar ../a
597 $ hg pull -B bar ../a
587 pulling from ../a
598 pulling from ../a
588 listkeys hook: HG_HOOKNAME=listkeys
599 listkeys hook: HG_HOOKNAME=listkeys
589 HG_HOOKTYPE=listkeys
600 HG_HOOKTYPE=listkeys
590 HG_NAMESPACE=bookmarks
601 HG_NAMESPACE=bookmarks
591 HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
602 HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
592
603
593 no changes found
604 no changes found
594 adding remote bookmark bar
605 adding remote bookmark bar
595 $ cd ../a
606 $ cd ../a
596
607
597 test that prepushkey can prevent incoming keys
608 test that prepushkey can prevent incoming keys
598
609
599 $ cat >> .hg/hgrc <<EOF
610 $ cat >> .hg/hgrc <<EOF
600 > prepushkey = sh -c "printenv.py --line prepushkey.forbid 1"
611 > prepushkey = sh -c "printenv.py --line prepushkey.forbid 1"
601 > EOF
612 > EOF
602 $ cd ../b
613 $ cd ../b
603 $ hg bookmark -r null baz
614 $ hg bookmark -r null baz
604 $ hg push -B baz ../a
615 $ hg push -B baz ../a
605 pushing to ../a
616 pushing to ../a
606 searching for changes
617 searching for changes
607 listkeys hook: HG_HOOKNAME=listkeys
618 listkeys hook: HG_HOOKNAME=listkeys
608 HG_HOOKTYPE=listkeys
619 HG_HOOKTYPE=listkeys
609 HG_NAMESPACE=phases
620 HG_NAMESPACE=phases
610 HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
621 HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
611
622
612 listkeys hook: HG_HOOKNAME=listkeys
623 listkeys hook: HG_HOOKNAME=listkeys
613 HG_HOOKTYPE=listkeys
624 HG_HOOKTYPE=listkeys
614 HG_NAMESPACE=bookmarks
625 HG_NAMESPACE=bookmarks
615 HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
626 HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
616
627
617 no changes found
628 no changes found
618 pretxnopen hook: HG_HOOKNAME=pretxnopen
629 pretxnopen hook: HG_HOOKNAME=pretxnopen
619 HG_HOOKTYPE=pretxnopen
630 HG_HOOKTYPE=pretxnopen
620 HG_TXNID=TXN:$ID$
631 HG_TXNID=TXN:$ID$
621 HG_TXNNAME=push
632 HG_TXNNAME=push
622
633
623 prepushkey.forbid hook: HG_BUNDLE2=1
634 prepushkey.forbid hook: HG_BUNDLE2=1
624 HG_HOOKNAME=prepushkey
635 HG_HOOKNAME=prepushkey
625 HG_HOOKTYPE=prepushkey
636 HG_HOOKTYPE=prepushkey
626 HG_KEY=baz
637 HG_KEY=baz
627 HG_NAMESPACE=bookmarks
638 HG_NAMESPACE=bookmarks
628 HG_NEW=0000000000000000000000000000000000000000
639 HG_NEW=0000000000000000000000000000000000000000
629 HG_PUSHKEYCOMPAT=1
640 HG_PUSHKEYCOMPAT=1
630 HG_SOURCE=push
641 HG_SOURCE=push
631 HG_TXNID=TXN:$ID$
642 HG_TXNID=TXN:$ID$
643 HG_TXNNAME=push
632 HG_URL=file:$TESTTMP/a
644 HG_URL=file:$TESTTMP/a
633
645
634 abort: prepushkey hook exited with status 1
646 abort: prepushkey hook exited with status 1
635 [255]
647 [255]
636 $ cd ../a
648 $ cd ../a
637
649
638 test that prelistkeys can prevent listing keys
650 test that prelistkeys can prevent listing keys
639
651
640 $ cat >> .hg/hgrc <<EOF
652 $ cat >> .hg/hgrc <<EOF
641 > prelistkeys = sh -c "printenv.py --line prelistkeys.forbid 1"
653 > prelistkeys = sh -c "printenv.py --line prelistkeys.forbid 1"
642 > EOF
654 > EOF
643 $ hg bookmark -r null quux
655 $ hg bookmark -r null quux
644 pretxnopen hook: HG_HOOKNAME=pretxnopen
656 pretxnopen hook: HG_HOOKNAME=pretxnopen
645 HG_HOOKTYPE=pretxnopen
657 HG_HOOKTYPE=pretxnopen
646 HG_TXNID=TXN:$ID$
658 HG_TXNID=TXN:$ID$
647 HG_TXNNAME=bookmark
659 HG_TXNNAME=bookmark
648
660
649 pretxnclose hook: HG_BOOKMARK_MOVED=1
661 pretxnclose hook: HG_BOOKMARK_MOVED=1
650 HG_HOOKNAME=pretxnclose
662 HG_HOOKNAME=pretxnclose
651 HG_HOOKTYPE=pretxnclose
663 HG_HOOKTYPE=pretxnclose
652 HG_PENDING=$TESTTMP/a
664 HG_PENDING=$TESTTMP/a
653 HG_TXNID=TXN:$ID$
665 HG_TXNID=TXN:$ID$
654 HG_TXNNAME=bookmark
666 HG_TXNNAME=bookmark
655
667
656 txnclose hook: HG_BOOKMARK_MOVED=1
668 txnclose hook: HG_BOOKMARK_MOVED=1
657 HG_HOOKNAME=txnclose
669 HG_HOOKNAME=txnclose
658 HG_HOOKTYPE=txnclose
670 HG_HOOKTYPE=txnclose
659 HG_TXNID=TXN:$ID$
671 HG_TXNID=TXN:$ID$
660 HG_TXNNAME=bookmark
672 HG_TXNNAME=bookmark
661
673
662 $ cd ../b
674 $ cd ../b
663 $ hg pull -B quux ../a
675 $ hg pull -B quux ../a
664 pulling from ../a
676 pulling from ../a
665 prelistkeys.forbid hook: HG_HOOKNAME=prelistkeys
677 prelistkeys.forbid hook: HG_HOOKNAME=prelistkeys
666 HG_HOOKTYPE=prelistkeys
678 HG_HOOKTYPE=prelistkeys
667 HG_NAMESPACE=bookmarks
679 HG_NAMESPACE=bookmarks
668
680
669 abort: prelistkeys hook exited with status 1
681 abort: prelistkeys hook exited with status 1
670 [255]
682 [255]
671 $ cd ../a
683 $ cd ../a
672 $ rm .hg/hgrc
684 $ rm .hg/hgrc
673
685
674 prechangegroup hook can prevent incoming changes
686 prechangegroup hook can prevent incoming changes
675
687
676 $ cd ../b
688 $ cd ../b
677 $ hg -q tip
689 $ hg -q tip
678 3:07f3376c1e65
690 3:07f3376c1e65
679 $ cat > .hg/hgrc <<EOF
691 $ cat > .hg/hgrc <<EOF
680 > [hooks]
692 > [hooks]
681 > prechangegroup.forbid = sh -c "printenv.py --line prechangegroup.forbid 1"
693 > prechangegroup.forbid = sh -c "printenv.py --line prechangegroup.forbid 1"
682 > EOF
694 > EOF
683 $ hg pull ../a
695 $ hg pull ../a
684 pulling from ../a
696 pulling from ../a
685 searching for changes
697 searching for changes
686 prechangegroup.forbid hook: HG_HOOKNAME=prechangegroup.forbid
698 prechangegroup.forbid hook: HG_HOOKNAME=prechangegroup.forbid
687 HG_HOOKTYPE=prechangegroup
699 HG_HOOKTYPE=prechangegroup
688 HG_SOURCE=pull
700 HG_SOURCE=pull
689 HG_TXNID=TXN:$ID$
701 HG_TXNID=TXN:$ID$
702 HG_TXNNAME=pull
703 file:/*/$TESTTMP/a (glob)
690 HG_URL=file:$TESTTMP/a
704 HG_URL=file:$TESTTMP/a
691
705
692 abort: prechangegroup.forbid hook exited with status 1
706 abort: prechangegroup.forbid hook exited with status 1
693 [255]
707 [255]
694
708
695 pretxnchangegroup hook can see incoming changes, can roll back txn,
709 pretxnchangegroup hook can see incoming changes, can roll back txn,
696 incoming changes no longer there after
710 incoming changes no longer there after
697
711
698 $ cat > .hg/hgrc <<EOF
712 $ cat > .hg/hgrc <<EOF
699 > [hooks]
713 > [hooks]
700 > pretxnchangegroup.forbid0 = hg tip -q
714 > pretxnchangegroup.forbid0 = hg tip -q
701 > pretxnchangegroup.forbid1 = sh -c "printenv.py --line pretxnchangegroup.forbid 1"
715 > pretxnchangegroup.forbid1 = sh -c "printenv.py --line pretxnchangegroup.forbid 1"
702 > EOF
716 > EOF
703 $ hg pull ../a
717 $ hg pull ../a
704 pulling from ../a
718 pulling from ../a
705 searching for changes
719 searching for changes
706 adding changesets
720 adding changesets
707 adding manifests
721 adding manifests
708 adding file changes
722 adding file changes
709 added 1 changesets with 1 changes to 1 files
723 added 1 changesets with 1 changes to 1 files
710 4:539e4b31b6dc
724 4:539e4b31b6dc
711 pretxnchangegroup.forbid hook: HG_HOOKNAME=pretxnchangegroup.forbid1
725 pretxnchangegroup.forbid hook: HG_HOOKNAME=pretxnchangegroup.forbid1
712 HG_HOOKTYPE=pretxnchangegroup
726 HG_HOOKTYPE=pretxnchangegroup
713 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
727 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
714 HG_NODE_LAST=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
728 HG_NODE_LAST=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
715 HG_PENDING=$TESTTMP/b
729 HG_PENDING=$TESTTMP/b
716 HG_SOURCE=pull
730 HG_SOURCE=pull
717 HG_TXNID=TXN:$ID$
731 HG_TXNID=TXN:$ID$
732 HG_TXNNAME=pull
733 file:/*/$TESTTMP/a (glob)
718 HG_URL=file:$TESTTMP/a
734 HG_URL=file:$TESTTMP/a
719
735
720 transaction abort!
736 transaction abort!
721 rollback completed
737 rollback completed
722 abort: pretxnchangegroup.forbid1 hook exited with status 1
738 abort: pretxnchangegroup.forbid1 hook exited with status 1
723 [255]
739 [255]
724 $ hg -q tip
740 $ hg -q tip
725 3:07f3376c1e65
741 3:07f3376c1e65
726
742
727 outgoing hooks can see env vars
743 outgoing hooks can see env vars
728
744
729 $ rm .hg/hgrc
745 $ rm .hg/hgrc
730 $ cat > ../a/.hg/hgrc <<EOF
746 $ cat > ../a/.hg/hgrc <<EOF
731 > [hooks]
747 > [hooks]
732 > preoutgoing = sh -c "printenv.py --line preoutgoing"
748 > preoutgoing = sh -c "printenv.py --line preoutgoing"
733 > outgoing = sh -c "printenv.py --line outgoing"
749 > outgoing = sh -c "printenv.py --line outgoing"
734 > EOF
750 > EOF
735 $ hg pull ../a
751 $ hg pull ../a
736 pulling from ../a
752 pulling from ../a
737 searching for changes
753 searching for changes
738 preoutgoing hook: HG_HOOKNAME=preoutgoing
754 preoutgoing hook: HG_HOOKNAME=preoutgoing
739 HG_HOOKTYPE=preoutgoing
755 HG_HOOKTYPE=preoutgoing
740 HG_SOURCE=pull
756 HG_SOURCE=pull
741
757
742 outgoing hook: HG_HOOKNAME=outgoing
758 outgoing hook: HG_HOOKNAME=outgoing
743 HG_HOOKTYPE=outgoing
759 HG_HOOKTYPE=outgoing
744 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
760 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
745 HG_SOURCE=pull
761 HG_SOURCE=pull
746
762
747 adding changesets
763 adding changesets
748 adding manifests
764 adding manifests
749 adding file changes
765 adding file changes
750 added 1 changesets with 1 changes to 1 files
766 added 1 changesets with 1 changes to 1 files
751 adding remote bookmark quux
767 adding remote bookmark quux
752 new changesets 539e4b31b6dc
768 new changesets 539e4b31b6dc
753 (run 'hg update' to get a working copy)
769 (run 'hg update' to get a working copy)
754 $ hg rollback
770 $ hg rollback
755 repository tip rolled back to revision 3 (undo pull)
771 repository tip rolled back to revision 3 (undo pull)
756
772
757 preoutgoing hook can prevent outgoing changes
773 preoutgoing hook can prevent outgoing changes
758
774
759 $ cat >> ../a/.hg/hgrc <<EOF
775 $ cat >> ../a/.hg/hgrc <<EOF
760 > preoutgoing.forbid = sh -c "printenv.py --line preoutgoing.forbid 1"
776 > preoutgoing.forbid = sh -c "printenv.py --line preoutgoing.forbid 1"
761 > EOF
777 > EOF
762 $ hg pull ../a
778 $ hg pull ../a
763 pulling from ../a
779 pulling from ../a
764 searching for changes
780 searching for changes
765 preoutgoing hook: HG_HOOKNAME=preoutgoing
781 preoutgoing hook: HG_HOOKNAME=preoutgoing
766 HG_HOOKTYPE=preoutgoing
782 HG_HOOKTYPE=preoutgoing
767 HG_SOURCE=pull
783 HG_SOURCE=pull
768
784
769 preoutgoing.forbid hook: HG_HOOKNAME=preoutgoing.forbid
785 preoutgoing.forbid hook: HG_HOOKNAME=preoutgoing.forbid
770 HG_HOOKTYPE=preoutgoing
786 HG_HOOKTYPE=preoutgoing
771 HG_SOURCE=pull
787 HG_SOURCE=pull
772
788
773 abort: preoutgoing.forbid hook exited with status 1
789 abort: preoutgoing.forbid hook exited with status 1
774 [255]
790 [255]
775
791
776 outgoing hooks work for local clones
792 outgoing hooks work for local clones
777
793
778 $ cd ..
794 $ cd ..
779 $ cat > a/.hg/hgrc <<EOF
795 $ cat > a/.hg/hgrc <<EOF
780 > [hooks]
796 > [hooks]
781 > preoutgoing = sh -c "printenv.py --line preoutgoing"
797 > preoutgoing = sh -c "printenv.py --line preoutgoing"
782 > outgoing = sh -c "printenv.py --line outgoing"
798 > outgoing = sh -c "printenv.py --line outgoing"
783 > EOF
799 > EOF
784 $ hg clone a c
800 $ hg clone a c
785 preoutgoing hook: HG_HOOKNAME=preoutgoing
801 preoutgoing hook: HG_HOOKNAME=preoutgoing
786 HG_HOOKTYPE=preoutgoing
802 HG_HOOKTYPE=preoutgoing
787 HG_SOURCE=clone
803 HG_SOURCE=clone
788
804
789 outgoing hook: HG_HOOKNAME=outgoing
805 outgoing hook: HG_HOOKNAME=outgoing
790 HG_HOOKTYPE=outgoing
806 HG_HOOKTYPE=outgoing
791 HG_NODE=0000000000000000000000000000000000000000
807 HG_NODE=0000000000000000000000000000000000000000
792 HG_SOURCE=clone
808 HG_SOURCE=clone
793
809
794 updating to branch default
810 updating to branch default
795 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
811 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
796 $ rm -rf c
812 $ rm -rf c
797
813
798 preoutgoing hook can prevent outgoing changes for local clones
814 preoutgoing hook can prevent outgoing changes for local clones
799
815
800 $ cat >> a/.hg/hgrc <<EOF
816 $ cat >> a/.hg/hgrc <<EOF
801 > preoutgoing.forbid = sh -c "printenv.py --line preoutgoing.forbid 1"
817 > preoutgoing.forbid = sh -c "printenv.py --line preoutgoing.forbid 1"
802 > EOF
818 > EOF
803 $ hg clone a zzz
819 $ hg clone a zzz
804 preoutgoing hook: HG_HOOKNAME=preoutgoing
820 preoutgoing hook: HG_HOOKNAME=preoutgoing
805 HG_HOOKTYPE=preoutgoing
821 HG_HOOKTYPE=preoutgoing
806 HG_SOURCE=clone
822 HG_SOURCE=clone
807
823
808 preoutgoing.forbid hook: HG_HOOKNAME=preoutgoing.forbid
824 preoutgoing.forbid hook: HG_HOOKNAME=preoutgoing.forbid
809 HG_HOOKTYPE=preoutgoing
825 HG_HOOKTYPE=preoutgoing
810 HG_SOURCE=clone
826 HG_SOURCE=clone
811
827
812 abort: preoutgoing.forbid hook exited with status 1
828 abort: preoutgoing.forbid hook exited with status 1
813 [255]
829 [255]
814
830
815 $ cd "$TESTTMP/b"
831 $ cd "$TESTTMP/b"
816
832
817 $ cat > hooktests.py <<EOF
833 $ cat > hooktests.py <<EOF
818 > from __future__ import print_function
834 > from __future__ import print_function
819 > from mercurial import (
835 > from mercurial import (
820 > error,
836 > error,
821 > pycompat,
837 > pycompat,
822 > )
838 > )
823 >
839 >
824 > uncallable = 0
840 > uncallable = 0
825 >
841 >
826 > def printargs(ui, args):
842 > def printargs(ui, args):
827 > a = list(pycompat.byteskwargs(args).items())
843 > a = list(pycompat.byteskwargs(args).items())
828 > a.sort()
844 > a.sort()
829 > ui.write(b'hook args:\n')
845 > ui.write(b'hook args:\n')
830 > for k, v in a:
846 > for k, v in a:
831 > ui.write(b' %s %s\n' % (k, v))
847 > ui.write(b' %s %s\n' % (k, v))
832 >
848 >
833 > def passhook(ui, repo, **args):
849 > def passhook(ui, repo, **args):
834 > printargs(ui, args)
850 > printargs(ui, args)
835 >
851 >
836 > def failhook(ui, repo, **args):
852 > def failhook(ui, repo, **args):
837 > printargs(ui, args)
853 > printargs(ui, args)
838 > return True
854 > return True
839 >
855 >
840 > class LocalException(Exception):
856 > class LocalException(Exception):
841 > pass
857 > pass
842 >
858 >
843 > def raisehook(**args):
859 > def raisehook(**args):
844 > raise LocalException('exception from hook')
860 > raise LocalException('exception from hook')
845 >
861 >
846 > def aborthook(**args):
862 > def aborthook(**args):
847 > raise error.Abort(b'raise abort from hook')
863 > raise error.Abort(b'raise abort from hook')
848 >
864 >
849 > def brokenhook(**args):
865 > def brokenhook(**args):
850 > return 1 + {}
866 > return 1 + {}
851 >
867 >
852 > def verbosehook(ui, **args):
868 > def verbosehook(ui, **args):
853 > ui.note(b'verbose output from hook\n')
869 > ui.note(b'verbose output from hook\n')
854 >
870 >
855 > def printtags(ui, repo, **args):
871 > def printtags(ui, repo, **args):
856 > ui.write(b'[%s]\n' % b', '.join(sorted(repo.tags())))
872 > ui.write(b'[%s]\n' % b', '.join(sorted(repo.tags())))
857 >
873 >
858 > class container(object):
874 > class container(object):
859 > unreachable = 1
875 > unreachable = 1
860 > EOF
876 > EOF
861
877
862 $ cat > syntaxerror.py << NO_CHECK_EOF
878 $ cat > syntaxerror.py << NO_CHECK_EOF
863 > (foo
879 > (foo
864 > NO_CHECK_EOF
880 > NO_CHECK_EOF
865
881
866 test python hooks
882 test python hooks
867
883
868 #if windows
884 #if windows
869 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
885 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
870 #else
886 #else
871 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
887 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
872 #endif
888 #endif
873 $ export PYTHONPATH
889 $ export PYTHONPATH
874
890
875 $ echo '[hooks]' > ../a/.hg/hgrc
891 $ echo '[hooks]' > ../a/.hg/hgrc
876 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
892 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
877 $ hg pull ../a 2>&1 | grep 'raised an exception'
893 $ hg pull ../a 2>&1 | grep 'raised an exception'
878 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
894 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
879
895
880 $ echo '[hooks]' > ../a/.hg/hgrc
896 $ echo '[hooks]' > ../a/.hg/hgrc
881 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
897 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
882 $ hg pull ../a 2>&1 | grep 'raised an exception'
898 $ hg pull ../a 2>&1 | grep 'raised an exception'
883 error: preoutgoing.raise hook raised an exception: exception from hook
899 error: preoutgoing.raise hook raised an exception: exception from hook
884
900
885 $ echo '[hooks]' > ../a/.hg/hgrc
901 $ echo '[hooks]' > ../a/.hg/hgrc
886 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
902 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
887 $ hg pull ../a
903 $ hg pull ../a
888 pulling from ../a
904 pulling from ../a
889 searching for changes
905 searching for changes
890 error: preoutgoing.abort hook failed: raise abort from hook
906 error: preoutgoing.abort hook failed: raise abort from hook
891 abort: raise abort from hook
907 abort: raise abort from hook
892 [255]
908 [255]
893
909
894 $ echo '[hooks]' > ../a/.hg/hgrc
910 $ echo '[hooks]' > ../a/.hg/hgrc
895 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
911 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
896 $ hg pull ../a
912 $ hg pull ../a
897 pulling from ../a
913 pulling from ../a
898 searching for changes
914 searching for changes
899 hook args:
915 hook args:
900 hooktype preoutgoing
916 hooktype preoutgoing
901 source pull
917 source pull
902 abort: preoutgoing.fail hook failed
918 abort: preoutgoing.fail hook failed
903 [255]
919 [255]
904
920
905 $ echo '[hooks]' > ../a/.hg/hgrc
921 $ echo '[hooks]' > ../a/.hg/hgrc
906 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
922 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
907 $ hg pull ../a
923 $ hg pull ../a
908 pulling from ../a
924 pulling from ../a
909 searching for changes
925 searching for changes
910 abort: preoutgoing.uncallable hook is invalid: "hooktests.uncallable" is not callable
926 abort: preoutgoing.uncallable hook is invalid: "hooktests.uncallable" is not callable
911 [255]
927 [255]
912
928
913 $ echo '[hooks]' > ../a/.hg/hgrc
929 $ echo '[hooks]' > ../a/.hg/hgrc
914 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
930 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
915 $ hg pull ../a
931 $ hg pull ../a
916 pulling from ../a
932 pulling from ../a
917 searching for changes
933 searching for changes
918 abort: preoutgoing.nohook hook is invalid: "hooktests.nohook" is not defined
934 abort: preoutgoing.nohook hook is invalid: "hooktests.nohook" is not defined
919 [255]
935 [255]
920
936
921 $ echo '[hooks]' > ../a/.hg/hgrc
937 $ echo '[hooks]' > ../a/.hg/hgrc
922 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
938 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
923 $ hg pull ../a
939 $ hg pull ../a
924 pulling from ../a
940 pulling from ../a
925 searching for changes
941 searching for changes
926 abort: preoutgoing.nomodule hook is invalid: "nomodule" not in a module
942 abort: preoutgoing.nomodule hook is invalid: "nomodule" not in a module
927 [255]
943 [255]
928
944
929 $ echo '[hooks]' > ../a/.hg/hgrc
945 $ echo '[hooks]' > ../a/.hg/hgrc
930 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
946 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
931 $ hg pull ../a
947 $ hg pull ../a
932 pulling from ../a
948 pulling from ../a
933 searching for changes
949 searching for changes
934 abort: preoutgoing.badmodule hook is invalid: import of "nomodule" failed
950 abort: preoutgoing.badmodule hook is invalid: import of "nomodule" failed
935 (run with --traceback for stack trace)
951 (run with --traceback for stack trace)
936 [255]
952 [255]
937
953
938 $ echo '[hooks]' > ../a/.hg/hgrc
954 $ echo '[hooks]' > ../a/.hg/hgrc
939 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
955 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
940 $ hg pull ../a
956 $ hg pull ../a
941 pulling from ../a
957 pulling from ../a
942 searching for changes
958 searching for changes
943 abort: preoutgoing.unreachable hook is invalid: import of "hooktests.container" failed
959 abort: preoutgoing.unreachable hook is invalid: import of "hooktests.container" failed
944 (run with --traceback for stack trace)
960 (run with --traceback for stack trace)
945 [255]
961 [255]
946
962
947 $ echo '[hooks]' > ../a/.hg/hgrc
963 $ echo '[hooks]' > ../a/.hg/hgrc
948 $ echo 'preoutgoing.syntaxerror = python:syntaxerror.syntaxerror' >> ../a/.hg/hgrc
964 $ echo 'preoutgoing.syntaxerror = python:syntaxerror.syntaxerror' >> ../a/.hg/hgrc
949 $ hg pull ../a
965 $ hg pull ../a
950 pulling from ../a
966 pulling from ../a
951 searching for changes
967 searching for changes
952 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
968 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
953 (run with --traceback for stack trace)
969 (run with --traceback for stack trace)
954 [255]
970 [255]
955
971
956 The second egrep is to filter out lines like ' ^', which are slightly
972 The second egrep is to filter out lines like ' ^', which are slightly
957 different between Python 2.6 and Python 2.7.
973 different between Python 2.6 and Python 2.7.
958 $ hg pull ../a --traceback 2>&1 | egrep -v '^( +File| [_a-zA-Z*(])' | egrep -v '^( )+(\^)?$'
974 $ hg pull ../a --traceback 2>&1 | egrep -v '^( +File| [_a-zA-Z*(])' | egrep -v '^( )+(\^)?$'
959 pulling from ../a
975 pulling from ../a
960 searching for changes
976 searching for changes
961 exception from first failed import attempt:
977 exception from first failed import attempt:
962 Traceback (most recent call last):
978 Traceback (most recent call last):
963 SyntaxError: * (glob)
979 SyntaxError: * (glob)
964 exception from second failed import attempt:
980 exception from second failed import attempt:
965 Traceback (most recent call last):
981 Traceback (most recent call last):
966 ImportError: No module named hgext_syntaxerror
982 ImportError: No module named hgext_syntaxerror
967 Traceback (most recent call last):
983 Traceback (most recent call last):
968 HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
984 HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
969 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
985 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
970
986
971 $ echo '[hooks]' > ../a/.hg/hgrc
987 $ echo '[hooks]' > ../a/.hg/hgrc
972 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
988 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
973 $ hg pull ../a
989 $ hg pull ../a
974 pulling from ../a
990 pulling from ../a
975 searching for changes
991 searching for changes
976 hook args:
992 hook args:
977 hooktype preoutgoing
993 hooktype preoutgoing
978 source pull
994 source pull
979 adding changesets
995 adding changesets
980 adding manifests
996 adding manifests
981 adding file changes
997 adding file changes
982 added 1 changesets with 1 changes to 1 files
998 added 1 changesets with 1 changes to 1 files
983 adding remote bookmark quux
999 adding remote bookmark quux
984 new changesets 539e4b31b6dc
1000 new changesets 539e4b31b6dc
985 (run 'hg update' to get a working copy)
1001 (run 'hg update' to get a working copy)
986
1002
987 post- python hooks that fail to *run* don't cause an abort
1003 post- python hooks that fail to *run* don't cause an abort
988 $ rm ../a/.hg/hgrc
1004 $ rm ../a/.hg/hgrc
989 $ echo '[hooks]' > .hg/hgrc
1005 $ echo '[hooks]' > .hg/hgrc
990 $ echo 'post-pull.broken = python:hooktests.brokenhook' >> .hg/hgrc
1006 $ echo 'post-pull.broken = python:hooktests.brokenhook' >> .hg/hgrc
991 $ hg pull ../a
1007 $ hg pull ../a
992 pulling from ../a
1008 pulling from ../a
993 searching for changes
1009 searching for changes
994 no changes found
1010 no changes found
995 error: post-pull.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
1011 error: post-pull.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
996 (run with --traceback for stack trace)
1012 (run with --traceback for stack trace)
997
1013
998 but post- python hooks that fail to *load* do
1014 but post- python hooks that fail to *load* do
999 $ echo '[hooks]' > .hg/hgrc
1015 $ echo '[hooks]' > .hg/hgrc
1000 $ echo 'post-pull.nomodule = python:nomodule' >> .hg/hgrc
1016 $ echo 'post-pull.nomodule = python:nomodule' >> .hg/hgrc
1001 $ hg pull ../a
1017 $ hg pull ../a
1002 pulling from ../a
1018 pulling from ../a
1003 searching for changes
1019 searching for changes
1004 no changes found
1020 no changes found
1005 abort: post-pull.nomodule hook is invalid: "nomodule" not in a module
1021 abort: post-pull.nomodule hook is invalid: "nomodule" not in a module
1006 [255]
1022 [255]
1007
1023
1008 $ echo '[hooks]' > .hg/hgrc
1024 $ echo '[hooks]' > .hg/hgrc
1009 $ echo 'post-pull.badmodule = python:nomodule.nowhere' >> .hg/hgrc
1025 $ echo 'post-pull.badmodule = python:nomodule.nowhere' >> .hg/hgrc
1010 $ hg pull ../a
1026 $ hg pull ../a
1011 pulling from ../a
1027 pulling from ../a
1012 searching for changes
1028 searching for changes
1013 no changes found
1029 no changes found
1014 abort: post-pull.badmodule hook is invalid: import of "nomodule" failed
1030 abort: post-pull.badmodule hook is invalid: import of "nomodule" failed
1015 (run with --traceback for stack trace)
1031 (run with --traceback for stack trace)
1016 [255]
1032 [255]
1017
1033
1018 $ echo '[hooks]' > .hg/hgrc
1034 $ echo '[hooks]' > .hg/hgrc
1019 $ echo 'post-pull.nohook = python:hooktests.nohook' >> .hg/hgrc
1035 $ echo 'post-pull.nohook = python:hooktests.nohook' >> .hg/hgrc
1020 $ hg pull ../a
1036 $ hg pull ../a
1021 pulling from ../a
1037 pulling from ../a
1022 searching for changes
1038 searching for changes
1023 no changes found
1039 no changes found
1024 abort: post-pull.nohook hook is invalid: "hooktests.nohook" is not defined
1040 abort: post-pull.nohook hook is invalid: "hooktests.nohook" is not defined
1025 [255]
1041 [255]
1026
1042
1027 make sure --traceback works
1043 make sure --traceback works
1028
1044
1029 $ echo '[hooks]' > .hg/hgrc
1045 $ echo '[hooks]' > .hg/hgrc
1030 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
1046 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
1031
1047
1032 $ echo aa > a
1048 $ echo aa > a
1033 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
1049 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
1034 Traceback (most recent call last):
1050 Traceback (most recent call last):
1035
1051
1036 $ cd ..
1052 $ cd ..
1037 $ hg init c
1053 $ hg init c
1038 $ cd c
1054 $ cd c
1039
1055
1040 $ cat > hookext.py <<EOF
1056 $ cat > hookext.py <<EOF
1041 > def autohook(ui, **args):
1057 > def autohook(ui, **args):
1042 > ui.write(b'Automatically installed hook\n')
1058 > ui.write(b'Automatically installed hook\n')
1043 >
1059 >
1044 > def reposetup(ui, repo):
1060 > def reposetup(ui, repo):
1045 > repo.ui.setconfig(b"hooks", b"commit.auto", autohook)
1061 > repo.ui.setconfig(b"hooks", b"commit.auto", autohook)
1046 > EOF
1062 > EOF
1047 $ echo '[extensions]' >> .hg/hgrc
1063 $ echo '[extensions]' >> .hg/hgrc
1048 $ echo 'hookext = hookext.py' >> .hg/hgrc
1064 $ echo 'hookext = hookext.py' >> .hg/hgrc
1049
1065
1050 $ touch foo
1066 $ touch foo
1051 $ hg add foo
1067 $ hg add foo
1052 $ hg ci -d '0 0' -m 'add foo'
1068 $ hg ci -d '0 0' -m 'add foo'
1053 Automatically installed hook
1069 Automatically installed hook
1054 $ echo >> foo
1070 $ echo >> foo
1055 $ hg ci --debug -d '0 0' -m 'change foo'
1071 $ hg ci --debug -d '0 0' -m 'change foo'
1056 committing files:
1072 committing files:
1057 foo
1073 foo
1058 committing manifest
1074 committing manifest
1059 committing changelog
1075 committing changelog
1060 updating the branch cache
1076 updating the branch cache
1061 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
1077 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
1062 calling hook commit.auto: hgext_hookext.autohook
1078 calling hook commit.auto: hgext_hookext.autohook
1063 Automatically installed hook
1079 Automatically installed hook
1064
1080
1065 $ hg showconfig hooks
1081 $ hg showconfig hooks
1066 hooks.commit.auto=<function autohook at *> (glob)
1082 hooks.commit.auto=<function autohook at *> (glob)
1067
1083
1068 test python hook configured with python:[file]:[hook] syntax
1084 test python hook configured with python:[file]:[hook] syntax
1069
1085
1070 $ cd ..
1086 $ cd ..
1071 $ mkdir d
1087 $ mkdir d
1072 $ cd d
1088 $ cd d
1073 $ hg init repo
1089 $ hg init repo
1074 $ mkdir hooks
1090 $ mkdir hooks
1075
1091
1076 $ cd hooks
1092 $ cd hooks
1077 $ cat > testhooks.py <<EOF
1093 $ cat > testhooks.py <<EOF
1078 > def testhook(ui, **args):
1094 > def testhook(ui, **args):
1079 > ui.write(b'hook works\n')
1095 > ui.write(b'hook works\n')
1080 > EOF
1096 > EOF
1081 $ echo '[hooks]' > ../repo/.hg/hgrc
1097 $ echo '[hooks]' > ../repo/.hg/hgrc
1082 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
1098 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
1083
1099
1084 $ cd ../repo
1100 $ cd ../repo
1085 $ hg commit -d '0 0'
1101 $ hg commit -d '0 0'
1086 hook works
1102 hook works
1087 nothing changed
1103 nothing changed
1088 [1]
1104 [1]
1089
1105
1090 $ echo '[hooks]' > .hg/hgrc
1106 $ echo '[hooks]' > .hg/hgrc
1091 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
1107 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
1092 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
1108 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
1093
1109
1094 $ hg up null
1110 $ hg up null
1095 loading update.ne hook failed:
1111 loading update.ne hook failed:
1096 abort: $ENOENT$: '$TESTTMP/d/repo/nonexistent.py'
1112 abort: $ENOENT$: '$TESTTMP/d/repo/nonexistent.py'
1097 [255]
1113 [255]
1098
1114
1099 $ hg id
1115 $ hg id
1100 loading pre-identify.npmd hook failed:
1116 loading pre-identify.npmd hook failed:
1101 abort: No module named repo!
1117 abort: No module named repo!
1102 [255]
1118 [255]
1103
1119
1104 $ cd ../../b
1120 $ cd ../../b
1105
1121
1106 make sure --traceback works on hook import failure
1122 make sure --traceback works on hook import failure
1107
1123
1108 $ cat > importfail.py <<EOF
1124 $ cat > importfail.py <<EOF
1109 > import somebogusmodule
1125 > import somebogusmodule
1110 > # dereference something in the module to force demandimport to load it
1126 > # dereference something in the module to force demandimport to load it
1111 > somebogusmodule.whatever
1127 > somebogusmodule.whatever
1112 > EOF
1128 > EOF
1113
1129
1114 $ echo '[hooks]' > .hg/hgrc
1130 $ echo '[hooks]' > .hg/hgrc
1115 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
1131 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
1116
1132
1117 $ echo a >> a
1133 $ echo a >> a
1118 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
1134 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
1119 exception from first failed import attempt:
1135 exception from first failed import attempt:
1120 Traceback (most recent call last):
1136 Traceback (most recent call last):
1121 ImportError: No module named somebogusmodule
1137 ImportError: No module named somebogusmodule
1122 exception from second failed import attempt:
1138 exception from second failed import attempt:
1123 Traceback (most recent call last):
1139 Traceback (most recent call last):
1124 ImportError: No module named hgext_importfail
1140 ImportError: No module named hgext_importfail
1125 Traceback (most recent call last):
1141 Traceback (most recent call last):
1126 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed
1142 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed
1127 abort: precommit.importfail hook is invalid: import of "importfail" failed
1143 abort: precommit.importfail hook is invalid: import of "importfail" failed
1128
1144
1129 Issue1827: Hooks Update & Commit not completely post operation
1145 Issue1827: Hooks Update & Commit not completely post operation
1130
1146
1131 commit and update hooks should run after command completion. The largefiles
1147 commit and update hooks should run after command completion. The largefiles
1132 use demonstrates a recursive wlock, showing the hook doesn't run until the
1148 use demonstrates a recursive wlock, showing the hook doesn't run until the
1133 final release (and dirstate flush).
1149 final release (and dirstate flush).
1134
1150
1135 $ echo '[hooks]' > .hg/hgrc
1151 $ echo '[hooks]' > .hg/hgrc
1136 $ echo 'commit = hg id' >> .hg/hgrc
1152 $ echo 'commit = hg id' >> .hg/hgrc
1137 $ echo 'update = hg id' >> .hg/hgrc
1153 $ echo 'update = hg id' >> .hg/hgrc
1138 $ echo bb > a
1154 $ echo bb > a
1139 $ hg ci -ma
1155 $ hg ci -ma
1140 223eafe2750c tip
1156 223eafe2750c tip
1141 $ hg up 0 --config extensions.largefiles=
1157 $ hg up 0 --config extensions.largefiles=
1142 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
1158 The fsmonitor extension is incompatible with the largefiles extension and has been disabled. (fsmonitor !)
1143 cb9a9f314b8b
1159 cb9a9f314b8b
1144 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1160 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1145
1161
1146 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
1162 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
1147 that is passed to pre/post hooks
1163 that is passed to pre/post hooks
1148
1164
1149 $ echo '[hooks]' > .hg/hgrc
1165 $ echo '[hooks]' > .hg/hgrc
1150 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
1166 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
1151 $ hg id
1167 $ hg id
1152 cb9a9f314b8b
1168 cb9a9f314b8b
1153 $ hg id --verbose
1169 $ hg id --verbose
1154 calling hook pre-identify: hooktests.verbosehook
1170 calling hook pre-identify: hooktests.verbosehook
1155 verbose output from hook
1171 verbose output from hook
1156 cb9a9f314b8b
1172 cb9a9f314b8b
1157
1173
1158 Ensure hooks can be prioritized
1174 Ensure hooks can be prioritized
1159
1175
1160 $ echo '[hooks]' > .hg/hgrc
1176 $ echo '[hooks]' > .hg/hgrc
1161 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
1177 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
1162 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
1178 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
1163 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
1179 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
1164 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
1180 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
1165 $ hg id --verbose
1181 $ hg id --verbose
1166 calling hook pre-identify.b: hooktests.verbosehook
1182 calling hook pre-identify.b: hooktests.verbosehook
1167 verbose output from hook
1183 verbose output from hook
1168 calling hook pre-identify.a: hooktests.verbosehook
1184 calling hook pre-identify.a: hooktests.verbosehook
1169 verbose output from hook
1185 verbose output from hook
1170 calling hook pre-identify.c: hooktests.verbosehook
1186 calling hook pre-identify.c: hooktests.verbosehook
1171 verbose output from hook
1187 verbose output from hook
1172 cb9a9f314b8b
1188 cb9a9f314b8b
1173
1189
1174 new tags must be visible in pretxncommit (issue3210)
1190 new tags must be visible in pretxncommit (issue3210)
1175
1191
1176 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
1192 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
1177 $ hg tag -f foo
1193 $ hg tag -f foo
1178 [a, foo, tip]
1194 [a, foo, tip]
1179
1195
1180 post-init hooks must not crash (issue4983)
1196 post-init hooks must not crash (issue4983)
1181 This also creates the `to` repo for the next test block.
1197 This also creates the `to` repo for the next test block.
1182
1198
1183 $ cd ..
1199 $ cd ..
1184 $ cat << EOF >> hgrc-with-post-init-hook
1200 $ cat << EOF >> hgrc-with-post-init-hook
1185 > [hooks]
1201 > [hooks]
1186 > post-init = sh -c "printenv.py --line post-init"
1202 > post-init = sh -c "printenv.py --line post-init"
1187 > EOF
1203 > EOF
1188 $ HGRCPATH=hgrc-with-post-init-hook hg init to
1204 $ HGRCPATH=hgrc-with-post-init-hook hg init to
1189 post-init hook: HG_ARGS=init to
1205 post-init hook: HG_ARGS=init to
1190 HG_HOOKNAME=post-init
1206 HG_HOOKNAME=post-init
1191 HG_HOOKTYPE=post-init
1207 HG_HOOKTYPE=post-init
1192 HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''}
1208 HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''}
1193 HG_PATS=['to']
1209 HG_PATS=['to']
1194 HG_RESULT=0
1210 HG_RESULT=0
1195
1211
1196
1212
1197 new commits must be visible in pretxnchangegroup (issue3428)
1213 new commits must be visible in pretxnchangegroup (issue3428)
1198
1214
1199 $ echo '[hooks]' >> to/.hg/hgrc
1215 $ echo '[hooks]' >> to/.hg/hgrc
1200 $ echo 'prechangegroup = hg --traceback tip' >> to/.hg/hgrc
1216 $ echo 'prechangegroup = hg --traceback tip' >> to/.hg/hgrc
1201 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
1217 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
1202 $ echo a >> to/a
1218 $ echo a >> to/a
1203 $ hg --cwd to ci -Ama
1219 $ hg --cwd to ci -Ama
1204 adding a
1220 adding a
1205 $ hg clone to from
1221 $ hg clone to from
1206 updating to branch default
1222 updating to branch default
1207 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1223 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1208 $ echo aa >> from/a
1224 $ echo aa >> from/a
1209 $ hg --cwd from ci -mb
1225 $ hg --cwd from ci -mb
1210 $ hg --cwd from push
1226 $ hg --cwd from push
1211 pushing to $TESTTMP/to
1227 pushing to $TESTTMP/to
1212 searching for changes
1228 searching for changes
1213 changeset: 0:cb9a9f314b8b
1229 changeset: 0:cb9a9f314b8b
1214 tag: tip
1230 tag: tip
1215 user: test
1231 user: test
1216 date: Thu Jan 01 00:00:00 1970 +0000
1232 date: Thu Jan 01 00:00:00 1970 +0000
1217 summary: a
1233 summary: a
1218
1234
1219 adding changesets
1235 adding changesets
1220 adding manifests
1236 adding manifests
1221 adding file changes
1237 adding file changes
1222 added 1 changesets with 1 changes to 1 files
1238 added 1 changesets with 1 changes to 1 files
1223 changeset: 1:9836a07b9b9d
1239 changeset: 1:9836a07b9b9d
1224 tag: tip
1240 tag: tip
1225 user: test
1241 user: test
1226 date: Thu Jan 01 00:00:00 1970 +0000
1242 date: Thu Jan 01 00:00:00 1970 +0000
1227 summary: b
1243 summary: b
1228
1244
1229
1245
1230 pretxnclose hook failure should abort the transaction
1246 pretxnclose hook failure should abort the transaction
1231
1247
1232 $ hg init txnfailure
1248 $ hg init txnfailure
1233 $ cd txnfailure
1249 $ cd txnfailure
1234 $ touch a && hg commit -Aqm a
1250 $ touch a && hg commit -Aqm a
1235 $ cat >> .hg/hgrc <<EOF
1251 $ cat >> .hg/hgrc <<EOF
1236 > [hooks]
1252 > [hooks]
1237 > pretxnclose.error = exit 1
1253 > pretxnclose.error = exit 1
1238 > EOF
1254 > EOF
1239 $ hg strip -r 0 --config extensions.strip=
1255 $ hg strip -r 0 --config extensions.strip=
1240 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1256 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1241 saved backup bundle to * (glob)
1257 saved backup bundle to * (glob)
1242 transaction abort!
1258 transaction abort!
1243 rollback completed
1259 rollback completed
1244 strip failed, backup bundle stored in * (glob)
1260 strip failed, backup bundle stored in * (glob)
1245 abort: pretxnclose.error hook exited with status 1
1261 abort: pretxnclose.error hook exited with status 1
1246 [255]
1262 [255]
1247 $ hg recover
1263 $ hg recover
1248 no interrupted transaction available
1264 no interrupted transaction available
1249 [1]
1265 [1]
1250 $ cd ..
1266 $ cd ..
1251
1267
1252 check whether HG_PENDING makes pending changes only in related
1268 check whether HG_PENDING makes pending changes only in related
1253 repositories visible to an external hook.
1269 repositories visible to an external hook.
1254
1270
1255 (emulate a transaction running concurrently by copied
1271 (emulate a transaction running concurrently by copied
1256 .hg/store/00changelog.i.a in subsequent test)
1272 .hg/store/00changelog.i.a in subsequent test)
1257
1273
1258 $ cat > $TESTTMP/savepending.sh <<EOF
1274 $ cat > $TESTTMP/savepending.sh <<EOF
1259 > cp .hg/store/00changelog.i.a .hg/store/00changelog.i.a.saved
1275 > cp .hg/store/00changelog.i.a .hg/store/00changelog.i.a.saved
1260 > exit 1 # to avoid adding new revision for subsequent tests
1276 > exit 1 # to avoid adding new revision for subsequent tests
1261 > EOF
1277 > EOF
1262 $ cd a
1278 $ cd a
1263 $ hg tip -q
1279 $ hg tip -q
1264 4:539e4b31b6dc
1280 4:539e4b31b6dc
1265 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" commit -m "invisible"
1281 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" commit -m "invisible"
1266 transaction abort!
1282 transaction abort!
1267 rollback completed
1283 rollback completed
1268 abort: pretxnclose hook exited with status 1
1284 abort: pretxnclose hook exited with status 1
1269 [255]
1285 [255]
1270 $ cp .hg/store/00changelog.i.a.saved .hg/store/00changelog.i.a
1286 $ cp .hg/store/00changelog.i.a.saved .hg/store/00changelog.i.a
1271
1287
1272 (check (in)visibility of new changeset while transaction running in
1288 (check (in)visibility of new changeset while transaction running in
1273 repo)
1289 repo)
1274
1290
1275 $ cat > $TESTTMP/checkpending.sh <<EOF
1291 $ cat > $TESTTMP/checkpending.sh <<EOF
1276 > echo '@a'
1292 > echo '@a'
1277 > hg -R "$TESTTMP/a" tip -q
1293 > hg -R "$TESTTMP/a" tip -q
1278 > echo '@a/nested'
1294 > echo '@a/nested'
1279 > hg -R "$TESTTMP/a/nested" tip -q
1295 > hg -R "$TESTTMP/a/nested" tip -q
1280 > exit 1 # to avoid adding new revision for subsequent tests
1296 > exit 1 # to avoid adding new revision for subsequent tests
1281 > EOF
1297 > EOF
1282 $ hg init nested
1298 $ hg init nested
1283 $ cd nested
1299 $ cd nested
1284 $ echo a > a
1300 $ echo a > a
1285 $ hg add a
1301 $ hg add a
1286 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" commit -m '#0'
1302 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" commit -m '#0'
1287 @a
1303 @a
1288 4:539e4b31b6dc
1304 4:539e4b31b6dc
1289 @a/nested
1305 @a/nested
1290 0:bf5e395ced2c
1306 0:bf5e395ced2c
1291 transaction abort!
1307 transaction abort!
1292 rollback completed
1308 rollback completed
1293 abort: pretxnclose hook exited with status 1
1309 abort: pretxnclose hook exited with status 1
1294 [255]
1310 [255]
1295
1311
1296 Hook from untrusted hgrc are reported as failure
1312 Hook from untrusted hgrc are reported as failure
1297 ================================================
1313 ================================================
1298
1314
1299 $ cat << EOF > $TESTTMP/untrusted.py
1315 $ cat << EOF > $TESTTMP/untrusted.py
1300 > from mercurial import scmutil, util
1316 > from mercurial import scmutil, util
1301 > def uisetup(ui):
1317 > def uisetup(ui):
1302 > class untrustedui(ui.__class__):
1318 > class untrustedui(ui.__class__):
1303 > def _trusted(self, fp, f):
1319 > def _trusted(self, fp, f):
1304 > if util.normpath(fp.name).endswith(b'untrusted/.hg/hgrc'):
1320 > if util.normpath(fp.name).endswith(b'untrusted/.hg/hgrc'):
1305 > return False
1321 > return False
1306 > return super(untrustedui, self)._trusted(fp, f)
1322 > return super(untrustedui, self)._trusted(fp, f)
1307 > ui.__class__ = untrustedui
1323 > ui.__class__ = untrustedui
1308 > EOF
1324 > EOF
1309 $ cat << EOF >> $HGRCPATH
1325 $ cat << EOF >> $HGRCPATH
1310 > [extensions]
1326 > [extensions]
1311 > untrusted=$TESTTMP/untrusted.py
1327 > untrusted=$TESTTMP/untrusted.py
1312 > EOF
1328 > EOF
1313 $ hg init untrusted
1329 $ hg init untrusted
1314 $ cd untrusted
1330 $ cd untrusted
1315
1331
1316 Non-blocking hook
1332 Non-blocking hook
1317 -----------------
1333 -----------------
1318
1334
1319 $ cat << EOF >> .hg/hgrc
1335 $ cat << EOF >> .hg/hgrc
1320 > [hooks]
1336 > [hooks]
1321 > txnclose.testing=echo txnclose hook called
1337 > txnclose.testing=echo txnclose hook called
1322 > EOF
1338 > EOF
1323 $ touch a && hg commit -Aqm a
1339 $ touch a && hg commit -Aqm a
1324 warning: untrusted hook txnclose.testing not executed
1340 warning: untrusted hook txnclose.testing not executed
1325 $ hg log
1341 $ hg log
1326 changeset: 0:3903775176ed
1342 changeset: 0:3903775176ed
1327 tag: tip
1343 tag: tip
1328 user: test
1344 user: test
1329 date: Thu Jan 01 00:00:00 1970 +0000
1345 date: Thu Jan 01 00:00:00 1970 +0000
1330 summary: a
1346 summary: a
1331
1347
1332
1348
1333 Non-blocking hook
1349 Non-blocking hook
1334 -----------------
1350 -----------------
1335
1351
1336 $ cat << EOF >> .hg/hgrc
1352 $ cat << EOF >> .hg/hgrc
1337 > [hooks]
1353 > [hooks]
1338 > pretxnclose.testing=echo pre-txnclose hook called
1354 > pretxnclose.testing=echo pre-txnclose hook called
1339 > EOF
1355 > EOF
1340 $ touch b && hg commit -Aqm a
1356 $ touch b && hg commit -Aqm a
1341 transaction abort!
1357 transaction abort!
1342 rollback completed
1358 rollback completed
1343 abort: untrusted hook pretxnclose.testing not executed
1359 abort: untrusted hook pretxnclose.testing not executed
1344 (see 'hg help config.trusted')
1360 (see 'hg help config.trusted')
1345 [255]
1361 [255]
1346 $ hg log
1362 $ hg log
1347 changeset: 0:3903775176ed
1363 changeset: 0:3903775176ed
1348 tag: tip
1364 tag: tip
1349 user: test
1365 user: test
1350 date: Thu Jan 01 00:00:00 1970 +0000
1366 date: Thu Jan 01 00:00:00 1970 +0000
1351 summary: a
1367 summary: a
1352
1368
@@ -1,408 +1,410 b''
1 #require serve
1 #require serve
2
2
3 This test is a duplicate of 'test-http.t', feel free to factor out
3 This test is a duplicate of 'test-http.t', feel free to factor out
4 parts that are not bundle1/bundle2 specific.
4 parts that are not bundle1/bundle2 specific.
5
5
6 $ cat << EOF >> $HGRCPATH
6 $ cat << EOF >> $HGRCPATH
7 > [devel]
7 > [devel]
8 > # This test is dedicated to interaction through old bundle
8 > # This test is dedicated to interaction through old bundle
9 > legacy.exchange = bundle1
9 > legacy.exchange = bundle1
10 > EOF
10 > EOF
11
11
12 $ hg init test
12 $ hg init test
13 $ cd test
13 $ cd test
14 $ echo foo>foo
14 $ echo foo>foo
15 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
15 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
16 $ echo foo>foo.d/foo
16 $ echo foo>foo.d/foo
17 $ echo bar>foo.d/bAr.hg.d/BaR
17 $ echo bar>foo.d/bAr.hg.d/BaR
18 $ echo bar>foo.d/baR.d.hg/bAR
18 $ echo bar>foo.d/baR.d.hg/bAR
19 $ hg commit -A -m 1
19 $ hg commit -A -m 1
20 adding foo
20 adding foo
21 adding foo.d/bAr.hg.d/BaR
21 adding foo.d/bAr.hg.d/BaR
22 adding foo.d/baR.d.hg/bAR
22 adding foo.d/baR.d.hg/bAR
23 adding foo.d/foo
23 adding foo.d/foo
24 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
24 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
25 $ hg serve --config server.uncompressed=False -p $HGPORT1 -d --pid-file=../hg2.pid
25 $ hg serve --config server.uncompressed=False -p $HGPORT1 -d --pid-file=../hg2.pid
26
26
27 Test server address cannot be reused
27 Test server address cannot be reused
28
28
29 $ hg serve -p $HGPORT1 2>&1
29 $ hg serve -p $HGPORT1 2>&1
30 abort: cannot start server at 'localhost:$HGPORT1': $EADDRINUSE$
30 abort: cannot start server at 'localhost:$HGPORT1': $EADDRINUSE$
31 [255]
31 [255]
32
32
33 $ cd ..
33 $ cd ..
34 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
34 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
35
35
36 clone via stream
36 clone via stream
37
37
38 #if no-reposimplestore
38 #if no-reposimplestore
39 $ hg clone --stream http://localhost:$HGPORT/ copy 2>&1
39 $ hg clone --stream http://localhost:$HGPORT/ copy 2>&1
40 streaming all changes
40 streaming all changes
41 6 files to transfer, 606 bytes of data
41 6 files to transfer, 606 bytes of data
42 transferred * bytes in * seconds (*/sec) (glob)
42 transferred * bytes in * seconds (*/sec) (glob)
43 searching for changes
43 searching for changes
44 no changes found
44 no changes found
45 updating to branch default
45 updating to branch default
46 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
46 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
47 $ hg verify -R copy
47 $ hg verify -R copy
48 checking changesets
48 checking changesets
49 checking manifests
49 checking manifests
50 crosschecking files in changesets and manifests
50 crosschecking files in changesets and manifests
51 checking files
51 checking files
52 checked 1 changesets with 4 changes to 4 files
52 checked 1 changesets with 4 changes to 4 files
53 #endif
53 #endif
54
54
55 try to clone via stream, should use pull instead
55 try to clone via stream, should use pull instead
56
56
57 $ hg clone --stream http://localhost:$HGPORT1/ copy2
57 $ hg clone --stream http://localhost:$HGPORT1/ copy2
58 warning: stream clone requested but server has them disabled
58 warning: stream clone requested but server has them disabled
59 requesting all changes
59 requesting all changes
60 adding changesets
60 adding changesets
61 adding manifests
61 adding manifests
62 adding file changes
62 adding file changes
63 added 1 changesets with 4 changes to 4 files
63 added 1 changesets with 4 changes to 4 files
64 new changesets 8b6053c928fe
64 new changesets 8b6053c928fe
65 updating to branch default
65 updating to branch default
66 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
67
67
68 try to clone via stream but missing requirements, so should use pull instead
68 try to clone via stream but missing requirements, so should use pull instead
69
69
70 $ cat > $TESTTMP/removesupportedformat.py << EOF
70 $ cat > $TESTTMP/removesupportedformat.py << EOF
71 > from mercurial import localrepo
71 > from mercurial import localrepo
72 > def extsetup(ui):
72 > def extsetup(ui):
73 > localrepo.localrepository.supportedformats.remove(b'generaldelta')
73 > localrepo.localrepository.supportedformats.remove(b'generaldelta')
74 > EOF
74 > EOF
75
75
76 $ hg clone --config extensions.rsf=$TESTTMP/removesupportedformat.py --stream http://localhost:$HGPORT/ copy3
76 $ hg clone --config extensions.rsf=$TESTTMP/removesupportedformat.py --stream http://localhost:$HGPORT/ copy3
77 warning: stream clone requested but client is missing requirements: generaldelta
77 warning: stream clone requested but client is missing requirements: generaldelta
78 (see https://www.mercurial-scm.org/wiki/MissingRequirement for more information)
78 (see https://www.mercurial-scm.org/wiki/MissingRequirement for more information)
79 requesting all changes
79 requesting all changes
80 adding changesets
80 adding changesets
81 adding manifests
81 adding manifests
82 adding file changes
82 adding file changes
83 added 1 changesets with 4 changes to 4 files
83 added 1 changesets with 4 changes to 4 files
84 new changesets 8b6053c928fe
84 new changesets 8b6053c928fe
85 updating to branch default
85 updating to branch default
86 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
86 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
87
87
88 clone via pull
88 clone via pull
89
89
90 $ hg clone http://localhost:$HGPORT1/ copy-pull
90 $ hg clone http://localhost:$HGPORT1/ copy-pull
91 requesting all changes
91 requesting all changes
92 adding changesets
92 adding changesets
93 adding manifests
93 adding manifests
94 adding file changes
94 adding file changes
95 added 1 changesets with 4 changes to 4 files
95 added 1 changesets with 4 changes to 4 files
96 new changesets 8b6053c928fe
96 new changesets 8b6053c928fe
97 updating to branch default
97 updating to branch default
98 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 $ hg verify -R copy-pull
99 $ hg verify -R copy-pull
100 checking changesets
100 checking changesets
101 checking manifests
101 checking manifests
102 crosschecking files in changesets and manifests
102 crosschecking files in changesets and manifests
103 checking files
103 checking files
104 checked 1 changesets with 4 changes to 4 files
104 checked 1 changesets with 4 changes to 4 files
105 $ cd test
105 $ cd test
106 $ echo bar > bar
106 $ echo bar > bar
107 $ hg commit -A -d '1 0' -m 2
107 $ hg commit -A -d '1 0' -m 2
108 adding bar
108 adding bar
109 $ cd ..
109 $ cd ..
110
110
111 clone over http with --update
111 clone over http with --update
112
112
113 $ hg clone http://localhost:$HGPORT1/ updated --update 0
113 $ hg clone http://localhost:$HGPORT1/ updated --update 0
114 requesting all changes
114 requesting all changes
115 adding changesets
115 adding changesets
116 adding manifests
116 adding manifests
117 adding file changes
117 adding file changes
118 added 2 changesets with 5 changes to 5 files
118 added 2 changesets with 5 changes to 5 files
119 new changesets 8b6053c928fe:5fed3813f7f5
119 new changesets 8b6053c928fe:5fed3813f7f5
120 updating to branch default
120 updating to branch default
121 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 $ hg log -r . -R updated
122 $ hg log -r . -R updated
123 changeset: 0:8b6053c928fe
123 changeset: 0:8b6053c928fe
124 user: test
124 user: test
125 date: Thu Jan 01 00:00:00 1970 +0000
125 date: Thu Jan 01 00:00:00 1970 +0000
126 summary: 1
126 summary: 1
127
127
128 $ rm -rf updated
128 $ rm -rf updated
129
129
130 incoming via HTTP
130 incoming via HTTP
131
131
132 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
132 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
133 adding changesets
133 adding changesets
134 adding manifests
134 adding manifests
135 adding file changes
135 adding file changes
136 added 1 changesets with 4 changes to 4 files
136 added 1 changesets with 4 changes to 4 files
137 new changesets 8b6053c928fe
137 new changesets 8b6053c928fe
138 updating to branch default
138 updating to branch default
139 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
139 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
140 $ cd partial
140 $ cd partial
141 $ touch LOCAL
141 $ touch LOCAL
142 $ hg ci -qAm LOCAL
142 $ hg ci -qAm LOCAL
143 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
143 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
144 comparing with http://localhost:$HGPORT1/
144 comparing with http://localhost:$HGPORT1/
145 searching for changes
145 searching for changes
146 2
146 2
147 $ cd ..
147 $ cd ..
148
148
149 pull
149 pull
150
150
151 $ cd copy-pull
151 $ cd copy-pull
152 $ cat >> .hg/hgrc <<EOF
152 $ cat >> .hg/hgrc <<EOF
153 > [hooks]
153 > [hooks]
154 > changegroup = sh -c "printenv.py --line changegroup"
154 > changegroup = sh -c "printenv.py --line changegroup"
155 > EOF
155 > EOF
156 $ hg pull
156 $ hg pull
157 pulling from http://localhost:$HGPORT1/
157 pulling from http://localhost:$HGPORT1/
158 searching for changes
158 searching for changes
159 adding changesets
159 adding changesets
160 adding manifests
160 adding manifests
161 adding file changes
161 adding file changes
162 added 1 changesets with 1 changes to 1 files
162 added 1 changesets with 1 changes to 1 files
163 new changesets 5fed3813f7f5
163 new changesets 5fed3813f7f5
164 changegroup hook: HG_HOOKNAME=changegroup
164 changegroup hook: HG_HOOKNAME=changegroup
165 HG_HOOKTYPE=changegroup
165 HG_HOOKTYPE=changegroup
166 HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
166 HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
167 HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
167 HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
168 HG_SOURCE=pull
168 HG_SOURCE=pull
169 HG_TXNID=TXN:$ID$
169 HG_TXNID=TXN:$ID$
170 HG_TXNNAME=pull
171 http://localhost:$HGPORT1/
170 HG_URL=http://localhost:$HGPORT1/
172 HG_URL=http://localhost:$HGPORT1/
171
173
172 (run 'hg update' to get a working copy)
174 (run 'hg update' to get a working copy)
173 $ cd ..
175 $ cd ..
174
176
175 clone from invalid URL
177 clone from invalid URL
176
178
177 $ hg clone http://localhost:$HGPORT/bad
179 $ hg clone http://localhost:$HGPORT/bad
178 abort: HTTP Error 404: Not Found
180 abort: HTTP Error 404: Not Found
179 [255]
181 [255]
180
182
181 test http authentication
183 test http authentication
182 + use the same server to test server side streaming preference
184 + use the same server to test server side streaming preference
183
185
184 $ cd test
186 $ cd test
185
187
186 $ hg serve --config extensions.x=$TESTDIR/httpserverauth.py -p $HGPORT2 -d \
188 $ hg serve --config extensions.x=$TESTDIR/httpserverauth.py -p $HGPORT2 -d \
187 > --pid-file=pid --config server.preferuncompressed=True \
189 > --pid-file=pid --config server.preferuncompressed=True \
188 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
190 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
189 $ cat pid >> $DAEMON_PIDS
191 $ cat pid >> $DAEMON_PIDS
190
192
191 $ cat << EOF > get_pass.py
193 $ cat << EOF > get_pass.py
192 > import getpass
194 > import getpass
193 > def newgetpass(arg):
195 > def newgetpass(arg):
194 > return "pass"
196 > return "pass"
195 > getpass.getpass = newgetpass
197 > getpass.getpass = newgetpass
196 > EOF
198 > EOF
197
199
198 $ hg id http://localhost:$HGPORT2/
200 $ hg id http://localhost:$HGPORT2/
199 abort: http authorization required for http://localhost:$HGPORT2/
201 abort: http authorization required for http://localhost:$HGPORT2/
200 [255]
202 [255]
201 $ hg id http://localhost:$HGPORT2/
203 $ hg id http://localhost:$HGPORT2/
202 abort: http authorization required for http://localhost:$HGPORT2/
204 abort: http authorization required for http://localhost:$HGPORT2/
203 [255]
205 [255]
204 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
206 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
205 http authorization required for http://localhost:$HGPORT2/
207 http authorization required for http://localhost:$HGPORT2/
206 realm: mercurial
208 realm: mercurial
207 user: user
209 user: user
208 password: 5fed3813f7f5
210 password: 5fed3813f7f5
209 $ hg id http://user:pass@localhost:$HGPORT2/
211 $ hg id http://user:pass@localhost:$HGPORT2/
210 5fed3813f7f5
212 5fed3813f7f5
211 $ echo '[auth]' >> .hg/hgrc
213 $ echo '[auth]' >> .hg/hgrc
212 $ echo 'l.schemes=http' >> .hg/hgrc
214 $ echo 'l.schemes=http' >> .hg/hgrc
213 $ echo 'l.prefix=lo' >> .hg/hgrc
215 $ echo 'l.prefix=lo' >> .hg/hgrc
214 $ echo 'l.username=user' >> .hg/hgrc
216 $ echo 'l.username=user' >> .hg/hgrc
215 $ echo 'l.password=pass' >> .hg/hgrc
217 $ echo 'l.password=pass' >> .hg/hgrc
216 $ hg id http://localhost:$HGPORT2/
218 $ hg id http://localhost:$HGPORT2/
217 5fed3813f7f5
219 5fed3813f7f5
218 $ hg id http://localhost:$HGPORT2/
220 $ hg id http://localhost:$HGPORT2/
219 5fed3813f7f5
221 5fed3813f7f5
220 $ hg id http://user@localhost:$HGPORT2/
222 $ hg id http://user@localhost:$HGPORT2/
221 5fed3813f7f5
223 5fed3813f7f5
222
224
223 #if no-reposimplestore
225 #if no-reposimplestore
224 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
226 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
225 streaming all changes
227 streaming all changes
226 7 files to transfer, 916 bytes of data
228 7 files to transfer, 916 bytes of data
227 transferred * bytes in * seconds (*/sec) (glob)
229 transferred * bytes in * seconds (*/sec) (glob)
228 searching for changes
230 searching for changes
229 no changes found
231 no changes found
230 updating to branch default
232 updating to branch default
231 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
233 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
232 #endif
234 #endif
233
235
234 --pull should override server's preferuncompressed
236 --pull should override server's preferuncompressed
235
237
236 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
238 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
237 requesting all changes
239 requesting all changes
238 adding changesets
240 adding changesets
239 adding manifests
241 adding manifests
240 adding file changes
242 adding file changes
241 added 2 changesets with 5 changes to 5 files
243 added 2 changesets with 5 changes to 5 files
242 new changesets 8b6053c928fe:5fed3813f7f5
244 new changesets 8b6053c928fe:5fed3813f7f5
243 updating to branch default
245 updating to branch default
244 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
246 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
245
247
246 $ hg id http://user2@localhost:$HGPORT2/
248 $ hg id http://user2@localhost:$HGPORT2/
247 abort: http authorization required for http://localhost:$HGPORT2/
249 abort: http authorization required for http://localhost:$HGPORT2/
248 [255]
250 [255]
249 $ hg id http://user:pass2@localhost:$HGPORT2/
251 $ hg id http://user:pass2@localhost:$HGPORT2/
250 abort: HTTP Error 403: no
252 abort: HTTP Error 403: no
251 [255]
253 [255]
252
254
253 $ hg -R dest-pull tag -r tip top
255 $ hg -R dest-pull tag -r tip top
254 $ hg -R dest-pull push http://user:pass@localhost:$HGPORT2/
256 $ hg -R dest-pull push http://user:pass@localhost:$HGPORT2/
255 pushing to http://user:***@localhost:$HGPORT2/
257 pushing to http://user:***@localhost:$HGPORT2/
256 searching for changes
258 searching for changes
257 remote: adding changesets
259 remote: adding changesets
258 remote: adding manifests
260 remote: adding manifests
259 remote: adding file changes
261 remote: adding file changes
260 remote: added 1 changesets with 1 changes to 1 files
262 remote: added 1 changesets with 1 changes to 1 files
261 $ hg rollback -q
263 $ hg rollback -q
262
264
263 $ sed 's/.*] "/"/' < ../access.log
265 $ sed 's/.*] "/"/' < ../access.log
264 "GET /?cmd=capabilities HTTP/1.1" 401 -
266 "GET /?cmd=capabilities HTTP/1.1" 401 -
265 "GET /?cmd=capabilities HTTP/1.1" 401 -
267 "GET /?cmd=capabilities HTTP/1.1" 401 -
266 "GET /?cmd=capabilities HTTP/1.1" 401 -
268 "GET /?cmd=capabilities HTTP/1.1" 401 -
267 "GET /?cmd=capabilities HTTP/1.1" 200 -
269 "GET /?cmd=capabilities HTTP/1.1" 200 -
268 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
270 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
269 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
271 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
270 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
272 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
271 "GET /?cmd=capabilities HTTP/1.1" 401 -
273 "GET /?cmd=capabilities HTTP/1.1" 401 -
272 "GET /?cmd=capabilities HTTP/1.1" 200 -
274 "GET /?cmd=capabilities HTTP/1.1" 200 -
273 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
275 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
274 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
276 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
275 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
277 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
276 "GET /?cmd=capabilities HTTP/1.1" 401 -
278 "GET /?cmd=capabilities HTTP/1.1" 401 -
277 "GET /?cmd=capabilities HTTP/1.1" 200 -
279 "GET /?cmd=capabilities HTTP/1.1" 200 -
278 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
280 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
279 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
281 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
280 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
282 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
281 "GET /?cmd=capabilities HTTP/1.1" 401 -
283 "GET /?cmd=capabilities HTTP/1.1" 401 -
282 "GET /?cmd=capabilities HTTP/1.1" 200 -
284 "GET /?cmd=capabilities HTTP/1.1" 200 -
283 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
285 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
284 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
286 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
285 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
287 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
286 "GET /?cmd=capabilities HTTP/1.1" 401 -
288 "GET /?cmd=capabilities HTTP/1.1" 401 -
287 "GET /?cmd=capabilities HTTP/1.1" 200 -
289 "GET /?cmd=capabilities HTTP/1.1" 200 -
288 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
290 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
289 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
291 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
290 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
292 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
291 "GET /?cmd=capabilities HTTP/1.1" 401 - (no-reposimplestore !)
293 "GET /?cmd=capabilities HTTP/1.1" 401 - (no-reposimplestore !)
292 "GET /?cmd=capabilities HTTP/1.1" 200 - (no-reposimplestore !)
294 "GET /?cmd=capabilities HTTP/1.1" 200 - (no-reposimplestore !)
293 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
295 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
294 "GET /?cmd=stream_out HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
296 "GET /?cmd=stream_out HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
295 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
297 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
296 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
298 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
297 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
299 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
298 "GET /?cmd=capabilities HTTP/1.1" 401 - (no-reposimplestore !)
300 "GET /?cmd=capabilities HTTP/1.1" 401 - (no-reposimplestore !)
299 "GET /?cmd=capabilities HTTP/1.1" 200 - (no-reposimplestore !)
301 "GET /?cmd=capabilities HTTP/1.1" 200 - (no-reposimplestore !)
300 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
302 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
301 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
303 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
302 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
304 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
303 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
305 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
304 "GET /?cmd=capabilities HTTP/1.1" 401 -
306 "GET /?cmd=capabilities HTTP/1.1" 401 -
305 "GET /?cmd=capabilities HTTP/1.1" 401 -
307 "GET /?cmd=capabilities HTTP/1.1" 401 -
306 "GET /?cmd=capabilities HTTP/1.1" 403 -
308 "GET /?cmd=capabilities HTTP/1.1" 403 -
307 "GET /?cmd=capabilities HTTP/1.1" 401 -
309 "GET /?cmd=capabilities HTTP/1.1" 401 -
308 "GET /?cmd=capabilities HTTP/1.1" 200 -
310 "GET /?cmd=capabilities HTTP/1.1" 200 -
309 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
311 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
310 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
312 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
311 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
313 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
312 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
314 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
313 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
315 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
314 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=686173686564+5eb5abfefeea63c80dd7553bcc3783f37e0c5524* (glob)
316 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=686173686564+5eb5abfefeea63c80dd7553bcc3783f37e0c5524* (glob)
315 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
317 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
316
318
317 $ cd ..
319 $ cd ..
318
320
319 clone of serve with repo in root and unserved subrepo (issue2970)
321 clone of serve with repo in root and unserved subrepo (issue2970)
320
322
321 $ hg --cwd test init sub
323 $ hg --cwd test init sub
322 $ echo empty > test/sub/empty
324 $ echo empty > test/sub/empty
323 $ hg --cwd test/sub add empty
325 $ hg --cwd test/sub add empty
324 $ hg --cwd test/sub commit -qm 'add empty'
326 $ hg --cwd test/sub commit -qm 'add empty'
325 $ hg --cwd test/sub tag -r 0 something
327 $ hg --cwd test/sub tag -r 0 something
326 $ echo sub = sub > test/.hgsub
328 $ echo sub = sub > test/.hgsub
327 $ hg --cwd test add .hgsub
329 $ hg --cwd test add .hgsub
328 $ hg --cwd test commit -qm 'add subrepo'
330 $ hg --cwd test commit -qm 'add subrepo'
329 $ hg clone http://localhost:$HGPORT noslash-clone
331 $ hg clone http://localhost:$HGPORT noslash-clone
330 requesting all changes
332 requesting all changes
331 adding changesets
333 adding changesets
332 adding manifests
334 adding manifests
333 adding file changes
335 adding file changes
334 added 3 changesets with 7 changes to 7 files
336 added 3 changesets with 7 changes to 7 files
335 new changesets 8b6053c928fe:56f9bc90cce6
337 new changesets 8b6053c928fe:56f9bc90cce6
336 updating to branch default
338 updating to branch default
337 cloning subrepo sub from http://localhost:$HGPORT/sub
339 cloning subrepo sub from http://localhost:$HGPORT/sub
338 abort: HTTP Error 404: Not Found
340 abort: HTTP Error 404: Not Found
339 [255]
341 [255]
340 $ hg clone http://localhost:$HGPORT/ slash-clone
342 $ hg clone http://localhost:$HGPORT/ slash-clone
341 requesting all changes
343 requesting all changes
342 adding changesets
344 adding changesets
343 adding manifests
345 adding manifests
344 adding file changes
346 adding file changes
345 added 3 changesets with 7 changes to 7 files
347 added 3 changesets with 7 changes to 7 files
346 new changesets 8b6053c928fe:56f9bc90cce6
348 new changesets 8b6053c928fe:56f9bc90cce6
347 updating to branch default
349 updating to branch default
348 cloning subrepo sub from http://localhost:$HGPORT/sub
350 cloning subrepo sub from http://localhost:$HGPORT/sub
349 abort: HTTP Error 404: Not Found
351 abort: HTTP Error 404: Not Found
350 [255]
352 [255]
351
353
352 check error log
354 check error log
353
355
354 $ cat error.log
356 $ cat error.log
355
357
356 Check error reporting while pulling/cloning
358 Check error reporting while pulling/cloning
357
359
358 $ $RUNTESTDIR/killdaemons.py
360 $ $RUNTESTDIR/killdaemons.py
359 $ hg serve -R test -p $HGPORT -d --pid-file=hg3.pid -E error.log --config extensions.crash=${TESTDIR}/crashgetbundler.py
361 $ hg serve -R test -p $HGPORT -d --pid-file=hg3.pid -E error.log --config extensions.crash=${TESTDIR}/crashgetbundler.py
360 $ cat hg3.pid >> $DAEMON_PIDS
362 $ cat hg3.pid >> $DAEMON_PIDS
361 $ hg clone http://localhost:$HGPORT/ abort-clone
363 $ hg clone http://localhost:$HGPORT/ abort-clone
362 requesting all changes
364 requesting all changes
363 abort: remote error:
365 abort: remote error:
364 this is an exercise
366 this is an exercise
365 [255]
367 [255]
366 $ cat error.log
368 $ cat error.log
367
369
368 disable pull-based clones
370 disable pull-based clones
369
371
370 $ hg serve -R test -p $HGPORT1 -d --pid-file=hg4.pid -E error.log --config server.disablefullbundle=True
372 $ hg serve -R test -p $HGPORT1 -d --pid-file=hg4.pid -E error.log --config server.disablefullbundle=True
371 $ cat hg4.pid >> $DAEMON_PIDS
373 $ cat hg4.pid >> $DAEMON_PIDS
372 $ hg clone http://localhost:$HGPORT1/ disable-pull-clone
374 $ hg clone http://localhost:$HGPORT1/ disable-pull-clone
373 requesting all changes
375 requesting all changes
374 abort: remote error:
376 abort: remote error:
375 server has pull-based clones disabled
377 server has pull-based clones disabled
376 [255]
378 [255]
377
379
378 #if no-reposimplestore
380 #if no-reposimplestore
379 ... but keep stream clones working
381 ... but keep stream clones working
380
382
381 $ hg clone --stream --noupdate http://localhost:$HGPORT1/ test-stream-clone
383 $ hg clone --stream --noupdate http://localhost:$HGPORT1/ test-stream-clone
382 streaming all changes
384 streaming all changes
383 * files to transfer, * of data (glob)
385 * files to transfer, * of data (glob)
384 transferred * in * seconds (* KB/sec) (glob)
386 transferred * in * seconds (* KB/sec) (glob)
385 searching for changes
387 searching for changes
386 no changes found
388 no changes found
387 #endif
389 #endif
388
390
389 ... and also keep partial clones and pulls working
391 ... and also keep partial clones and pulls working
390 $ hg clone http://localhost:$HGPORT1 --rev 0 test-partial-clone
392 $ hg clone http://localhost:$HGPORT1 --rev 0 test-partial-clone
391 adding changesets
393 adding changesets
392 adding manifests
394 adding manifests
393 adding file changes
395 adding file changes
394 added 1 changesets with 4 changes to 4 files
396 added 1 changesets with 4 changes to 4 files
395 new changesets 8b6053c928fe
397 new changesets 8b6053c928fe
396 updating to branch default
398 updating to branch default
397 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
398 $ hg pull -R test-partial-clone
400 $ hg pull -R test-partial-clone
399 pulling from http://localhost:$HGPORT1/
401 pulling from http://localhost:$HGPORT1/
400 searching for changes
402 searching for changes
401 adding changesets
403 adding changesets
402 adding manifests
404 adding manifests
403 adding file changes
405 adding file changes
404 added 2 changesets with 3 changes to 3 files
406 added 2 changesets with 3 changes to 3 files
405 new changesets 5fed3813f7f5:56f9bc90cce6
407 new changesets 5fed3813f7f5:56f9bc90cce6
406 (run 'hg update' to get a working copy)
408 (run 'hg update' to get a working copy)
407
409
408 $ cat error.log
410 $ cat error.log
@@ -1,581 +1,583 b''
1 #require serve
1 #require serve
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo foo>foo
5 $ echo foo>foo
6 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
6 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
7 $ echo foo>foo.d/foo
7 $ echo foo>foo.d/foo
8 $ echo bar>foo.d/bAr.hg.d/BaR
8 $ echo bar>foo.d/bAr.hg.d/BaR
9 $ echo bar>foo.d/baR.d.hg/bAR
9 $ echo bar>foo.d/baR.d.hg/bAR
10 $ hg commit -A -m 1
10 $ hg commit -A -m 1
11 adding foo
11 adding foo
12 adding foo.d/bAr.hg.d/BaR
12 adding foo.d/bAr.hg.d/BaR
13 adding foo.d/baR.d.hg/bAR
13 adding foo.d/baR.d.hg/bAR
14 adding foo.d/foo
14 adding foo.d/foo
15 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
15 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
16 $ hg serve --config server.uncompressed=False -p $HGPORT1 -d --pid-file=../hg2.pid
16 $ hg serve --config server.uncompressed=False -p $HGPORT1 -d --pid-file=../hg2.pid
17
17
18 Test server address cannot be reused
18 Test server address cannot be reused
19
19
20 $ hg serve -p $HGPORT1 2>&1
20 $ hg serve -p $HGPORT1 2>&1
21 abort: cannot start server at 'localhost:$HGPORT1': $EADDRINUSE$
21 abort: cannot start server at 'localhost:$HGPORT1': $EADDRINUSE$
22 [255]
22 [255]
23
23
24 $ cd ..
24 $ cd ..
25 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
25 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
26
26
27 clone via stream
27 clone via stream
28
28
29 #if no-reposimplestore
29 #if no-reposimplestore
30 $ hg clone --stream http://localhost:$HGPORT/ copy 2>&1
30 $ hg clone --stream http://localhost:$HGPORT/ copy 2>&1
31 streaming all changes
31 streaming all changes
32 9 files to transfer, 715 bytes of data
32 9 files to transfer, 715 bytes of data
33 transferred * bytes in * seconds (*/sec) (glob)
33 transferred * bytes in * seconds (*/sec) (glob)
34 updating to branch default
34 updating to branch default
35 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
35 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
36 $ hg verify -R copy
36 $ hg verify -R copy
37 checking changesets
37 checking changesets
38 checking manifests
38 checking manifests
39 crosschecking files in changesets and manifests
39 crosschecking files in changesets and manifests
40 checking files
40 checking files
41 checked 1 changesets with 4 changes to 4 files
41 checked 1 changesets with 4 changes to 4 files
42 #endif
42 #endif
43
43
44 try to clone via stream, should use pull instead
44 try to clone via stream, should use pull instead
45
45
46 $ hg clone --stream http://localhost:$HGPORT1/ copy2
46 $ hg clone --stream http://localhost:$HGPORT1/ copy2
47 warning: stream clone requested but server has them disabled
47 warning: stream clone requested but server has them disabled
48 requesting all changes
48 requesting all changes
49 adding changesets
49 adding changesets
50 adding manifests
50 adding manifests
51 adding file changes
51 adding file changes
52 added 1 changesets with 4 changes to 4 files
52 added 1 changesets with 4 changes to 4 files
53 new changesets 8b6053c928fe
53 new changesets 8b6053c928fe
54 updating to branch default
54 updating to branch default
55 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
55 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
56
56
57 try to clone via stream but missing requirements, so should use pull instead
57 try to clone via stream but missing requirements, so should use pull instead
58
58
59 $ cat > $TESTTMP/removesupportedformat.py << EOF
59 $ cat > $TESTTMP/removesupportedformat.py << EOF
60 > from mercurial import localrepo
60 > from mercurial import localrepo
61 > def extsetup(ui):
61 > def extsetup(ui):
62 > localrepo.localrepository.supportedformats.remove(b'generaldelta')
62 > localrepo.localrepository.supportedformats.remove(b'generaldelta')
63 > EOF
63 > EOF
64
64
65 $ hg clone --config extensions.rsf=$TESTTMP/removesupportedformat.py --stream http://localhost:$HGPORT/ copy3
65 $ hg clone --config extensions.rsf=$TESTTMP/removesupportedformat.py --stream http://localhost:$HGPORT/ copy3
66 warning: stream clone requested but client is missing requirements: generaldelta
66 warning: stream clone requested but client is missing requirements: generaldelta
67 (see https://www.mercurial-scm.org/wiki/MissingRequirement for more information)
67 (see https://www.mercurial-scm.org/wiki/MissingRequirement for more information)
68 requesting all changes
68 requesting all changes
69 adding changesets
69 adding changesets
70 adding manifests
70 adding manifests
71 adding file changes
71 adding file changes
72 added 1 changesets with 4 changes to 4 files
72 added 1 changesets with 4 changes to 4 files
73 new changesets 8b6053c928fe
73 new changesets 8b6053c928fe
74 updating to branch default
74 updating to branch default
75 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
75 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
76
76
77 clone via pull
77 clone via pull
78
78
79 $ hg clone http://localhost:$HGPORT1/ copy-pull
79 $ hg clone http://localhost:$HGPORT1/ copy-pull
80 requesting all changes
80 requesting all changes
81 adding changesets
81 adding changesets
82 adding manifests
82 adding manifests
83 adding file changes
83 adding file changes
84 added 1 changesets with 4 changes to 4 files
84 added 1 changesets with 4 changes to 4 files
85 new changesets 8b6053c928fe
85 new changesets 8b6053c928fe
86 updating to branch default
86 updating to branch default
87 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 $ hg verify -R copy-pull
88 $ hg verify -R copy-pull
89 checking changesets
89 checking changesets
90 checking manifests
90 checking manifests
91 crosschecking files in changesets and manifests
91 crosschecking files in changesets and manifests
92 checking files
92 checking files
93 checked 1 changesets with 4 changes to 4 files
93 checked 1 changesets with 4 changes to 4 files
94 $ cd test
94 $ cd test
95 $ echo bar > bar
95 $ echo bar > bar
96 $ hg commit -A -d '1 0' -m 2
96 $ hg commit -A -d '1 0' -m 2
97 adding bar
97 adding bar
98 $ cd ..
98 $ cd ..
99
99
100 clone over http with --update
100 clone over http with --update
101
101
102 $ hg clone http://localhost:$HGPORT1/ updated --update 0
102 $ hg clone http://localhost:$HGPORT1/ updated --update 0
103 requesting all changes
103 requesting all changes
104 adding changesets
104 adding changesets
105 adding manifests
105 adding manifests
106 adding file changes
106 adding file changes
107 added 2 changesets with 5 changes to 5 files
107 added 2 changesets with 5 changes to 5 files
108 new changesets 8b6053c928fe:5fed3813f7f5
108 new changesets 8b6053c928fe:5fed3813f7f5
109 updating to branch default
109 updating to branch default
110 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
111 $ hg log -r . -R updated
111 $ hg log -r . -R updated
112 changeset: 0:8b6053c928fe
112 changeset: 0:8b6053c928fe
113 user: test
113 user: test
114 date: Thu Jan 01 00:00:00 1970 +0000
114 date: Thu Jan 01 00:00:00 1970 +0000
115 summary: 1
115 summary: 1
116
116
117 $ rm -rf updated
117 $ rm -rf updated
118
118
119 incoming via HTTP
119 incoming via HTTP
120
120
121 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
121 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
122 adding changesets
122 adding changesets
123 adding manifests
123 adding manifests
124 adding file changes
124 adding file changes
125 added 1 changesets with 4 changes to 4 files
125 added 1 changesets with 4 changes to 4 files
126 new changesets 8b6053c928fe
126 new changesets 8b6053c928fe
127 updating to branch default
127 updating to branch default
128 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
128 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
129 $ cd partial
129 $ cd partial
130 $ touch LOCAL
130 $ touch LOCAL
131 $ hg ci -qAm LOCAL
131 $ hg ci -qAm LOCAL
132 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
132 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
133 comparing with http://localhost:$HGPORT1/
133 comparing with http://localhost:$HGPORT1/
134 searching for changes
134 searching for changes
135 2
135 2
136 $ cd ..
136 $ cd ..
137
137
138 pull
138 pull
139
139
140 $ cd copy-pull
140 $ cd copy-pull
141 $ cat >> .hg/hgrc <<EOF
141 $ cat >> .hg/hgrc <<EOF
142 > [hooks]
142 > [hooks]
143 > changegroup = sh -c "printenv.py --line changegroup"
143 > changegroup = sh -c "printenv.py --line changegroup"
144 > EOF
144 > EOF
145 $ hg pull
145 $ hg pull
146 pulling from http://localhost:$HGPORT1/
146 pulling from http://localhost:$HGPORT1/
147 searching for changes
147 searching for changes
148 adding changesets
148 adding changesets
149 adding manifests
149 adding manifests
150 adding file changes
150 adding file changes
151 added 1 changesets with 1 changes to 1 files
151 added 1 changesets with 1 changes to 1 files
152 new changesets 5fed3813f7f5
152 new changesets 5fed3813f7f5
153 changegroup hook: HG_HOOKNAME=changegroup
153 changegroup hook: HG_HOOKNAME=changegroup
154 HG_HOOKTYPE=changegroup
154 HG_HOOKTYPE=changegroup
155 HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
155 HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
156 HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
156 HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
157 HG_SOURCE=pull
157 HG_SOURCE=pull
158 HG_TXNID=TXN:$ID$
158 HG_TXNID=TXN:$ID$
159 HG_TXNNAME=pull
160 http://localhost:$HGPORT1/
159 HG_URL=http://localhost:$HGPORT1/
161 HG_URL=http://localhost:$HGPORT1/
160
162
161 (run 'hg update' to get a working copy)
163 (run 'hg update' to get a working copy)
162 $ cd ..
164 $ cd ..
163
165
164 clone from invalid URL
166 clone from invalid URL
165
167
166 $ hg clone http://localhost:$HGPORT/bad
168 $ hg clone http://localhost:$HGPORT/bad
167 abort: HTTP Error 404: Not Found
169 abort: HTTP Error 404: Not Found
168 [255]
170 [255]
169
171
170 test http authentication
172 test http authentication
171 + use the same server to test server side streaming preference
173 + use the same server to test server side streaming preference
172
174
173 $ cd test
175 $ cd test
174
176
175 $ hg serve --config extensions.x=$TESTDIR/httpserverauth.py -p $HGPORT2 -d \
177 $ hg serve --config extensions.x=$TESTDIR/httpserverauth.py -p $HGPORT2 -d \
176 > --pid-file=pid --config server.preferuncompressed=True -E ../errors2.log \
178 > --pid-file=pid --config server.preferuncompressed=True -E ../errors2.log \
177 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
179 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
178 $ cat pid >> $DAEMON_PIDS
180 $ cat pid >> $DAEMON_PIDS
179
181
180 $ cat << EOF > get_pass.py
182 $ cat << EOF > get_pass.py
181 > import getpass
183 > import getpass
182 > def newgetpass(arg):
184 > def newgetpass(arg):
183 > return "pass"
185 > return "pass"
184 > getpass.getpass = newgetpass
186 > getpass.getpass = newgetpass
185 > EOF
187 > EOF
186
188
187 $ hg id http://localhost:$HGPORT2/
189 $ hg id http://localhost:$HGPORT2/
188 abort: http authorization required for http://localhost:$HGPORT2/
190 abort: http authorization required for http://localhost:$HGPORT2/
189 [255]
191 [255]
190 $ hg id http://localhost:$HGPORT2/
192 $ hg id http://localhost:$HGPORT2/
191 abort: http authorization required for http://localhost:$HGPORT2/
193 abort: http authorization required for http://localhost:$HGPORT2/
192 [255]
194 [255]
193 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
195 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
194 http authorization required for http://localhost:$HGPORT2/
196 http authorization required for http://localhost:$HGPORT2/
195 realm: mercurial
197 realm: mercurial
196 user: user
198 user: user
197 password: 5fed3813f7f5
199 password: 5fed3813f7f5
198 $ hg id http://user:pass@localhost:$HGPORT2/
200 $ hg id http://user:pass@localhost:$HGPORT2/
199 5fed3813f7f5
201 5fed3813f7f5
200 $ echo '[auth]' >> .hg/hgrc
202 $ echo '[auth]' >> .hg/hgrc
201 $ echo 'l.schemes=http' >> .hg/hgrc
203 $ echo 'l.schemes=http' >> .hg/hgrc
202 $ echo 'l.prefix=lo' >> .hg/hgrc
204 $ echo 'l.prefix=lo' >> .hg/hgrc
203 $ echo 'l.username=user' >> .hg/hgrc
205 $ echo 'l.username=user' >> .hg/hgrc
204 $ echo 'l.password=pass' >> .hg/hgrc
206 $ echo 'l.password=pass' >> .hg/hgrc
205 $ hg id http://localhost:$HGPORT2/
207 $ hg id http://localhost:$HGPORT2/
206 5fed3813f7f5
208 5fed3813f7f5
207 $ hg id http://localhost:$HGPORT2/
209 $ hg id http://localhost:$HGPORT2/
208 5fed3813f7f5
210 5fed3813f7f5
209 $ hg id http://user@localhost:$HGPORT2/
211 $ hg id http://user@localhost:$HGPORT2/
210 5fed3813f7f5
212 5fed3813f7f5
211
213
212 $ cat > use_digests.py << EOF
214 $ cat > use_digests.py << EOF
213 > from mercurial import (
215 > from mercurial import (
214 > exthelper,
216 > exthelper,
215 > url,
217 > url,
216 > )
218 > )
217 >
219 >
218 > eh = exthelper.exthelper()
220 > eh = exthelper.exthelper()
219 > uisetup = eh.finaluisetup
221 > uisetup = eh.finaluisetup
220 >
222 >
221 > @eh.wrapfunction(url, 'opener')
223 > @eh.wrapfunction(url, 'opener')
222 > def urlopener(orig, *args, **kwargs):
224 > def urlopener(orig, *args, **kwargs):
223 > opener = orig(*args, **kwargs)
225 > opener = orig(*args, **kwargs)
224 > opener.addheaders.append((r'X-HgTest-AuthType', r'Digest'))
226 > opener.addheaders.append((r'X-HgTest-AuthType', r'Digest'))
225 > return opener
227 > return opener
226 > EOF
228 > EOF
227
229
228 $ hg id http://localhost:$HGPORT2/ --config extensions.x=use_digests.py
230 $ hg id http://localhost:$HGPORT2/ --config extensions.x=use_digests.py
229 5fed3813f7f5
231 5fed3813f7f5
230
232
231 #if no-reposimplestore
233 #if no-reposimplestore
232 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
234 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
233 streaming all changes
235 streaming all changes
234 10 files to transfer, 1.01 KB of data
236 10 files to transfer, 1.01 KB of data
235 transferred * KB in * seconds (*/sec) (glob)
237 transferred * KB in * seconds (*/sec) (glob)
236 updating to branch default
238 updating to branch default
237 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
239 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
238 #endif
240 #endif
239
241
240 --pull should override server's preferuncompressed
242 --pull should override server's preferuncompressed
241 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
243 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
242 requesting all changes
244 requesting all changes
243 adding changesets
245 adding changesets
244 adding manifests
246 adding manifests
245 adding file changes
247 adding file changes
246 added 2 changesets with 5 changes to 5 files
248 added 2 changesets with 5 changes to 5 files
247 new changesets 8b6053c928fe:5fed3813f7f5
249 new changesets 8b6053c928fe:5fed3813f7f5
248 updating to branch default
250 updating to branch default
249 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
251 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
250
252
251 $ hg id http://user2@localhost:$HGPORT2/
253 $ hg id http://user2@localhost:$HGPORT2/
252 abort: http authorization required for http://localhost:$HGPORT2/
254 abort: http authorization required for http://localhost:$HGPORT2/
253 [255]
255 [255]
254 $ hg id http://user:pass2@localhost:$HGPORT2/
256 $ hg id http://user:pass2@localhost:$HGPORT2/
255 abort: HTTP Error 403: no
257 abort: HTTP Error 403: no
256 [255]
258 [255]
257
259
258 $ hg -R dest-pull tag -r tip top
260 $ hg -R dest-pull tag -r tip top
259 $ hg -R dest-pull push http://user:pass@localhost:$HGPORT2/
261 $ hg -R dest-pull push http://user:pass@localhost:$HGPORT2/
260 pushing to http://user:***@localhost:$HGPORT2/
262 pushing to http://user:***@localhost:$HGPORT2/
261 searching for changes
263 searching for changes
262 remote: adding changesets
264 remote: adding changesets
263 remote: adding manifests
265 remote: adding manifests
264 remote: adding file changes
266 remote: adding file changes
265 remote: added 1 changesets with 1 changes to 1 files
267 remote: added 1 changesets with 1 changes to 1 files
266 $ hg rollback -q
268 $ hg rollback -q
267 $ hg -R dest-pull push http://user:pass@localhost:$HGPORT2/ --debug --config devel.debug.peer-request=yes
269 $ hg -R dest-pull push http://user:pass@localhost:$HGPORT2/ --debug --config devel.debug.peer-request=yes
268 pushing to http://user:***@localhost:$HGPORT2/
270 pushing to http://user:***@localhost:$HGPORT2/
269 using http://localhost:$HGPORT2/
271 using http://localhost:$HGPORT2/
270 http auth: user user, password ****
272 http auth: user user, password ****
271 sending capabilities command
273 sending capabilities command
272 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=capabilities
274 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=capabilities
273 http auth: user user, password ****
275 http auth: user user, password ****
274 devel-peer-request: finished in *.???? seconds (200) (glob)
276 devel-peer-request: finished in *.???? seconds (200) (glob)
275 query 1; heads
277 query 1; heads
276 devel-peer-request: batched-content
278 devel-peer-request: batched-content
277 devel-peer-request: - heads (0 arguments)
279 devel-peer-request: - heads (0 arguments)
278 devel-peer-request: - known (1 arguments)
280 devel-peer-request: - known (1 arguments)
279 sending batch command
281 sending batch command
280 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=batch
282 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=batch
281 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
283 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
282 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
284 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
283 devel-peer-request: 68 bytes of commands arguments in headers
285 devel-peer-request: 68 bytes of commands arguments in headers
284 devel-peer-request: finished in *.???? seconds (200) (glob)
286 devel-peer-request: finished in *.???? seconds (200) (glob)
285 searching for changes
287 searching for changes
286 all remote heads known locally
288 all remote heads known locally
287 preparing listkeys for "phases"
289 preparing listkeys for "phases"
288 sending listkeys command
290 sending listkeys command
289 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=listkeys
291 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=listkeys
290 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
292 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
291 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
293 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
292 devel-peer-request: 16 bytes of commands arguments in headers
294 devel-peer-request: 16 bytes of commands arguments in headers
293 devel-peer-request: finished in *.???? seconds (200) (glob)
295 devel-peer-request: finished in *.???? seconds (200) (glob)
294 received listkey for "phases": 58 bytes
296 received listkey for "phases": 58 bytes
295 checking for updated bookmarks
297 checking for updated bookmarks
296 preparing listkeys for "bookmarks"
298 preparing listkeys for "bookmarks"
297 sending listkeys command
299 sending listkeys command
298 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=listkeys
300 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=listkeys
299 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
301 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
300 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
302 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
301 devel-peer-request: 19 bytes of commands arguments in headers
303 devel-peer-request: 19 bytes of commands arguments in headers
302 devel-peer-request: finished in *.???? seconds (200) (glob)
304 devel-peer-request: finished in *.???? seconds (200) (glob)
303 received listkey for "bookmarks": 0 bytes
305 received listkey for "bookmarks": 0 bytes
304 sending branchmap command
306 sending branchmap command
305 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=branchmap
307 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=branchmap
306 devel-peer-request: Vary X-HgProto-1
308 devel-peer-request: Vary X-HgProto-1
307 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
309 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
308 devel-peer-request: finished in *.???? seconds (200) (glob)
310 devel-peer-request: finished in *.???? seconds (200) (glob)
309 preparing listkeys for "bookmarks"
311 preparing listkeys for "bookmarks"
310 sending listkeys command
312 sending listkeys command
311 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=listkeys
313 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=listkeys
312 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
314 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
313 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
315 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
314 devel-peer-request: 19 bytes of commands arguments in headers
316 devel-peer-request: 19 bytes of commands arguments in headers
315 devel-peer-request: finished in *.???? seconds (200) (glob)
317 devel-peer-request: finished in *.???? seconds (200) (glob)
316 received listkey for "bookmarks": 0 bytes
318 received listkey for "bookmarks": 0 bytes
317 1 changesets found
319 1 changesets found
318 list of changesets:
320 list of changesets:
319 7f4e523d01f2cc3765ac8934da3d14db775ff872
321 7f4e523d01f2cc3765ac8934da3d14db775ff872
320 bundle2-output-bundle: "HG20", 5 parts total
322 bundle2-output-bundle: "HG20", 5 parts total
321 bundle2-output-part: "replycaps" 205 bytes payload
323 bundle2-output-part: "replycaps" 205 bytes payload
322 bundle2-output-part: "check:phases" 24 bytes payload
324 bundle2-output-part: "check:phases" 24 bytes payload
323 bundle2-output-part: "check:heads" streamed payload
325 bundle2-output-part: "check:heads" streamed payload
324 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
326 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
325 bundle2-output-part: "phase-heads" 24 bytes payload
327 bundle2-output-part: "phase-heads" 24 bytes payload
326 sending unbundle command
328 sending unbundle command
327 sending 1013 bytes
329 sending 1013 bytes
328 devel-peer-request: POST http://localhost:$HGPORT2/?cmd=unbundle
330 devel-peer-request: POST http://localhost:$HGPORT2/?cmd=unbundle
329 devel-peer-request: Content-length 1013
331 devel-peer-request: Content-length 1013
330 devel-peer-request: Content-type application/mercurial-0.1
332 devel-peer-request: Content-type application/mercurial-0.1
331 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
333 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
332 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
334 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
333 devel-peer-request: 16 bytes of commands arguments in headers
335 devel-peer-request: 16 bytes of commands arguments in headers
334 devel-peer-request: 1013 bytes of data
336 devel-peer-request: 1013 bytes of data
335 devel-peer-request: finished in *.???? seconds (200) (glob)
337 devel-peer-request: finished in *.???? seconds (200) (glob)
336 bundle2-input-bundle: no-transaction
338 bundle2-input-bundle: no-transaction
337 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
339 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
338 bundle2-input-part: "output" (advisory) (params: 0 advisory) supported
340 bundle2-input-part: "output" (advisory) (params: 0 advisory) supported
339 bundle2-input-part: total payload size 100
341 bundle2-input-part: total payload size 100
340 remote: adding changesets
342 remote: adding changesets
341 remote: adding manifests
343 remote: adding manifests
342 remote: adding file changes
344 remote: adding file changes
343 remote: added 1 changesets with 1 changes to 1 files
345 remote: added 1 changesets with 1 changes to 1 files
344 bundle2-input-part: "output" (advisory) supported
346 bundle2-input-part: "output" (advisory) supported
345 bundle2-input-bundle: 2 parts total
347 bundle2-input-bundle: 2 parts total
346 preparing listkeys for "phases"
348 preparing listkeys for "phases"
347 sending listkeys command
349 sending listkeys command
348 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=listkeys
350 devel-peer-request: GET http://localhost:$HGPORT2/?cmd=listkeys
349 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
351 devel-peer-request: Vary X-HgArg-1,X-HgProto-1
350 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
352 devel-peer-request: X-hgproto-1 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
351 devel-peer-request: 16 bytes of commands arguments in headers
353 devel-peer-request: 16 bytes of commands arguments in headers
352 devel-peer-request: finished in *.???? seconds (200) (glob)
354 devel-peer-request: finished in *.???? seconds (200) (glob)
353 received listkey for "phases": 15 bytes
355 received listkey for "phases": 15 bytes
354 $ hg rollback -q
356 $ hg rollback -q
355
357
356 $ sed 's/.*] "/"/' < ../access.log
358 $ sed 's/.*] "/"/' < ../access.log
357 "GET /?cmd=capabilities HTTP/1.1" 401 -
359 "GET /?cmd=capabilities HTTP/1.1" 401 -
358 "GET /?cmd=capabilities HTTP/1.1" 401 -
360 "GET /?cmd=capabilities HTTP/1.1" 401 -
359 "GET /?cmd=capabilities HTTP/1.1" 401 -
361 "GET /?cmd=capabilities HTTP/1.1" 401 -
360 "GET /?cmd=capabilities HTTP/1.1" 200 -
362 "GET /?cmd=capabilities HTTP/1.1" 200 -
361 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
363 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
362 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
364 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
363 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
365 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
364 "GET /?cmd=capabilities HTTP/1.1" 401 -
366 "GET /?cmd=capabilities HTTP/1.1" 401 -
365 "GET /?cmd=capabilities HTTP/1.1" 200 -
367 "GET /?cmd=capabilities HTTP/1.1" 200 -
366 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
368 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
367 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
369 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
368 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
370 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
369 "GET /?cmd=capabilities HTTP/1.1" 401 -
371 "GET /?cmd=capabilities HTTP/1.1" 401 -
370 "GET /?cmd=capabilities HTTP/1.1" 200 -
372 "GET /?cmd=capabilities HTTP/1.1" 200 -
371 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
373 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
372 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
374 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
373 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
375 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
374 "GET /?cmd=capabilities HTTP/1.1" 401 -
376 "GET /?cmd=capabilities HTTP/1.1" 401 -
375 "GET /?cmd=capabilities HTTP/1.1" 200 -
377 "GET /?cmd=capabilities HTTP/1.1" 200 -
376 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
378 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
377 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
379 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
378 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
380 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
379 "GET /?cmd=capabilities HTTP/1.1" 401 -
381 "GET /?cmd=capabilities HTTP/1.1" 401 -
380 "GET /?cmd=capabilities HTTP/1.1" 200 -
382 "GET /?cmd=capabilities HTTP/1.1" 200 -
381 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
383 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
382 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
384 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
383 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
385 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
384 "GET /?cmd=capabilities HTTP/1.1" 401 - x-hgtest-authtype:Digest
386 "GET /?cmd=capabilities HTTP/1.1" 401 - x-hgtest-authtype:Digest
385 "GET /?cmd=capabilities HTTP/1.1" 200 - x-hgtest-authtype:Digest
387 "GET /?cmd=capabilities HTTP/1.1" 200 - x-hgtest-authtype:Digest
386 "GET /?cmd=lookup HTTP/1.1" 401 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
388 "GET /?cmd=lookup HTTP/1.1" 401 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
387 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
389 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
388 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
390 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
389 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
391 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
390 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
392 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
391 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
393 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull x-hgtest-authtype:Digest
392 "GET /?cmd=capabilities HTTP/1.1" 401 - (no-reposimplestore !)
394 "GET /?cmd=capabilities HTTP/1.1" 401 - (no-reposimplestore !)
393 "GET /?cmd=capabilities HTTP/1.1" 200 - (no-reposimplestore !)
395 "GET /?cmd=capabilities HTTP/1.1" 200 - (no-reposimplestore !)
394 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
396 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
395 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=0&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=bookmarks&stream=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
397 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=0&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=bookmarks&stream=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull (no-reposimplestore !)
396 "GET /?cmd=capabilities HTTP/1.1" 401 - (no-reposimplestore !)
398 "GET /?cmd=capabilities HTTP/1.1" 401 - (no-reposimplestore !)
397 "GET /?cmd=capabilities HTTP/1.1" 200 - (no-reposimplestore !)
399 "GET /?cmd=capabilities HTTP/1.1" 200 - (no-reposimplestore !)
398 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
400 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
399 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
401 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bookmarks=1&$USUAL_BUNDLE_CAPS$&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=bookmarks&phases=1 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
400 "GET /?cmd=capabilities HTTP/1.1" 401 -
402 "GET /?cmd=capabilities HTTP/1.1" 401 -
401 "GET /?cmd=capabilities HTTP/1.1" 401 -
403 "GET /?cmd=capabilities HTTP/1.1" 401 -
402 "GET /?cmd=capabilities HTTP/1.1" 403 -
404 "GET /?cmd=capabilities HTTP/1.1" 403 -
403 "GET /?cmd=capabilities HTTP/1.1" 401 -
405 "GET /?cmd=capabilities HTTP/1.1" 401 -
404 "GET /?cmd=capabilities HTTP/1.1" 200 -
406 "GET /?cmd=capabilities HTTP/1.1" 200 -
405 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
407 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
406 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
408 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
407 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
409 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
408 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
410 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
409 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
411 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
410 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365* (glob)
412 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365* (glob)
411 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
413 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
412 "GET /?cmd=capabilities HTTP/1.1" 401 -
414 "GET /?cmd=capabilities HTTP/1.1" 401 -
413 "GET /?cmd=capabilities HTTP/1.1" 200 -
415 "GET /?cmd=capabilities HTTP/1.1" 200 -
414 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
416 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
415 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
417 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
416 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
418 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
417 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
419 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
418 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
420 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
419 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
421 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365 x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
420 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
422 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull
421
423
422 $ cd ..
424 $ cd ..
423
425
424 clone of serve with repo in root and unserved subrepo (issue2970)
426 clone of serve with repo in root and unserved subrepo (issue2970)
425
427
426 $ hg --cwd test init sub
428 $ hg --cwd test init sub
427 $ echo empty > test/sub/empty
429 $ echo empty > test/sub/empty
428 $ hg --cwd test/sub add empty
430 $ hg --cwd test/sub add empty
429 $ hg --cwd test/sub commit -qm 'add empty'
431 $ hg --cwd test/sub commit -qm 'add empty'
430 $ hg --cwd test/sub tag -r 0 something
432 $ hg --cwd test/sub tag -r 0 something
431 $ echo sub = sub > test/.hgsub
433 $ echo sub = sub > test/.hgsub
432 $ hg --cwd test add .hgsub
434 $ hg --cwd test add .hgsub
433 $ hg --cwd test commit -qm 'add subrepo'
435 $ hg --cwd test commit -qm 'add subrepo'
434 $ hg clone http://localhost:$HGPORT noslash-clone
436 $ hg clone http://localhost:$HGPORT noslash-clone
435 requesting all changes
437 requesting all changes
436 adding changesets
438 adding changesets
437 adding manifests
439 adding manifests
438 adding file changes
440 adding file changes
439 added 3 changesets with 7 changes to 7 files
441 added 3 changesets with 7 changes to 7 files
440 new changesets 8b6053c928fe:56f9bc90cce6
442 new changesets 8b6053c928fe:56f9bc90cce6
441 updating to branch default
443 updating to branch default
442 cloning subrepo sub from http://localhost:$HGPORT/sub
444 cloning subrepo sub from http://localhost:$HGPORT/sub
443 abort: HTTP Error 404: Not Found
445 abort: HTTP Error 404: Not Found
444 [255]
446 [255]
445 $ hg clone http://localhost:$HGPORT/ slash-clone
447 $ hg clone http://localhost:$HGPORT/ slash-clone
446 requesting all changes
448 requesting all changes
447 adding changesets
449 adding changesets
448 adding manifests
450 adding manifests
449 adding file changes
451 adding file changes
450 added 3 changesets with 7 changes to 7 files
452 added 3 changesets with 7 changes to 7 files
451 new changesets 8b6053c928fe:56f9bc90cce6
453 new changesets 8b6053c928fe:56f9bc90cce6
452 updating to branch default
454 updating to branch default
453 cloning subrepo sub from http://localhost:$HGPORT/sub
455 cloning subrepo sub from http://localhost:$HGPORT/sub
454 abort: HTTP Error 404: Not Found
456 abort: HTTP Error 404: Not Found
455 [255]
457 [255]
456
458
457 check error log
459 check error log
458
460
459 $ cat error.log
461 $ cat error.log
460
462
461 $ cat errors2.log
463 $ cat errors2.log
462
464
463 check abort error reporting while pulling/cloning
465 check abort error reporting while pulling/cloning
464
466
465 $ $RUNTESTDIR/killdaemons.py
467 $ $RUNTESTDIR/killdaemons.py
466 $ hg serve -R test -p $HGPORT -d --pid-file=hg3.pid -E error.log --config extensions.crash=${TESTDIR}/crashgetbundler.py
468 $ hg serve -R test -p $HGPORT -d --pid-file=hg3.pid -E error.log --config extensions.crash=${TESTDIR}/crashgetbundler.py
467 $ cat hg3.pid >> $DAEMON_PIDS
469 $ cat hg3.pid >> $DAEMON_PIDS
468 $ hg clone http://localhost:$HGPORT/ abort-clone
470 $ hg clone http://localhost:$HGPORT/ abort-clone
469 requesting all changes
471 requesting all changes
470 remote: abort: this is an exercise
472 remote: abort: this is an exercise
471 abort: pull failed on remote
473 abort: pull failed on remote
472 [255]
474 [255]
473 $ cat error.log
475 $ cat error.log
474
476
475 disable pull-based clones
477 disable pull-based clones
476
478
477 $ hg serve -R test -p $HGPORT1 -d --pid-file=hg4.pid -E error.log --config server.disablefullbundle=True
479 $ hg serve -R test -p $HGPORT1 -d --pid-file=hg4.pid -E error.log --config server.disablefullbundle=True
478 $ cat hg4.pid >> $DAEMON_PIDS
480 $ cat hg4.pid >> $DAEMON_PIDS
479 $ hg clone http://localhost:$HGPORT1/ disable-pull-clone
481 $ hg clone http://localhost:$HGPORT1/ disable-pull-clone
480 requesting all changes
482 requesting all changes
481 remote: abort: server has pull-based clones disabled
483 remote: abort: server has pull-based clones disabled
482 abort: pull failed on remote
484 abort: pull failed on remote
483 (remove --pull if specified or upgrade Mercurial)
485 (remove --pull if specified or upgrade Mercurial)
484 [255]
486 [255]
485
487
486 #if no-reposimplestore
488 #if no-reposimplestore
487 ... but keep stream clones working
489 ... but keep stream clones working
488
490
489 $ hg clone --stream --noupdate http://localhost:$HGPORT1/ test-stream-clone
491 $ hg clone --stream --noupdate http://localhost:$HGPORT1/ test-stream-clone
490 streaming all changes
492 streaming all changes
491 * files to transfer, * of data (glob)
493 * files to transfer, * of data (glob)
492 transferred * in * seconds (*/sec) (glob)
494 transferred * in * seconds (*/sec) (glob)
493 $ cat error.log
495 $ cat error.log
494 #endif
496 #endif
495
497
496 ... and also keep partial clones and pulls working
498 ... and also keep partial clones and pulls working
497 $ hg clone http://localhost:$HGPORT1 --rev 0 test/partial/clone
499 $ hg clone http://localhost:$HGPORT1 --rev 0 test/partial/clone
498 adding changesets
500 adding changesets
499 adding manifests
501 adding manifests
500 adding file changes
502 adding file changes
501 added 1 changesets with 4 changes to 4 files
503 added 1 changesets with 4 changes to 4 files
502 new changesets 8b6053c928fe
504 new changesets 8b6053c928fe
503 updating to branch default
505 updating to branch default
504 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
506 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
505 $ hg pull -R test/partial/clone
507 $ hg pull -R test/partial/clone
506 pulling from http://localhost:$HGPORT1/
508 pulling from http://localhost:$HGPORT1/
507 searching for changes
509 searching for changes
508 adding changesets
510 adding changesets
509 adding manifests
511 adding manifests
510 adding file changes
512 adding file changes
511 added 2 changesets with 3 changes to 3 files
513 added 2 changesets with 3 changes to 3 files
512 new changesets 5fed3813f7f5:56f9bc90cce6
514 new changesets 5fed3813f7f5:56f9bc90cce6
513 (run 'hg update' to get a working copy)
515 (run 'hg update' to get a working copy)
514
516
515 $ hg clone -U -r 0 test/partial/clone test/another/clone
517 $ hg clone -U -r 0 test/partial/clone test/another/clone
516 adding changesets
518 adding changesets
517 adding manifests
519 adding manifests
518 adding file changes
520 adding file changes
519 added 1 changesets with 4 changes to 4 files
521 added 1 changesets with 4 changes to 4 files
520 new changesets 8b6053c928fe
522 new changesets 8b6053c928fe
521
523
522 corrupt cookies file should yield a warning
524 corrupt cookies file should yield a warning
523
525
524 $ cat > $TESTTMP/cookies.txt << EOF
526 $ cat > $TESTTMP/cookies.txt << EOF
525 > bad format
527 > bad format
526 > EOF
528 > EOF
527
529
528 $ hg --config auth.cookiefile=$TESTTMP/cookies.txt id http://localhost:$HGPORT/
530 $ hg --config auth.cookiefile=$TESTTMP/cookies.txt id http://localhost:$HGPORT/
529 (error loading cookie file $TESTTMP/cookies.txt: '*/cookies.txt' does not look like a Netscape format cookies file; continuing without cookies) (glob)
531 (error loading cookie file $TESTTMP/cookies.txt: '*/cookies.txt' does not look like a Netscape format cookies file; continuing without cookies) (glob)
530 56f9bc90cce6
532 56f9bc90cce6
531
533
532 $ killdaemons.py
534 $ killdaemons.py
533
535
534 Create dummy authentication handler that looks for cookies. It doesn't do anything
536 Create dummy authentication handler that looks for cookies. It doesn't do anything
535 useful. It just raises an HTTP 500 with details about the Cookie request header.
537 useful. It just raises an HTTP 500 with details about the Cookie request header.
536 We raise HTTP 500 because its message is printed in the abort message.
538 We raise HTTP 500 because its message is printed in the abort message.
537
539
538 $ cat > cookieauth.py << EOF
540 $ cat > cookieauth.py << EOF
539 > from mercurial import util
541 > from mercurial import util
540 > from mercurial.hgweb import common
542 > from mercurial.hgweb import common
541 > def perform_authentication(hgweb, req, op):
543 > def perform_authentication(hgweb, req, op):
542 > cookie = req.headers.get(b'Cookie')
544 > cookie = req.headers.get(b'Cookie')
543 > if not cookie:
545 > if not cookie:
544 > raise common.ErrorResponse(common.HTTP_SERVER_ERROR, b'no-cookie')
546 > raise common.ErrorResponse(common.HTTP_SERVER_ERROR, b'no-cookie')
545 > raise common.ErrorResponse(common.HTTP_SERVER_ERROR, b'Cookie: %s' % cookie)
547 > raise common.ErrorResponse(common.HTTP_SERVER_ERROR, b'Cookie: %s' % cookie)
546 > def extsetup(ui):
548 > def extsetup(ui):
547 > common.permhooks.insert(0, perform_authentication)
549 > common.permhooks.insert(0, perform_authentication)
548 > EOF
550 > EOF
549
551
550 $ hg serve --config extensions.cookieauth=cookieauth.py -R test -p $HGPORT -d --pid-file=pid
552 $ hg serve --config extensions.cookieauth=cookieauth.py -R test -p $HGPORT -d --pid-file=pid
551 $ cat pid > $DAEMON_PIDS
553 $ cat pid > $DAEMON_PIDS
552
554
553 Request without cookie sent should fail due to lack of cookie
555 Request without cookie sent should fail due to lack of cookie
554
556
555 $ hg id http://localhost:$HGPORT
557 $ hg id http://localhost:$HGPORT
556 abort: HTTP Error 500: no-cookie
558 abort: HTTP Error 500: no-cookie
557 [255]
559 [255]
558
560
559 Populate a cookies file
561 Populate a cookies file
560
562
561 $ cat > cookies.txt << EOF
563 $ cat > cookies.txt << EOF
562 > # HTTP Cookie File
564 > # HTTP Cookie File
563 > # Expiration is 2030-01-01 at midnight
565 > # Expiration is 2030-01-01 at midnight
564 > .example.com TRUE / FALSE 1893456000 hgkey examplevalue
566 > .example.com TRUE / FALSE 1893456000 hgkey examplevalue
565 > EOF
567 > EOF
566
568
567 Should not send a cookie for another domain
569 Should not send a cookie for another domain
568
570
569 $ hg --config auth.cookiefile=cookies.txt id http://localhost:$HGPORT/
571 $ hg --config auth.cookiefile=cookies.txt id http://localhost:$HGPORT/
570 abort: HTTP Error 500: no-cookie
572 abort: HTTP Error 500: no-cookie
571 [255]
573 [255]
572
574
573 Add a cookie entry for our test server and verify it is sent
575 Add a cookie entry for our test server and verify it is sent
574
576
575 $ cat >> cookies.txt << EOF
577 $ cat >> cookies.txt << EOF
576 > localhost.local FALSE / FALSE 1893456000 hgkey localhostvalue
578 > localhost.local FALSE / FALSE 1893456000 hgkey localhostvalue
577 > EOF
579 > EOF
578
580
579 $ hg --config auth.cookiefile=cookies.txt id http://localhost:$HGPORT/
581 $ hg --config auth.cookiefile=cookies.txt id http://localhost:$HGPORT/
580 abort: HTTP Error 500: Cookie: hgkey=localhostvalue
582 abort: HTTP Error 500: Cookie: hgkey=localhostvalue
581 [255]
583 [255]
@@ -1,673 +1,675 b''
1 #require serve ssl
1 #require serve ssl
2
2
3 Proper https client requires the built-in ssl from Python 2.6.
3 Proper https client requires the built-in ssl from Python 2.6.
4
4
5 Make server certificates:
5 Make server certificates:
6
6
7 $ CERTSDIR="$TESTDIR/sslcerts"
7 $ CERTSDIR="$TESTDIR/sslcerts"
8 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub.pem" >> server.pem
8 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub.pem" >> server.pem
9 $ PRIV=`pwd`/server.pem
9 $ PRIV=`pwd`/server.pem
10 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub-not-yet.pem" > server-not-yet.pem
10 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub-not-yet.pem" > server-not-yet.pem
11 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub-expired.pem" > server-expired.pem
11 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub-expired.pem" > server-expired.pem
12
12
13 $ hg init test
13 $ hg init test
14 $ cd test
14 $ cd test
15 $ echo foo>foo
15 $ echo foo>foo
16 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
16 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
17 $ echo foo>foo.d/foo
17 $ echo foo>foo.d/foo
18 $ echo bar>foo.d/bAr.hg.d/BaR
18 $ echo bar>foo.d/bAr.hg.d/BaR
19 $ echo bar>foo.d/baR.d.hg/bAR
19 $ echo bar>foo.d/baR.d.hg/bAR
20 $ hg commit -A -m 1
20 $ hg commit -A -m 1
21 adding foo
21 adding foo
22 adding foo.d/bAr.hg.d/BaR
22 adding foo.d/bAr.hg.d/BaR
23 adding foo.d/baR.d.hg/bAR
23 adding foo.d/baR.d.hg/bAR
24 adding foo.d/foo
24 adding foo.d/foo
25 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
25 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
26 $ cat ../hg0.pid >> $DAEMON_PIDS
26 $ cat ../hg0.pid >> $DAEMON_PIDS
27
27
28 cacert not found
28 cacert not found
29
29
30 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
30 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
31 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
31 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
32 abort: could not find web.cacerts: no-such.pem
32 abort: could not find web.cacerts: no-such.pem
33 [255]
33 [255]
34
34
35 Test server address cannot be reused
35 Test server address cannot be reused
36
36
37 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
37 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
38 abort: cannot start server at 'localhost:$HGPORT': $EADDRINUSE$
38 abort: cannot start server at 'localhost:$HGPORT': $EADDRINUSE$
39 [255]
39 [255]
40
40
41 $ cd ..
41 $ cd ..
42
42
43 Our test cert is not signed by a trusted CA. It should fail to verify if
43 Our test cert is not signed by a trusted CA. It should fail to verify if
44 we are able to load CA certs.
44 we are able to load CA certs.
45
45
46 #if sslcontext defaultcacerts no-defaultcacertsloaded
46 #if sslcontext defaultcacerts no-defaultcacertsloaded
47 $ hg clone https://localhost:$HGPORT/ copy-pull
47 $ hg clone https://localhost:$HGPORT/ copy-pull
48 (an attempt was made to load CA certificates but none were loaded; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
48 (an attempt was made to load CA certificates but none were loaded; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
49 abort: error: *certificate verify failed* (glob)
49 abort: error: *certificate verify failed* (glob)
50 [255]
50 [255]
51 #endif
51 #endif
52
52
53 #if no-sslcontext defaultcacerts
53 #if no-sslcontext defaultcacerts
54 $ hg clone https://localhost:$HGPORT/ copy-pull
54 $ hg clone https://localhost:$HGPORT/ copy-pull
55 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
55 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
56 (using CA certificates from *; if you see this message, your Mercurial install is not properly configured; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
56 (using CA certificates from *; if you see this message, your Mercurial install is not properly configured; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
57 abort: error: *certificate verify failed* (glob)
57 abort: error: *certificate verify failed* (glob)
58 [255]
58 [255]
59 #endif
59 #endif
60
60
61 #if no-sslcontext windows
61 #if no-sslcontext windows
62 $ hg clone https://localhost:$HGPORT/ copy-pull
62 $ hg clone https://localhost:$HGPORT/ copy-pull
63 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
63 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
64 (unable to load Windows CA certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message)
64 (unable to load Windows CA certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message)
65 abort: error: *certificate verify failed* (glob)
65 abort: error: *certificate verify failed* (glob)
66 [255]
66 [255]
67 #endif
67 #endif
68
68
69 #if no-sslcontext osx
69 #if no-sslcontext osx
70 $ hg clone https://localhost:$HGPORT/ copy-pull
70 $ hg clone https://localhost:$HGPORT/ copy-pull
71 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
71 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
72 (unable to load CA certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message)
72 (unable to load CA certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message)
73 abort: localhost certificate error: no certificate received
73 abort: localhost certificate error: no certificate received
74 (set hostsecurity.localhost:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
74 (set hostsecurity.localhost:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
75 [255]
75 [255]
76 #endif
76 #endif
77
77
78 #if defaultcacertsloaded
78 #if defaultcacertsloaded
79 $ hg clone https://localhost:$HGPORT/ copy-pull
79 $ hg clone https://localhost:$HGPORT/ copy-pull
80 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
80 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
81 (using CA certificates from *; if you see this message, your Mercurial install is not properly configured; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
81 (using CA certificates from *; if you see this message, your Mercurial install is not properly configured; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
82 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
82 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
83 abort: error: *certificate verify failed* (glob)
83 abort: error: *certificate verify failed* (glob)
84 [255]
84 [255]
85 #endif
85 #endif
86
86
87 #if no-defaultcacerts
87 #if no-defaultcacerts
88 $ hg clone https://localhost:$HGPORT/ copy-pull
88 $ hg clone https://localhost:$HGPORT/ copy-pull
89 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
89 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
90 (unable to load * certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
90 (unable to load * certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
91 abort: localhost certificate error: no certificate received
91 abort: localhost certificate error: no certificate received
92 (set hostsecurity.localhost:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
92 (set hostsecurity.localhost:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
93 [255]
93 [255]
94 #endif
94 #endif
95
95
96 Specifying a per-host certificate file that doesn't exist will abort. The full
96 Specifying a per-host certificate file that doesn't exist will abort. The full
97 C:/path/to/msysroot will print on Windows.
97 C:/path/to/msysroot will print on Windows.
98
98
99 $ hg --config hostsecurity.localhost:verifycertsfile=/does/not/exist clone https://localhost:$HGPORT/
99 $ hg --config hostsecurity.localhost:verifycertsfile=/does/not/exist clone https://localhost:$HGPORT/
100 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
100 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
101 abort: path specified by hostsecurity.localhost:verifycertsfile does not exist: */does/not/exist (glob)
101 abort: path specified by hostsecurity.localhost:verifycertsfile does not exist: */does/not/exist (glob)
102 [255]
102 [255]
103
103
104 A malformed per-host certificate file will raise an error
104 A malformed per-host certificate file will raise an error
105
105
106 $ echo baddata > badca.pem
106 $ echo baddata > badca.pem
107 #if sslcontext
107 #if sslcontext
108 $ hg --config hostsecurity.localhost:verifycertsfile=badca.pem clone https://localhost:$HGPORT/
108 $ hg --config hostsecurity.localhost:verifycertsfile=badca.pem clone https://localhost:$HGPORT/
109 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
109 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
110 abort: error loading CA file badca.pem: * (glob)
110 abort: error loading CA file badca.pem: * (glob)
111 (file is empty or malformed?)
111 (file is empty or malformed?)
112 [255]
112 [255]
113 #else
113 #else
114 $ hg --config hostsecurity.localhost:verifycertsfile=badca.pem clone https://localhost:$HGPORT/
114 $ hg --config hostsecurity.localhost:verifycertsfile=badca.pem clone https://localhost:$HGPORT/
115 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
115 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
116 abort: error: * (glob)
116 abort: error: * (glob)
117 [255]
117 [255]
118 #endif
118 #endif
119
119
120 A per-host certificate mismatching the server will fail verification
120 A per-host certificate mismatching the server will fail verification
121
121
122 (modern ssl is able to discern whether the loaded cert is a CA cert)
122 (modern ssl is able to discern whether the loaded cert is a CA cert)
123 #if sslcontext
123 #if sslcontext
124 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/client-cert.pem" clone https://localhost:$HGPORT/
124 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/client-cert.pem" clone https://localhost:$HGPORT/
125 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
125 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
126 (an attempt was made to load CA certificates but none were loaded; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
126 (an attempt was made to load CA certificates but none were loaded; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
127 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
127 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
128 abort: error: *certificate verify failed* (glob)
128 abort: error: *certificate verify failed* (glob)
129 [255]
129 [255]
130 #else
130 #else
131 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/client-cert.pem" clone https://localhost:$HGPORT/
131 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/client-cert.pem" clone https://localhost:$HGPORT/
132 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
132 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
133 abort: error: *certificate verify failed* (glob)
133 abort: error: *certificate verify failed* (glob)
134 [255]
134 [255]
135 #endif
135 #endif
136
136
137 A per-host certificate matching the server's cert will be accepted
137 A per-host certificate matching the server's cert will be accepted
138
138
139 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/pub.pem" clone -U https://localhost:$HGPORT/ perhostgood1
139 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/pub.pem" clone -U https://localhost:$HGPORT/ perhostgood1
140 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
140 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
141 requesting all changes
141 requesting all changes
142 adding changesets
142 adding changesets
143 adding manifests
143 adding manifests
144 adding file changes
144 adding file changes
145 added 1 changesets with 4 changes to 4 files
145 added 1 changesets with 4 changes to 4 files
146 new changesets 8b6053c928fe
146 new changesets 8b6053c928fe
147
147
148 A per-host certificate with multiple certs and one matching will be accepted
148 A per-host certificate with multiple certs and one matching will be accepted
149
149
150 $ cat "$CERTSDIR/client-cert.pem" "$CERTSDIR/pub.pem" > perhost.pem
150 $ cat "$CERTSDIR/client-cert.pem" "$CERTSDIR/pub.pem" > perhost.pem
151 $ hg --config hostsecurity.localhost:verifycertsfile=perhost.pem clone -U https://localhost:$HGPORT/ perhostgood2
151 $ hg --config hostsecurity.localhost:verifycertsfile=perhost.pem clone -U https://localhost:$HGPORT/ perhostgood2
152 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
152 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
153 requesting all changes
153 requesting all changes
154 adding changesets
154 adding changesets
155 adding manifests
155 adding manifests
156 adding file changes
156 adding file changes
157 added 1 changesets with 4 changes to 4 files
157 added 1 changesets with 4 changes to 4 files
158 new changesets 8b6053c928fe
158 new changesets 8b6053c928fe
159
159
160 Defining both per-host certificate and a fingerprint will print a warning
160 Defining both per-host certificate and a fingerprint will print a warning
161
161
162 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/pub.pem" --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 clone -U https://localhost:$HGPORT/ caandfingerwarning
162 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/pub.pem" --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 clone -U https://localhost:$HGPORT/ caandfingerwarning
163 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
163 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
164 (hostsecurity.localhost:verifycertsfile ignored when host fingerprints defined; using host fingerprints for verification)
164 (hostsecurity.localhost:verifycertsfile ignored when host fingerprints defined; using host fingerprints for verification)
165 requesting all changes
165 requesting all changes
166 adding changesets
166 adding changesets
167 adding manifests
167 adding manifests
168 adding file changes
168 adding file changes
169 added 1 changesets with 4 changes to 4 files
169 added 1 changesets with 4 changes to 4 files
170 new changesets 8b6053c928fe
170 new changesets 8b6053c928fe
171
171
172 $ DISABLECACERTS="--config devel.disableloaddefaultcerts=true"
172 $ DISABLECACERTS="--config devel.disableloaddefaultcerts=true"
173
173
174 Inability to verify peer certificate will result in abort
174 Inability to verify peer certificate will result in abort
175
175
176 $ hg clone https://localhost:$HGPORT/ copy-pull $DISABLECACERTS
176 $ hg clone https://localhost:$HGPORT/ copy-pull $DISABLECACERTS
177 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
177 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
178 abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect
178 abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect
179 (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
179 (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
180 [255]
180 [255]
181
181
182 $ hg clone --insecure https://localhost:$HGPORT/ copy-pull
182 $ hg clone --insecure https://localhost:$HGPORT/ copy-pull
183 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
183 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
184 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
184 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
185 requesting all changes
185 requesting all changes
186 adding changesets
186 adding changesets
187 adding manifests
187 adding manifests
188 adding file changes
188 adding file changes
189 added 1 changesets with 4 changes to 4 files
189 added 1 changesets with 4 changes to 4 files
190 new changesets 8b6053c928fe
190 new changesets 8b6053c928fe
191 updating to branch default
191 updating to branch default
192 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
193 $ hg verify -R copy-pull
193 $ hg verify -R copy-pull
194 checking changesets
194 checking changesets
195 checking manifests
195 checking manifests
196 crosschecking files in changesets and manifests
196 crosschecking files in changesets and manifests
197 checking files
197 checking files
198 checked 1 changesets with 4 changes to 4 files
198 checked 1 changesets with 4 changes to 4 files
199 $ cd test
199 $ cd test
200 $ echo bar > bar
200 $ echo bar > bar
201 $ hg commit -A -d '1 0' -m 2
201 $ hg commit -A -d '1 0' -m 2
202 adding bar
202 adding bar
203 $ cd ..
203 $ cd ..
204
204
205 pull without cacert
205 pull without cacert
206
206
207 $ cd copy-pull
207 $ cd copy-pull
208 $ cat >> .hg/hgrc <<EOF
208 $ cat >> .hg/hgrc <<EOF
209 > [hooks]
209 > [hooks]
210 > changegroup = sh -c "printenv.py --line changegroup"
210 > changegroup = sh -c "printenv.py --line changegroup"
211 > EOF
211 > EOF
212 $ hg pull $DISABLECACERTS
212 $ hg pull $DISABLECACERTS
213 pulling from https://localhost:$HGPORT/
213 pulling from https://localhost:$HGPORT/
214 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
214 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
215 abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect
215 abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect
216 (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
216 (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
217 [255]
217 [255]
218
218
219 $ hg pull --insecure
219 $ hg pull --insecure
220 pulling from https://localhost:$HGPORT/
220 pulling from https://localhost:$HGPORT/
221 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
221 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
222 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
222 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
223 searching for changes
223 searching for changes
224 adding changesets
224 adding changesets
225 adding manifests
225 adding manifests
226 adding file changes
226 adding file changes
227 added 1 changesets with 1 changes to 1 files
227 added 1 changesets with 1 changes to 1 files
228 new changesets 5fed3813f7f5
228 new changesets 5fed3813f7f5
229 changegroup hook: HG_HOOKNAME=changegroup
229 changegroup hook: HG_HOOKNAME=changegroup
230 HG_HOOKTYPE=changegroup
230 HG_HOOKTYPE=changegroup
231 HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
231 HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
232 HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
232 HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
233 HG_SOURCE=pull
233 HG_SOURCE=pull
234 HG_TXNID=TXN:$ID$
234 HG_TXNID=TXN:$ID$
235 HG_TXNNAME=pull
236 https://localhost:$HGPORT/
235 HG_URL=https://localhost:$HGPORT/
237 HG_URL=https://localhost:$HGPORT/
236
238
237 (run 'hg update' to get a working copy)
239 (run 'hg update' to get a working copy)
238 $ cd ..
240 $ cd ..
239
241
240 cacert configured in local repo
242 cacert configured in local repo
241
243
242 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
244 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
243 $ echo "[web]" >> copy-pull/.hg/hgrc
245 $ echo "[web]" >> copy-pull/.hg/hgrc
244 $ echo "cacerts=$CERTSDIR/pub.pem" >> copy-pull/.hg/hgrc
246 $ echo "cacerts=$CERTSDIR/pub.pem" >> copy-pull/.hg/hgrc
245 $ hg -R copy-pull pull
247 $ hg -R copy-pull pull
246 pulling from https://localhost:$HGPORT/
248 pulling from https://localhost:$HGPORT/
247 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
249 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
248 searching for changes
250 searching for changes
249 no changes found
251 no changes found
250 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
252 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
251
253
252 cacert configured globally, also testing expansion of environment
254 cacert configured globally, also testing expansion of environment
253 variables in the filename
255 variables in the filename
254
256
255 $ echo "[web]" >> $HGRCPATH
257 $ echo "[web]" >> $HGRCPATH
256 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
258 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
257 $ P="$CERTSDIR" hg -R copy-pull pull
259 $ P="$CERTSDIR" hg -R copy-pull pull
258 pulling from https://localhost:$HGPORT/
260 pulling from https://localhost:$HGPORT/
259 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
261 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
260 searching for changes
262 searching for changes
261 no changes found
263 no changes found
262 $ P="$CERTSDIR" hg -R copy-pull pull --insecure
264 $ P="$CERTSDIR" hg -R copy-pull pull --insecure
263 pulling from https://localhost:$HGPORT/
265 pulling from https://localhost:$HGPORT/
264 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
266 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
265 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
267 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
266 searching for changes
268 searching for changes
267 no changes found
269 no changes found
268
270
269 empty cacert file
271 empty cacert file
270
272
271 $ touch emptycafile
273 $ touch emptycafile
272
274
273 #if sslcontext
275 #if sslcontext
274 $ hg --config web.cacerts=emptycafile -R copy-pull pull
276 $ hg --config web.cacerts=emptycafile -R copy-pull pull
275 pulling from https://localhost:$HGPORT/
277 pulling from https://localhost:$HGPORT/
276 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
278 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
277 abort: error loading CA file emptycafile: * (glob)
279 abort: error loading CA file emptycafile: * (glob)
278 (file is empty or malformed?)
280 (file is empty or malformed?)
279 [255]
281 [255]
280 #else
282 #else
281 $ hg --config web.cacerts=emptycafile -R copy-pull pull
283 $ hg --config web.cacerts=emptycafile -R copy-pull pull
282 pulling from https://localhost:$HGPORT/
284 pulling from https://localhost:$HGPORT/
283 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
285 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
284 abort: error: * (glob)
286 abort: error: * (glob)
285 [255]
287 [255]
286 #endif
288 #endif
287
289
288 cacert mismatch
290 cacert mismatch
289
291
290 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub.pem" \
292 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub.pem" \
291 > https://$LOCALIP:$HGPORT/
293 > https://$LOCALIP:$HGPORT/
292 pulling from https://*:$HGPORT/ (glob)
294 pulling from https://*:$HGPORT/ (glob)
293 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
295 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
294 abort: $LOCALIP certificate error: certificate is for localhost (glob)
296 abort: $LOCALIP certificate error: certificate is for localhost (glob)
295 (set hostsecurity.$LOCALIP:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
297 (set hostsecurity.$LOCALIP:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
296 [255]
298 [255]
297 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub.pem" \
299 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub.pem" \
298 > https://$LOCALIP:$HGPORT/ --insecure
300 > https://$LOCALIP:$HGPORT/ --insecure
299 pulling from https://*:$HGPORT/ (glob)
301 pulling from https://*:$HGPORT/ (glob)
300 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
302 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
301 warning: connection security to $LOCALIP is disabled per current settings; communication is susceptible to eavesdropping and tampering (glob)
303 warning: connection security to $LOCALIP is disabled per current settings; communication is susceptible to eavesdropping and tampering (glob)
302 searching for changes
304 searching for changes
303 no changes found
305 no changes found
304 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-other.pem"
306 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-other.pem"
305 pulling from https://localhost:$HGPORT/
307 pulling from https://localhost:$HGPORT/
306 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
308 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
307 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
309 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
308 abort: error: *certificate verify failed* (glob)
310 abort: error: *certificate verify failed* (glob)
309 [255]
311 [255]
310 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-other.pem" \
312 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-other.pem" \
311 > --insecure
313 > --insecure
312 pulling from https://localhost:$HGPORT/
314 pulling from https://localhost:$HGPORT/
313 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
315 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
314 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
316 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
315 searching for changes
317 searching for changes
316 no changes found
318 no changes found
317
319
318 Test server cert which isn't valid yet
320 Test server cert which isn't valid yet
319
321
320 $ hg serve -R test -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
322 $ hg serve -R test -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
321 $ cat hg1.pid >> $DAEMON_PIDS
323 $ cat hg1.pid >> $DAEMON_PIDS
322 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-not-yet.pem" \
324 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-not-yet.pem" \
323 > https://localhost:$HGPORT1/
325 > https://localhost:$HGPORT1/
324 pulling from https://localhost:$HGPORT1/
326 pulling from https://localhost:$HGPORT1/
325 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
327 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
326 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
328 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
327 abort: error: *certificate verify failed* (glob)
329 abort: error: *certificate verify failed* (glob)
328 [255]
330 [255]
329
331
330 Test server cert which no longer is valid
332 Test server cert which no longer is valid
331
333
332 $ hg serve -R test -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
334 $ hg serve -R test -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
333 $ cat hg2.pid >> $DAEMON_PIDS
335 $ cat hg2.pid >> $DAEMON_PIDS
334 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-expired.pem" \
336 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-expired.pem" \
335 > https://localhost:$HGPORT2/
337 > https://localhost:$HGPORT2/
336 pulling from https://localhost:$HGPORT2/
338 pulling from https://localhost:$HGPORT2/
337 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
339 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
338 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
340 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
339 abort: error: *certificate verify failed* (glob)
341 abort: error: *certificate verify failed* (glob)
340 [255]
342 [255]
341
343
342 Disabling the TLS 1.0 warning works
344 Disabling the TLS 1.0 warning works
343 $ hg -R copy-pull id https://localhost:$HGPORT/ \
345 $ hg -R copy-pull id https://localhost:$HGPORT/ \
344 > --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 \
346 > --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 \
345 > --config hostsecurity.disabletls10warning=true
347 > --config hostsecurity.disabletls10warning=true
346 5fed3813f7f5
348 5fed3813f7f5
347
349
348 Error message for setting ciphers is different depending on SSLContext support
350 Error message for setting ciphers is different depending on SSLContext support
349
351
350 #if no-sslcontext
352 #if no-sslcontext
351 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
353 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
352 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
354 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
353 abort: *No cipher can be selected. (glob)
355 abort: *No cipher can be selected. (glob)
354 [255]
356 [255]
355
357
356 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/
358 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/
357 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
359 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
358 5fed3813f7f5
360 5fed3813f7f5
359 #endif
361 #endif
360
362
361 #if sslcontext
363 #if sslcontext
362 Setting ciphers to an invalid value aborts
364 Setting ciphers to an invalid value aborts
363 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
365 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
364 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
366 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
365 abort: could not set ciphers: No cipher can be selected.
367 abort: could not set ciphers: No cipher can be selected.
366 (change cipher string (invalid) in config)
368 (change cipher string (invalid) in config)
367 [255]
369 [255]
368
370
369 $ P="$CERTSDIR" hg --config hostsecurity.localhost:ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
371 $ P="$CERTSDIR" hg --config hostsecurity.localhost:ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
370 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
372 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
371 abort: could not set ciphers: No cipher can be selected.
373 abort: could not set ciphers: No cipher can be selected.
372 (change cipher string (invalid) in config)
374 (change cipher string (invalid) in config)
373 [255]
375 [255]
374
376
375 Changing the cipher string works
377 Changing the cipher string works
376
378
377 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/
379 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/
378 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
380 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
379 5fed3813f7f5
381 5fed3813f7f5
380 #endif
382 #endif
381
383
382 Fingerprints
384 Fingerprints
383
385
384 - works without cacerts (hostfingerprints)
386 - works without cacerts (hostfingerprints)
385 $ hg -R copy-pull id https://localhost:$HGPORT/ --insecure --config hostfingerprints.localhost=ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
387 $ hg -R copy-pull id https://localhost:$HGPORT/ --insecure --config hostfingerprints.localhost=ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
386 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
388 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
387 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, remove the old SHA-1 fingerprint from [hostfingerprints] and add the following entry to the new [hostsecurity] section: localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
389 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, remove the old SHA-1 fingerprint from [hostfingerprints] and add the following entry to the new [hostsecurity] section: localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
388 5fed3813f7f5
390 5fed3813f7f5
389
391
390 - works without cacerts (hostsecurity)
392 - works without cacerts (hostsecurity)
391 $ hg -R copy-pull id https://localhost:$HGPORT/ --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
393 $ hg -R copy-pull id https://localhost:$HGPORT/ --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
392 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
394 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
393 5fed3813f7f5
395 5fed3813f7f5
394
396
395 $ hg -R copy-pull id https://localhost:$HGPORT/ --config hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e
397 $ hg -R copy-pull id https://localhost:$HGPORT/ --config hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e
396 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
398 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
397 5fed3813f7f5
399 5fed3813f7f5
398
400
399 - multiple fingerprints specified and first matches
401 - multiple fingerprints specified and first matches
400 $ hg --config 'hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03, deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/ --insecure
402 $ hg --config 'hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03, deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/ --insecure
401 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
403 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
402 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, remove the old SHA-1 fingerprint from [hostfingerprints] and add the following entry to the new [hostsecurity] section: localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
404 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, remove the old SHA-1 fingerprint from [hostfingerprints] and add the following entry to the new [hostsecurity] section: localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
403 5fed3813f7f5
405 5fed3813f7f5
404
406
405 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03, sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/
407 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03, sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/
406 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
408 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
407 5fed3813f7f5
409 5fed3813f7f5
408
410
409 - multiple fingerprints specified and last matches
411 - multiple fingerprints specified and last matches
410 $ hg --config 'hostfingerprints.localhost=deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03' -R copy-pull id https://localhost:$HGPORT/ --insecure
412 $ hg --config 'hostfingerprints.localhost=deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03' -R copy-pull id https://localhost:$HGPORT/ --insecure
411 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
413 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
412 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, remove the old SHA-1 fingerprint from [hostfingerprints] and add the following entry to the new [hostsecurity] section: localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
414 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, remove the old SHA-1 fingerprint from [hostfingerprints] and add the following entry to the new [hostsecurity] section: localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
413 5fed3813f7f5
415 5fed3813f7f5
414
416
415 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03' -R copy-pull id https://localhost:$HGPORT/
417 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03' -R copy-pull id https://localhost:$HGPORT/
416 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
418 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
417 5fed3813f7f5
419 5fed3813f7f5
418
420
419 - multiple fingerprints specified and none match
421 - multiple fingerprints specified and none match
420
422
421 $ hg --config 'hostfingerprints.localhost=deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, aeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/ --insecure
423 $ hg --config 'hostfingerprints.localhost=deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, aeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/ --insecure
422 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
424 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
423 abort: certificate for localhost has unexpected fingerprint ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
425 abort: certificate for localhost has unexpected fingerprint ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
424 (check hostfingerprint configuration)
426 (check hostfingerprint configuration)
425 [255]
427 [255]
426
428
427 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, sha1:aeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/
429 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, sha1:aeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/
428 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
430 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
429 abort: certificate for localhost has unexpected fingerprint sha1:ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
431 abort: certificate for localhost has unexpected fingerprint sha1:ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
430 (check hostsecurity configuration)
432 (check hostsecurity configuration)
431 [255]
433 [255]
432
434
433 - fails when cert doesn't match hostname (port is ignored)
435 - fails when cert doesn't match hostname (port is ignored)
434 $ hg -R copy-pull id https://localhost:$HGPORT1/ --config hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
436 $ hg -R copy-pull id https://localhost:$HGPORT1/ --config hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
435 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
437 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
436 abort: certificate for localhost has unexpected fingerprint f4:2f:5a:0c:3e:52:5b:db:e7:24:a8:32:1d:18:97:6d:69:b5:87:84
438 abort: certificate for localhost has unexpected fingerprint f4:2f:5a:0c:3e:52:5b:db:e7:24:a8:32:1d:18:97:6d:69:b5:87:84
437 (check hostfingerprint configuration)
439 (check hostfingerprint configuration)
438 [255]
440 [255]
439
441
440
442
441 - ignores that certificate doesn't match hostname
443 - ignores that certificate doesn't match hostname
442 $ hg -R copy-pull id https://$LOCALIP:$HGPORT/ --config hostfingerprints.$LOCALIP=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
444 $ hg -R copy-pull id https://$LOCALIP:$HGPORT/ --config hostfingerprints.$LOCALIP=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
443 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
445 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
444 (SHA-1 fingerprint for $LOCALIP found in legacy [hostfingerprints] section; if you trust this fingerprint, remove the old SHA-1 fingerprint from [hostfingerprints] and add the following entry to the new [hostsecurity] section: $LOCALIP:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
446 (SHA-1 fingerprint for $LOCALIP found in legacy [hostfingerprints] section; if you trust this fingerprint, remove the old SHA-1 fingerprint from [hostfingerprints] and add the following entry to the new [hostsecurity] section: $LOCALIP:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
445 5fed3813f7f5
447 5fed3813f7f5
446
448
447 Ports used by next test. Kill servers.
449 Ports used by next test. Kill servers.
448
450
449 $ killdaemons.py hg0.pid
451 $ killdaemons.py hg0.pid
450 $ killdaemons.py hg1.pid
452 $ killdaemons.py hg1.pid
451 $ killdaemons.py hg2.pid
453 $ killdaemons.py hg2.pid
452
454
453 #if sslcontext tls1.2
455 #if sslcontext tls1.2
454 Start servers running supported TLS versions
456 Start servers running supported TLS versions
455
457
456 $ cd test
458 $ cd test
457 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV \
459 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV \
458 > --config devel.serverexactprotocol=tls1.0
460 > --config devel.serverexactprotocol=tls1.0
459 $ cat ../hg0.pid >> $DAEMON_PIDS
461 $ cat ../hg0.pid >> $DAEMON_PIDS
460 $ hg serve -p $HGPORT1 -d --pid-file=../hg1.pid --certificate=$PRIV \
462 $ hg serve -p $HGPORT1 -d --pid-file=../hg1.pid --certificate=$PRIV \
461 > --config devel.serverexactprotocol=tls1.1
463 > --config devel.serverexactprotocol=tls1.1
462 $ cat ../hg1.pid >> $DAEMON_PIDS
464 $ cat ../hg1.pid >> $DAEMON_PIDS
463 $ hg serve -p $HGPORT2 -d --pid-file=../hg2.pid --certificate=$PRIV \
465 $ hg serve -p $HGPORT2 -d --pid-file=../hg2.pid --certificate=$PRIV \
464 > --config devel.serverexactprotocol=tls1.2
466 > --config devel.serverexactprotocol=tls1.2
465 $ cat ../hg2.pid >> $DAEMON_PIDS
467 $ cat ../hg2.pid >> $DAEMON_PIDS
466 $ cd ..
468 $ cd ..
467
469
468 Clients talking same TLS versions work
470 Clients talking same TLS versions work
469
471
470 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.0 id https://localhost:$HGPORT/
472 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.0 id https://localhost:$HGPORT/
471 5fed3813f7f5
473 5fed3813f7f5
472 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT1/
474 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT1/
473 5fed3813f7f5
475 5fed3813f7f5
474 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT2/
476 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT2/
475 5fed3813f7f5
477 5fed3813f7f5
476
478
477 Clients requiring newer TLS version than what server supports fail
479 Clients requiring newer TLS version than what server supports fail
478
480
479 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/
481 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/
480 (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
482 (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
481 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
483 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
482 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
484 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
483 abort: error: *unsupported protocol* (glob)
485 abort: error: *unsupported protocol* (glob)
484 [255]
486 [255]
485
487
486 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT/
488 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT/
487 (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
489 (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
488 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
490 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
489 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
491 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
490 abort: error: *unsupported protocol* (glob)
492 abort: error: *unsupported protocol* (glob)
491 [255]
493 [255]
492 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT/
494 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT/
493 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
495 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
494 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
496 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
495 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
497 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
496 abort: error: *unsupported protocol* (glob)
498 abort: error: *unsupported protocol* (glob)
497 [255]
499 [255]
498 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT1/
500 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT1/
499 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
501 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
500 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
502 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
501 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
503 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
502 abort: error: *unsupported protocol* (glob)
504 abort: error: *unsupported protocol* (glob)
503 [255]
505 [255]
504
506
505 --insecure will allow TLS 1.0 connections and override configs
507 --insecure will allow TLS 1.0 connections and override configs
506
508
507 $ hg --config hostsecurity.minimumprotocol=tls1.2 id --insecure https://localhost:$HGPORT1/
509 $ hg --config hostsecurity.minimumprotocol=tls1.2 id --insecure https://localhost:$HGPORT1/
508 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
510 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
509 5fed3813f7f5
511 5fed3813f7f5
510
512
511 The per-host config option overrides the default
513 The per-host config option overrides the default
512
514
513 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
515 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
514 > --config hostsecurity.minimumprotocol=tls1.2 \
516 > --config hostsecurity.minimumprotocol=tls1.2 \
515 > --config hostsecurity.localhost:minimumprotocol=tls1.0
517 > --config hostsecurity.localhost:minimumprotocol=tls1.0
516 5fed3813f7f5
518 5fed3813f7f5
517
519
518 The per-host config option by itself works
520 The per-host config option by itself works
519
521
520 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
522 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
521 > --config hostsecurity.localhost:minimumprotocol=tls1.2
523 > --config hostsecurity.localhost:minimumprotocol=tls1.2
522 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
524 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
523 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
525 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
524 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
526 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
525 abort: error: *unsupported protocol* (glob)
527 abort: error: *unsupported protocol* (glob)
526 [255]
528 [255]
527
529
528 .hg/hgrc file [hostsecurity] settings are applied to remote ui instances (issue5305)
530 .hg/hgrc file [hostsecurity] settings are applied to remote ui instances (issue5305)
529
531
530 $ cat >> copy-pull/.hg/hgrc << EOF
532 $ cat >> copy-pull/.hg/hgrc << EOF
531 > [hostsecurity]
533 > [hostsecurity]
532 > localhost:minimumprotocol=tls1.2
534 > localhost:minimumprotocol=tls1.2
533 > EOF
535 > EOF
534 $ P="$CERTSDIR" hg -R copy-pull id https://localhost:$HGPORT/
536 $ P="$CERTSDIR" hg -R copy-pull id https://localhost:$HGPORT/
535 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
537 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
536 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
538 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
537 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
539 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
538 abort: error: *unsupported protocol* (glob)
540 abort: error: *unsupported protocol* (glob)
539 [255]
541 [255]
540
542
541 $ killdaemons.py hg0.pid
543 $ killdaemons.py hg0.pid
542 $ killdaemons.py hg1.pid
544 $ killdaemons.py hg1.pid
543 $ killdaemons.py hg2.pid
545 $ killdaemons.py hg2.pid
544 #endif
546 #endif
545
547
546 Prepare for connecting through proxy
548 Prepare for connecting through proxy
547
549
548 $ hg serve -R test -p $HGPORT -d --pid-file=hg0.pid --certificate=$PRIV
550 $ hg serve -R test -p $HGPORT -d --pid-file=hg0.pid --certificate=$PRIV
549 $ cat hg0.pid >> $DAEMON_PIDS
551 $ cat hg0.pid >> $DAEMON_PIDS
550 $ hg serve -R test -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
552 $ hg serve -R test -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
551 $ cat hg2.pid >> $DAEMON_PIDS
553 $ cat hg2.pid >> $DAEMON_PIDS
552 tinyproxy.py doesn't fully detach, so killing it may result in extra output
554 tinyproxy.py doesn't fully detach, so killing it may result in extra output
553 from the shell. So don't kill it.
555 from the shell. So don't kill it.
554 $ tinyproxy.py $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
556 $ tinyproxy.py $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
555 $ while [ ! -f proxy.pid ]; do sleep 0; done
557 $ while [ ! -f proxy.pid ]; do sleep 0; done
556 $ cat proxy.pid >> $DAEMON_PIDS
558 $ cat proxy.pid >> $DAEMON_PIDS
557
559
558 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
560 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
559 $ echo "always=True" >> copy-pull/.hg/hgrc
561 $ echo "always=True" >> copy-pull/.hg/hgrc
560 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
562 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
561 $ echo "localhost =" >> copy-pull/.hg/hgrc
563 $ echo "localhost =" >> copy-pull/.hg/hgrc
562
564
563 Test unvalidated https through proxy
565 Test unvalidated https through proxy
564
566
565 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure
567 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure
566 pulling from https://localhost:$HGPORT/
568 pulling from https://localhost:$HGPORT/
567 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
569 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
568 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
570 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
569 searching for changes
571 searching for changes
570 no changes found
572 no changes found
571
573
572 Test https with cacert and fingerprint through proxy
574 Test https with cacert and fingerprint through proxy
573
575
574 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
576 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
575 > --config web.cacerts="$CERTSDIR/pub.pem"
577 > --config web.cacerts="$CERTSDIR/pub.pem"
576 pulling from https://localhost:$HGPORT/
578 pulling from https://localhost:$HGPORT/
577 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
579 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
578 searching for changes
580 searching for changes
579 no changes found
581 no changes found
580 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://localhost:$HGPORT/ --config hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 --trace
582 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://localhost:$HGPORT/ --config hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 --trace
581 pulling from https://*:$HGPORT/ (glob)
583 pulling from https://*:$HGPORT/ (glob)
582 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
584 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
583 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, remove the old SHA-1 fingerprint from [hostfingerprints] and add the following entry to the new [hostsecurity] section: localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
585 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, remove the old SHA-1 fingerprint from [hostfingerprints] and add the following entry to the new [hostsecurity] section: localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
584 searching for changes
586 searching for changes
585 no changes found
587 no changes found
586
588
587 Test https with cert problems through proxy
589 Test https with cert problems through proxy
588
590
589 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
591 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
590 > --config web.cacerts="$CERTSDIR/pub-other.pem"
592 > --config web.cacerts="$CERTSDIR/pub-other.pem"
591 pulling from https://localhost:$HGPORT/
593 pulling from https://localhost:$HGPORT/
592 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
594 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
593 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
595 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
594 abort: error: *certificate verify failed* (glob)
596 abort: error: *certificate verify failed* (glob)
595 [255]
597 [255]
596 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
598 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
597 > --config web.cacerts="$CERTSDIR/pub-expired.pem" https://localhost:$HGPORT2/
599 > --config web.cacerts="$CERTSDIR/pub-expired.pem" https://localhost:$HGPORT2/
598 pulling from https://localhost:$HGPORT2/
600 pulling from https://localhost:$HGPORT2/
599 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
601 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
600 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
602 (the full certificate chain may not be available locally; see "hg help debugssl") (windows !)
601 abort: error: *certificate verify failed* (glob)
603 abort: error: *certificate verify failed* (glob)
602 [255]
604 [255]
603
605
604
606
605 $ killdaemons.py hg0.pid
607 $ killdaemons.py hg0.pid
606
608
607 #if sslcontext
609 #if sslcontext
608
610
609 $ cd test
611 $ cd test
610
612
611 Missing certificate file(s) are detected
613 Missing certificate file(s) are detected
612
614
613 $ hg serve -p $HGPORT --certificate=/missing/certificate \
615 $ hg serve -p $HGPORT --certificate=/missing/certificate \
614 > --config devel.servercafile=$PRIV --config devel.serverrequirecert=true
616 > --config devel.servercafile=$PRIV --config devel.serverrequirecert=true
615 abort: referenced certificate file (*/missing/certificate) does not exist (glob)
617 abort: referenced certificate file (*/missing/certificate) does not exist (glob)
616 [255]
618 [255]
617
619
618 $ hg serve -p $HGPORT --certificate=$PRIV \
620 $ hg serve -p $HGPORT --certificate=$PRIV \
619 > --config devel.servercafile=/missing/cafile --config devel.serverrequirecert=true
621 > --config devel.servercafile=/missing/cafile --config devel.serverrequirecert=true
620 abort: referenced certificate file (*/missing/cafile) does not exist (glob)
622 abort: referenced certificate file (*/missing/cafile) does not exist (glob)
621 [255]
623 [255]
622
624
623 Start hgweb that requires client certificates:
625 Start hgweb that requires client certificates:
624
626
625 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV \
627 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV \
626 > --config devel.servercafile=$PRIV --config devel.serverrequirecert=true
628 > --config devel.servercafile=$PRIV --config devel.serverrequirecert=true
627 $ cat ../hg0.pid >> $DAEMON_PIDS
629 $ cat ../hg0.pid >> $DAEMON_PIDS
628 $ cd ..
630 $ cd ..
629
631
630 without client certificate:
632 without client certificate:
631
633
632 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/
634 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/
633 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
635 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
634 abort: error: *handshake failure* (glob)
636 abort: error: *handshake failure* (glob)
635 [255]
637 [255]
636
638
637 with client certificate:
639 with client certificate:
638
640
639 $ cat << EOT >> $HGRCPATH
641 $ cat << EOT >> $HGRCPATH
640 > [auth]
642 > [auth]
641 > l.prefix = localhost
643 > l.prefix = localhost
642 > l.cert = $CERTSDIR/client-cert.pem
644 > l.cert = $CERTSDIR/client-cert.pem
643 > l.key = $CERTSDIR/client-key.pem
645 > l.key = $CERTSDIR/client-key.pem
644 > EOT
646 > EOT
645
647
646 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
648 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
647 > --config auth.l.key="$CERTSDIR/client-key-decrypted.pem"
649 > --config auth.l.key="$CERTSDIR/client-key-decrypted.pem"
648 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
650 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
649 5fed3813f7f5
651 5fed3813f7f5
650
652
651 $ printf '1234\n' | env P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
653 $ printf '1234\n' | env P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
652 > --config ui.interactive=True --config ui.nontty=True
654 > --config ui.interactive=True --config ui.nontty=True
653 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
655 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
654 passphrase for */client-key.pem: 5fed3813f7f5 (glob)
656 passphrase for */client-key.pem: 5fed3813f7f5 (glob)
655
657
656 $ env P="$CERTSDIR" hg id https://localhost:$HGPORT/
658 $ env P="$CERTSDIR" hg id https://localhost:$HGPORT/
657 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
659 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
658 abort: error: * (glob)
660 abort: error: * (glob)
659 [255]
661 [255]
660
662
661 Missing certficate and key files result in error
663 Missing certficate and key files result in error
662
664
663 $ hg id https://localhost:$HGPORT/ --config auth.l.cert=/missing/cert
665 $ hg id https://localhost:$HGPORT/ --config auth.l.cert=/missing/cert
664 abort: certificate file (*/missing/cert) does not exist; cannot connect to localhost (glob)
666 abort: certificate file (*/missing/cert) does not exist; cannot connect to localhost (glob)
665 (restore missing file or fix references in Mercurial config)
667 (restore missing file or fix references in Mercurial config)
666 [255]
668 [255]
667
669
668 $ hg id https://localhost:$HGPORT/ --config auth.l.key=/missing/key
670 $ hg id https://localhost:$HGPORT/ --config auth.l.key=/missing/key
669 abort: certificate file (*/missing/key) does not exist; cannot connect to localhost (glob)
671 abort: certificate file (*/missing/key) does not exist; cannot connect to localhost (glob)
670 (restore missing file or fix references in Mercurial config)
672 (restore missing file or fix references in Mercurial config)
671 [255]
673 [255]
672
674
673 #endif
675 #endif
@@ -1,540 +1,555 b''
1 #require no-chg
1 #require no-chg
2
2
3 #testcases bundle1 bundle2
3 #testcases bundle1 bundle2
4
4
5 #if bundle1
5 #if bundle1
6 $ cat << EOF >> $HGRCPATH
6 $ cat << EOF >> $HGRCPATH
7 > [devel]
7 > [devel]
8 > # This test is dedicated to interaction through old bundle
8 > # This test is dedicated to interaction through old bundle
9 > legacy.exchange = bundle1
9 > legacy.exchange = bundle1
10 > EOF
10 > EOF
11 #endif
11 #endif
12
12
13 $ hg init test
13 $ hg init test
14 $ cd test
14 $ cd test
15 $ echo a > a
15 $ echo a > a
16 $ hg ci -Ama
16 $ hg ci -Ama
17 adding a
17 adding a
18 $ cd ..
18 $ cd ..
19 $ hg clone test test2
19 $ hg clone test test2
20 updating to branch default
20 updating to branch default
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 $ cd test2
22 $ cd test2
23 $ echo a >> a
23 $ echo a >> a
24 $ hg ci -mb
24 $ hg ci -mb
25 $ req() {
25 $ req() {
26 > hg $1 serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
26 > hg $1 serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
27 > cat hg.pid >> $DAEMON_PIDS
27 > cat hg.pid >> $DAEMON_PIDS
28 > hg --cwd ../test2 push http://localhost:$HGPORT/
28 > hg --cwd ../test2 push http://localhost:$HGPORT/
29 > exitstatus=$?
29 > exitstatus=$?
30 > killdaemons.py
30 > killdaemons.py
31 > echo % serve errors
31 > echo % serve errors
32 > cat errors.log
32 > cat errors.log
33 > return $exitstatus
33 > return $exitstatus
34 > }
34 > }
35 $ cd ../test
35 $ cd ../test
36
36
37 expect ssl error
37 expect ssl error
38
38
39 $ req
39 $ req
40 pushing to http://localhost:$HGPORT/
40 pushing to http://localhost:$HGPORT/
41 searching for changes
41 searching for changes
42 abort: HTTP Error 403: ssl required
42 abort: HTTP Error 403: ssl required
43 % serve errors
43 % serve errors
44 [255]
44 [255]
45
45
46 expect authorization error
46 expect authorization error
47
47
48 $ echo '[web]' > .hg/hgrc
48 $ echo '[web]' > .hg/hgrc
49 $ echo 'push_ssl = false' >> .hg/hgrc
49 $ echo 'push_ssl = false' >> .hg/hgrc
50 $ req
50 $ req
51 pushing to http://localhost:$HGPORT/
51 pushing to http://localhost:$HGPORT/
52 searching for changes
52 searching for changes
53 abort: authorization failed
53 abort: authorization failed
54 % serve errors
54 % serve errors
55 [255]
55 [255]
56
56
57 expect authorization error: must have authorized user
57 expect authorization error: must have authorized user
58
58
59 $ echo 'allow_push = unperson' >> .hg/hgrc
59 $ echo 'allow_push = unperson' >> .hg/hgrc
60 $ req
60 $ req
61 pushing to http://localhost:$HGPORT/
61 pushing to http://localhost:$HGPORT/
62 searching for changes
62 searching for changes
63 abort: authorization failed
63 abort: authorization failed
64 % serve errors
64 % serve errors
65 [255]
65 [255]
66
66
67 expect success
67 expect success
68
68
69 $ cat > $TESTTMP/hook.sh <<'EOF'
69 $ cat > $TESTTMP/hook.sh <<'EOF'
70 > echo "phase-move: $HG_NODE: $HG_OLDPHASE -> $HG_PHASE"
70 > echo "phase-move: $HG_NODE: $HG_OLDPHASE -> $HG_PHASE"
71 > EOF
71 > EOF
72
72
73 #if bundle1
73 #if bundle1
74 $ cat >> .hg/hgrc <<EOF
74 $ cat >> .hg/hgrc <<EOF
75 > allow_push = *
75 > allow_push = *
76 > [hooks]
76 > [hooks]
77 > changegroup = sh -c "printenv.py --line changegroup 0"
77 > changegroup = sh -c "printenv.py --line changegroup 0"
78 > pushkey = sh -c "printenv.py --line pushkey 0"
78 > pushkey = sh -c "printenv.py --line pushkey 0"
79 > txnclose-phase.test = sh $TESTTMP/hook.sh
79 > txnclose-phase.test = sh $TESTTMP/hook.sh
80 > EOF
80 > EOF
81 $ req "--debug --config extensions.blackbox="
81 $ req "--debug --config extensions.blackbox="
82 listening at http://*:$HGPORT/ (bound to $LOCALIP:$HGPORT) (glob) (?)
82 listening at http://*:$HGPORT/ (bound to $LOCALIP:$HGPORT) (glob) (?)
83 pushing to http://localhost:$HGPORT/
83 pushing to http://localhost:$HGPORT/
84 searching for changes
84 searching for changes
85 remote: redirecting incoming bundle to */hg-unbundle-* (glob)
85 remote: redirecting incoming bundle to */hg-unbundle-* (glob)
86 remote: adding changesets
86 remote: adding changesets
87 remote: add changeset ba677d0156c1
87 remote: add changeset ba677d0156c1
88 remote: adding manifests
88 remote: adding manifests
89 remote: adding file changes
89 remote: adding file changes
90 remote: adding a revisions
90 remote: adding a revisions
91 remote: added 1 changesets with 1 changes to 1 files
91 remote: added 1 changesets with 1 changes to 1 files
92 remote: updating the branch cache
92 remote: updating the branch cache
93 remote: running hook txnclose-phase.test: sh $TESTTMP/hook.sh
93 remote: running hook txnclose-phase.test: sh $TESTTMP/hook.sh
94 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
94 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
95 remote: running hook txnclose-phase.test: sh $TESTTMP/hook.sh
95 remote: running hook txnclose-phase.test: sh $TESTTMP/hook.sh
96 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
96 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
97 remote: running hook changegroup: sh -c "printenv.py --line changegroup 0"
97 remote: running hook changegroup: sh -c "printenv.py --line changegroup 0"
98 remote: changegroup hook: HG_HOOKNAME=changegroup
98 remote: changegroup hook: HG_HOOKNAME=changegroup
99 remote: HG_HOOKTYPE=changegroup
99 remote: HG_HOOKTYPE=changegroup
100 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
100 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
101 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
101 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
102 remote: HG_SOURCE=serve
102 remote: HG_SOURCE=serve
103 remote: HG_TXNID=TXN:$ID$
103 remote: HG_TXNID=TXN:$ID$
104 remote: HG_TXNNAME=serve
105 remote: remote:http:$LOCALIP: (glob)
104 remote: HG_URL=remote:http:$LOCALIP: (glob)
106 remote: HG_URL=remote:http:$LOCALIP: (glob)
105 remote:
107 remote:
106 % serve errors
108 % serve errors
107 $ hg rollback
109 $ hg rollback
108 repository tip rolled back to revision 0 (undo serve)
110 repository tip rolled back to revision 0 (undo serve)
109 $ req "--debug --config server.streamunbundle=True --config extensions.blackbox="
111 $ req "--debug --config server.streamunbundle=True --config extensions.blackbox="
110 listening at http://*:$HGPORT/ (bound to $LOCALIP:$HGPORT) (glob) (?)
112 listening at http://*:$HGPORT/ (bound to $LOCALIP:$HGPORT) (glob) (?)
111 pushing to http://localhost:$HGPORT/
113 pushing to http://localhost:$HGPORT/
112 searching for changes
114 searching for changes
113 remote: adding changesets
115 remote: adding changesets
114 remote: add changeset ba677d0156c1
116 remote: add changeset ba677d0156c1
115 remote: adding manifests
117 remote: adding manifests
116 remote: adding file changes
118 remote: adding file changes
117 remote: adding a revisions
119 remote: adding a revisions
118 remote: added 1 changesets with 1 changes to 1 files
120 remote: added 1 changesets with 1 changes to 1 files
119 remote: updating the branch cache
121 remote: updating the branch cache
120 remote: running hook txnclose-phase.test: sh $TESTTMP/hook.sh
122 remote: running hook txnclose-phase.test: sh $TESTTMP/hook.sh
121 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
123 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
122 remote: running hook txnclose-phase.test: sh $TESTTMP/hook.sh
124 remote: running hook txnclose-phase.test: sh $TESTTMP/hook.sh
123 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
125 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
124 remote: running hook changegroup: sh -c "printenv.py --line changegroup 0"
126 remote: running hook changegroup: sh -c "printenv.py --line changegroup 0"
125 remote: changegroup hook: HG_HOOKNAME=changegroup
127 remote: changegroup hook: HG_HOOKNAME=changegroup
126 remote: HG_HOOKTYPE=changegroup
128 remote: HG_HOOKTYPE=changegroup
127 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
129 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
128 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
130 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
129 remote: HG_SOURCE=serve
131 remote: HG_SOURCE=serve
130 remote: HG_TXNID=TXN:$ID$
132 remote: HG_TXNID=TXN:$ID$
133 remote: HG_TXNNAME=serve
134 remote: remote:http:$LOCALIP: (glob)
131 remote: HG_URL=remote:http:$LOCALIP: (glob)
135 remote: HG_URL=remote:http:$LOCALIP: (glob)
132 remote:
136 remote:
133 % serve errors
137 % serve errors
134 $ hg rollback
138 $ hg rollback
135 repository tip rolled back to revision 0 (undo serve)
139 repository tip rolled back to revision 0 (undo serve)
136 #endif
140 #endif
137
141
138 #if bundle2
142 #if bundle2
139 $ cat >> .hg/hgrc <<EOF
143 $ cat >> .hg/hgrc <<EOF
140 > allow_push = *
144 > allow_push = *
141 > [hooks]
145 > [hooks]
142 > changegroup = sh -c "printenv.py --line changegroup 0"
146 > changegroup = sh -c "printenv.py --line changegroup 0"
143 > pushkey = sh -c "printenv.py --line pushkey 0"
147 > pushkey = sh -c "printenv.py --line pushkey 0"
144 > txnclose-phase.test = sh $TESTTMP/hook.sh
148 > txnclose-phase.test = sh $TESTTMP/hook.sh
145 > EOF
149 > EOF
146 $ req
150 $ req
147 pushing to http://localhost:$HGPORT/
151 pushing to http://localhost:$HGPORT/
148 searching for changes
152 searching for changes
149 remote: adding changesets
153 remote: adding changesets
150 remote: adding manifests
154 remote: adding manifests
151 remote: adding file changes
155 remote: adding file changes
152 remote: added 1 changesets with 1 changes to 1 files
156 remote: added 1 changesets with 1 changes to 1 files
153 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
157 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
154 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
158 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
155 remote: changegroup hook: HG_BUNDLE2=1
159 remote: changegroup hook: HG_BUNDLE2=1
156 remote: HG_HOOKNAME=changegroup
160 remote: HG_HOOKNAME=changegroup
157 remote: HG_HOOKTYPE=changegroup
161 remote: HG_HOOKTYPE=changegroup
158 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
162 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
159 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
163 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
160 remote: HG_SOURCE=serve
164 remote: HG_SOURCE=serve
161 remote: HG_TXNID=TXN:$ID$
165 remote: HG_TXNID=TXN:$ID$
166 remote: HG_TXNNAME=serve
162 remote: HG_URL=remote:http:$LOCALIP: (glob)
167 remote: HG_URL=remote:http:$LOCALIP: (glob)
163 remote:
168 remote:
164 % serve errors
169 % serve errors
165 $ hg rollback
170 $ hg rollback
166 repository tip rolled back to revision 0 (undo serve)
171 repository tip rolled back to revision 0 (undo serve)
167 #endif
172 #endif
168
173
169 expect success, server lacks the httpheader capability
174 expect success, server lacks the httpheader capability
170
175
171 $ CAP=httpheader
176 $ CAP=httpheader
172 $ . "$TESTDIR/notcapable"
177 $ . "$TESTDIR/notcapable"
173 $ req
178 $ req
174 pushing to http://localhost:$HGPORT/
179 pushing to http://localhost:$HGPORT/
175 searching for changes
180 searching for changes
176 remote: adding changesets
181 remote: adding changesets
177 remote: adding manifests
182 remote: adding manifests
178 remote: adding file changes
183 remote: adding file changes
179 remote: added 1 changesets with 1 changes to 1 files
184 remote: added 1 changesets with 1 changes to 1 files
180 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
185 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
181 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
186 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
182 remote: changegroup hook: HG_HOOKNAME=changegroup (no-bundle2 !)
187 remote: changegroup hook: HG_HOOKNAME=changegroup (no-bundle2 !)
183 remote: changegroup hook: HG_BUNDLE2=1 (bundle2 !)
188 remote: changegroup hook: HG_BUNDLE2=1 (bundle2 !)
184 remote: HG_HOOKNAME=changegroup (bundle2 !)
189 remote: HG_HOOKNAME=changegroup (bundle2 !)
185 remote: HG_HOOKTYPE=changegroup
190 remote: HG_HOOKTYPE=changegroup
186 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
191 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
187 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
192 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
188 remote: HG_SOURCE=serve
193 remote: HG_SOURCE=serve
189 remote: HG_TXNID=TXN:$ID$
194 remote: HG_TXNID=TXN:$ID$
195 remote: HG_TXNNAME=serve
196 remote: remote:http:$LOCALIP: (glob) (no-bundle2 !)
190 remote: HG_URL=remote:http:$LOCALIP: (glob)
197 remote: HG_URL=remote:http:$LOCALIP: (glob)
191 remote:
198 remote:
192 % serve errors
199 % serve errors
193 $ hg rollback
200 $ hg rollback
194 repository tip rolled back to revision 0 (undo serve)
201 repository tip rolled back to revision 0 (undo serve)
195
202
196 expect success, server lacks the unbundlehash capability
203 expect success, server lacks the unbundlehash capability
197
204
198 $ CAP=unbundlehash
205 $ CAP=unbundlehash
199 $ . "$TESTDIR/notcapable"
206 $ . "$TESTDIR/notcapable"
200 $ req
207 $ req
201 pushing to http://localhost:$HGPORT/
208 pushing to http://localhost:$HGPORT/
202 searching for changes
209 searching for changes
203 remote: adding changesets
210 remote: adding changesets
204 remote: adding manifests
211 remote: adding manifests
205 remote: adding file changes
212 remote: adding file changes
206 remote: added 1 changesets with 1 changes to 1 files
213 remote: added 1 changesets with 1 changes to 1 files
207 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
214 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
208 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
215 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
209 remote: changegroup hook: HG_HOOKNAME=changegroup (no-bundle2 !)
216 remote: changegroup hook: HG_HOOKNAME=changegroup (no-bundle2 !)
210 remote: changegroup hook: HG_BUNDLE2=1 (bundle2 !)
217 remote: changegroup hook: HG_BUNDLE2=1 (bundle2 !)
211 remote: HG_HOOKNAME=changegroup (bundle2 !)
218 remote: HG_HOOKNAME=changegroup (bundle2 !)
212 remote: HG_HOOKTYPE=changegroup
219 remote: HG_HOOKTYPE=changegroup
213 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
220 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
214 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
221 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
215 remote: HG_SOURCE=serve
222 remote: HG_SOURCE=serve
216 remote: HG_TXNID=TXN:$ID$
223 remote: HG_TXNID=TXN:$ID$
224 remote: HG_TXNNAME=serve
225 remote: remote:http:$LOCALIP: (glob) (no-bundle2 !)
217 remote: HG_URL=remote:http:$LOCALIP: (glob)
226 remote: HG_URL=remote:http:$LOCALIP: (glob)
218 remote:
227 remote:
219 % serve errors
228 % serve errors
220 $ hg rollback
229 $ hg rollback
221 repository tip rolled back to revision 0 (undo serve)
230 repository tip rolled back to revision 0 (undo serve)
222
231
223 expect success, pre-d1b16a746db6 server supports the unbundle capability, but
232 expect success, pre-d1b16a746db6 server supports the unbundle capability, but
224 has no parameter
233 has no parameter
225
234
226 $ cat <<EOF > notcapable-unbundleparam.py
235 $ cat <<EOF > notcapable-unbundleparam.py
227 > from mercurial import extensions, httppeer
236 > from mercurial import extensions, httppeer
228 > def capable(orig, self, name):
237 > def capable(orig, self, name):
229 > if name == 'unbundle':
238 > if name == 'unbundle':
230 > return True
239 > return True
231 > return orig(self, name)
240 > return orig(self, name)
232 > def uisetup(ui):
241 > def uisetup(ui):
233 > extensions.wrapfunction(httppeer.httppeer, 'capable', capable)
242 > extensions.wrapfunction(httppeer.httppeer, 'capable', capable)
234 > EOF
243 > EOF
235 $ cp $HGRCPATH $HGRCPATH.orig
244 $ cp $HGRCPATH $HGRCPATH.orig
236 $ cat <<EOF >> $HGRCPATH
245 $ cat <<EOF >> $HGRCPATH
237 > [extensions]
246 > [extensions]
238 > notcapable-unbundleparam = `pwd`/notcapable-unbundleparam.py
247 > notcapable-unbundleparam = `pwd`/notcapable-unbundleparam.py
239 > EOF
248 > EOF
240 $ req
249 $ req
241 pushing to http://localhost:$HGPORT/
250 pushing to http://localhost:$HGPORT/
242 searching for changes
251 searching for changes
243 remote: adding changesets
252 remote: adding changesets
244 remote: adding manifests
253 remote: adding manifests
245 remote: adding file changes
254 remote: adding file changes
246 remote: added 1 changesets with 1 changes to 1 files
255 remote: added 1 changesets with 1 changes to 1 files
247 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
256 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: draft -> public
248 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
257 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> public
249 remote: changegroup hook: * (glob)
258 remote: changegroup hook: * (glob)
250 remote: HG_HOOKNAME=changegroup (bundle2 !)
259 remote: HG_HOOKNAME=changegroup (bundle2 !)
251 remote: HG_HOOKTYPE=changegroup
260 remote: HG_HOOKTYPE=changegroup
252 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
261 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
253 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
262 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
254 remote: HG_SOURCE=serve
263 remote: HG_SOURCE=serve
255 remote: HG_TXNID=TXN:$ID$
264 remote: HG_TXNID=TXN:$ID$
265 remote: HG_TXNNAME=serve
266 remote: remote:http:$LOCALIP: (glob) (no-bundle2 !)
256 remote: HG_URL=remote:http:$LOCALIP: (glob)
267 remote: HG_URL=remote:http:$LOCALIP: (glob)
257 remote:
268 remote:
258 % serve errors
269 % serve errors
259 $ hg rollback
270 $ hg rollback
260 repository tip rolled back to revision 0 (undo serve)
271 repository tip rolled back to revision 0 (undo serve)
261 $ mv $HGRCPATH.orig $HGRCPATH
272 $ mv $HGRCPATH.orig $HGRCPATH
262
273
263 Test pushing to a publishing repository with a failing prepushkey hook
274 Test pushing to a publishing repository with a failing prepushkey hook
264
275
265 $ cat > .hg/hgrc <<EOF
276 $ cat > .hg/hgrc <<EOF
266 > [web]
277 > [web]
267 > push_ssl = false
278 > push_ssl = false
268 > allow_push = *
279 > allow_push = *
269 > [hooks]
280 > [hooks]
270 > prepushkey = sh -c "printenv.py --line prepushkey 1"
281 > prepushkey = sh -c "printenv.py --line prepushkey 1"
271 > [devel]
282 > [devel]
272 > legacy.exchange=phases
283 > legacy.exchange=phases
273 > EOF
284 > EOF
274
285
275 #if bundle1
286 #if bundle1
276 Bundle1 works because a) phases are updated as part of changegroup application
287 Bundle1 works because a) phases are updated as part of changegroup application
277 and b) client checks phases after the "unbundle" command. Since it sees no
288 and b) client checks phases after the "unbundle" command. Since it sees no
278 phase changes are necessary, it doesn't send the "pushkey" command and the
289 phase changes are necessary, it doesn't send the "pushkey" command and the
279 prepushkey hook never has to fire.
290 prepushkey hook never has to fire.
280
291
281 $ req
292 $ req
282 pushing to http://localhost:$HGPORT/
293 pushing to http://localhost:$HGPORT/
283 searching for changes
294 searching for changes
284 remote: adding changesets
295 remote: adding changesets
285 remote: adding manifests
296 remote: adding manifests
286 remote: adding file changes
297 remote: adding file changes
287 remote: added 1 changesets with 1 changes to 1 files
298 remote: added 1 changesets with 1 changes to 1 files
288 % serve errors
299 % serve errors
289
300
290 #endif
301 #endif
291
302
292 #if bundle2
303 #if bundle2
293 Bundle2 sends a "pushkey" bundle2 part. This runs as part of the transaction
304 Bundle2 sends a "pushkey" bundle2 part. This runs as part of the transaction
294 and fails the entire push.
305 and fails the entire push.
295 $ req
306 $ req
296 pushing to http://localhost:$HGPORT/
307 pushing to http://localhost:$HGPORT/
297 searching for changes
308 searching for changes
298 remote: adding changesets
309 remote: adding changesets
299 remote: adding manifests
310 remote: adding manifests
300 remote: adding file changes
311 remote: adding file changes
301 remote: added 1 changesets with 1 changes to 1 files
312 remote: added 1 changesets with 1 changes to 1 files
302 remote: prepushkey hook: HG_BUNDLE2=1
313 remote: prepushkey hook: HG_BUNDLE2=1
303 remote: HG_HOOKNAME=prepushkey
314 remote: HG_HOOKNAME=prepushkey
304 remote: HG_HOOKTYPE=prepushkey
315 remote: HG_HOOKTYPE=prepushkey
305 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
316 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
306 remote: HG_NAMESPACE=phases
317 remote: HG_NAMESPACE=phases
307 remote: HG_NEW=0
318 remote: HG_NEW=0
308 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
319 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
309 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
320 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
310 remote: HG_OLD=1
321 remote: HG_OLD=1
311 remote: HG_PENDING=$TESTTMP/test
322 remote: HG_PENDING=$TESTTMP/test
312 remote: HG_PHASES_MOVED=1
323 remote: HG_PHASES_MOVED=1
313 remote: HG_SOURCE=serve
324 remote: HG_SOURCE=serve
314 remote: HG_TXNID=TXN:$ID$
325 remote: HG_TXNID=TXN:$ID$
326 remote: HG_TXNNAME=serve
315 remote: HG_URL=remote:http:$LOCALIP: (glob)
327 remote: HG_URL=remote:http:$LOCALIP: (glob)
316 remote:
328 remote:
317 remote: pushkey-abort: prepushkey hook exited with status 1
329 remote: pushkey-abort: prepushkey hook exited with status 1
318 remote: transaction abort!
330 remote: transaction abort!
319 remote: rollback completed
331 remote: rollback completed
320 abort: updating ba677d0156c1 to public failed
332 abort: updating ba677d0156c1 to public failed
321 % serve errors
333 % serve errors
322 [255]
334 [255]
323
335
324 #endif
336 #endif
325
337
326 Now remove the failing prepushkey hook.
338 Now remove the failing prepushkey hook.
327
339
328 $ cat >> .hg/hgrc <<EOF
340 $ cat >> .hg/hgrc <<EOF
329 > [hooks]
341 > [hooks]
330 > prepushkey = sh -c "printenv.py --line prepushkey 0"
342 > prepushkey = sh -c "printenv.py --line prepushkey 0"
331 > EOF
343 > EOF
332
344
333 We don't need to test bundle1 because it succeeded above.
345 We don't need to test bundle1 because it succeeded above.
334
346
335 #if bundle2
347 #if bundle2
336 $ req
348 $ req
337 pushing to http://localhost:$HGPORT/
349 pushing to http://localhost:$HGPORT/
338 searching for changes
350 searching for changes
339 remote: adding changesets
351 remote: adding changesets
340 remote: adding manifests
352 remote: adding manifests
341 remote: adding file changes
353 remote: adding file changes
342 remote: added 1 changesets with 1 changes to 1 files
354 remote: added 1 changesets with 1 changes to 1 files
343 remote: prepushkey hook: HG_BUNDLE2=1
355 remote: prepushkey hook: HG_BUNDLE2=1
344 remote: HG_HOOKNAME=prepushkey
356 remote: HG_HOOKNAME=prepushkey
345 remote: HG_HOOKTYPE=prepushkey
357 remote: HG_HOOKTYPE=prepushkey
346 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
358 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
347 remote: HG_NAMESPACE=phases
359 remote: HG_NAMESPACE=phases
348 remote: HG_NEW=0
360 remote: HG_NEW=0
349 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
361 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
350 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
362 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
351 remote: HG_OLD=1
363 remote: HG_OLD=1
352 remote: HG_PENDING=$TESTTMP/test
364 remote: HG_PENDING=$TESTTMP/test
353 remote: HG_PHASES_MOVED=1
365 remote: HG_PHASES_MOVED=1
354 remote: HG_SOURCE=serve
366 remote: HG_SOURCE=serve
355 remote: HG_TXNID=TXN:$ID$
367 remote: HG_TXNID=TXN:$ID$
368 remote: HG_TXNNAME=serve
356 remote: HG_URL=remote:http:$LOCALIP: (glob)
369 remote: HG_URL=remote:http:$LOCALIP: (glob)
357 remote:
370 remote:
358 % serve errors
371 % serve errors
359 #endif
372 #endif
360
373
361 $ hg --config extensions.strip= strip -r 1:
374 $ hg --config extensions.strip= strip -r 1:
362 saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
375 saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
363
376
364 Now do a variant of the above, except on a non-publishing repository
377 Now do a variant of the above, except on a non-publishing repository
365
378
366 $ cat >> .hg/hgrc <<EOF
379 $ cat >> .hg/hgrc <<EOF
367 > [phases]
380 > [phases]
368 > publish = false
381 > publish = false
369 > [hooks]
382 > [hooks]
370 > prepushkey = sh -c "printenv.py --line prepushkey 1"
383 > prepushkey = sh -c "printenv.py --line prepushkey 1"
371 > EOF
384 > EOF
372
385
373 #if bundle1
386 #if bundle1
374 $ req
387 $ req
375 pushing to http://localhost:$HGPORT/
388 pushing to http://localhost:$HGPORT/
376 searching for changes
389 searching for changes
377 remote: adding changesets
390 remote: adding changesets
378 remote: adding manifests
391 remote: adding manifests
379 remote: adding file changes
392 remote: adding file changes
380 remote: added 1 changesets with 1 changes to 1 files
393 remote: added 1 changesets with 1 changes to 1 files
381 remote: prepushkey hook: HG_HOOKNAME=prepushkey
394 remote: prepushkey hook: HG_HOOKNAME=prepushkey
382 remote: HG_HOOKTYPE=prepushkey
395 remote: HG_HOOKTYPE=prepushkey
383 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
396 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
384 remote: HG_NAMESPACE=phases
397 remote: HG_NAMESPACE=phases
385 remote: HG_NEW=0
398 remote: HG_NEW=0
386 remote: HG_OLD=1
399 remote: HG_OLD=1
387 remote:
400 remote:
388 remote: pushkey-abort: prepushkey hook exited with status 1
401 remote: pushkey-abort: prepushkey hook exited with status 1
389 updating ba677d0156c1 to public failed!
402 updating ba677d0156c1 to public failed!
390 % serve errors
403 % serve errors
391 #endif
404 #endif
392
405
393 #if bundle2
406 #if bundle2
394 $ req
407 $ req
395 pushing to http://localhost:$HGPORT/
408 pushing to http://localhost:$HGPORT/
396 searching for changes
409 searching for changes
397 remote: adding changesets
410 remote: adding changesets
398 remote: adding manifests
411 remote: adding manifests
399 remote: adding file changes
412 remote: adding file changes
400 remote: added 1 changesets with 1 changes to 1 files
413 remote: added 1 changesets with 1 changes to 1 files
401 remote: prepushkey hook: HG_BUNDLE2=1
414 remote: prepushkey hook: HG_BUNDLE2=1
402 remote: HG_HOOKNAME=prepushkey
415 remote: HG_HOOKNAME=prepushkey
403 remote: HG_HOOKTYPE=prepushkey
416 remote: HG_HOOKTYPE=prepushkey
404 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
417 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
405 remote: HG_NAMESPACE=phases
418 remote: HG_NAMESPACE=phases
406 remote: HG_NEW=0
419 remote: HG_NEW=0
407 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
420 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
408 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
421 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
409 remote: HG_OLD=1
422 remote: HG_OLD=1
410 remote: HG_PENDING=$TESTTMP/test
423 remote: HG_PENDING=$TESTTMP/test
411 remote: HG_PHASES_MOVED=1
424 remote: HG_PHASES_MOVED=1
412 remote: HG_SOURCE=serve
425 remote: HG_SOURCE=serve
413 remote: HG_TXNID=TXN:$ID$
426 remote: HG_TXNID=TXN:$ID$
427 remote: HG_TXNNAME=serve
414 remote: HG_URL=remote:http:$LOCALIP: (glob)
428 remote: HG_URL=remote:http:$LOCALIP: (glob)
415 remote:
429 remote:
416 remote: pushkey-abort: prepushkey hook exited with status 1
430 remote: pushkey-abort: prepushkey hook exited with status 1
417 remote: transaction abort!
431 remote: transaction abort!
418 remote: rollback completed
432 remote: rollback completed
419 abort: updating ba677d0156c1 to public failed
433 abort: updating ba677d0156c1 to public failed
420 % serve errors
434 % serve errors
421 [255]
435 [255]
422 #endif
436 #endif
423
437
424 Make phases updates work
438 Make phases updates work
425
439
426 $ cat >> .hg/hgrc <<EOF
440 $ cat >> .hg/hgrc <<EOF
427 > [hooks]
441 > [hooks]
428 > prepushkey = sh -c "printenv.py --line prepushkey 0"
442 > prepushkey = sh -c "printenv.py --line prepushkey 0"
429 > EOF
443 > EOF
430
444
431 #if bundle1
445 #if bundle1
432 $ req
446 $ req
433 pushing to http://localhost:$HGPORT/
447 pushing to http://localhost:$HGPORT/
434 searching for changes
448 searching for changes
435 no changes found
449 no changes found
436 remote: prepushkey hook: HG_HOOKNAME=prepushkey
450 remote: prepushkey hook: HG_HOOKNAME=prepushkey
437 remote: HG_HOOKTYPE=prepushkey
451 remote: HG_HOOKTYPE=prepushkey
438 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
452 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
439 remote: HG_NAMESPACE=phases
453 remote: HG_NAMESPACE=phases
440 remote: HG_NEW=0
454 remote: HG_NEW=0
441 remote: HG_OLD=1
455 remote: HG_OLD=1
442 remote:
456 remote:
443 % serve errors
457 % serve errors
444 [1]
458 [1]
445 #endif
459 #endif
446
460
447 #if bundle2
461 #if bundle2
448 $ req
462 $ req
449 pushing to http://localhost:$HGPORT/
463 pushing to http://localhost:$HGPORT/
450 searching for changes
464 searching for changes
451 remote: adding changesets
465 remote: adding changesets
452 remote: adding manifests
466 remote: adding manifests
453 remote: adding file changes
467 remote: adding file changes
454 remote: added 1 changesets with 1 changes to 1 files
468 remote: added 1 changesets with 1 changes to 1 files
455 remote: prepushkey hook: HG_BUNDLE2=1
469 remote: prepushkey hook: HG_BUNDLE2=1
456 remote: HG_HOOKNAME=prepushkey
470 remote: HG_HOOKNAME=prepushkey
457 remote: HG_HOOKTYPE=prepushkey
471 remote: HG_HOOKTYPE=prepushkey
458 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
472 remote: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872
459 remote: HG_NAMESPACE=phases
473 remote: HG_NAMESPACE=phases
460 remote: HG_NEW=0
474 remote: HG_NEW=0
461 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
475 remote: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872
462 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
476 remote: HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872
463 remote: HG_OLD=1
477 remote: HG_OLD=1
464 remote: HG_PENDING=$TESTTMP/test
478 remote: HG_PENDING=$TESTTMP/test
465 remote: HG_PHASES_MOVED=1
479 remote: HG_PHASES_MOVED=1
466 remote: HG_SOURCE=serve
480 remote: HG_SOURCE=serve
467 remote: HG_TXNID=TXN:$ID$
481 remote: HG_TXNID=TXN:$ID$
482 remote: HG_TXNNAME=serve
468 remote: HG_URL=remote:http:$LOCALIP: (glob)
483 remote: HG_URL=remote:http:$LOCALIP: (glob)
469 remote:
484 remote:
470 % serve errors
485 % serve errors
471 #endif
486 #endif
472
487
473 $ hg --config extensions.strip= strip -r 1:
488 $ hg --config extensions.strip= strip -r 1:
474 saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
489 saved backup bundle to $TESTTMP/test/.hg/strip-backup/ba677d0156c1-eea704d7-backup.hg
475
490
476 #if bundle2
491 #if bundle2
477
492
478 $ cat > .hg/hgrc <<EOF
493 $ cat > .hg/hgrc <<EOF
479 > [web]
494 > [web]
480 > push_ssl = false
495 > push_ssl = false
481 > allow_push = *
496 > allow_push = *
482 > [experimental]
497 > [experimental]
483 > httppostargs=true
498 > httppostargs=true
484 > EOF
499 > EOF
485 $ req
500 $ req
486 pushing to http://localhost:$HGPORT/
501 pushing to http://localhost:$HGPORT/
487 searching for changes
502 searching for changes
488 remote: adding changesets
503 remote: adding changesets
489 remote: adding manifests
504 remote: adding manifests
490 remote: adding file changes
505 remote: adding file changes
491 remote: added 1 changesets with 1 changes to 1 files
506 remote: added 1 changesets with 1 changes to 1 files
492 % serve errors
507 % serve errors
493
508
494 #endif
509 #endif
495
510
496 $ cd ..
511 $ cd ..
497
512
498 Pushing via hgwebdir works
513 Pushing via hgwebdir works
499
514
500 $ hg init hgwebdir
515 $ hg init hgwebdir
501 $ cd hgwebdir
516 $ cd hgwebdir
502 $ echo 0 > a
517 $ echo 0 > a
503 $ hg -q commit -A -m initial
518 $ hg -q commit -A -m initial
504 $ cd ..
519 $ cd ..
505
520
506 $ cat > web.conf << EOF
521 $ cat > web.conf << EOF
507 > [paths]
522 > [paths]
508 > / = *
523 > / = *
509 > [web]
524 > [web]
510 > push_ssl = false
525 > push_ssl = false
511 > allow_push = *
526 > allow_push = *
512 > EOF
527 > EOF
513
528
514 $ hg serve --web-conf web.conf -p $HGPORT -d --pid-file hg.pid
529 $ hg serve --web-conf web.conf -p $HGPORT -d --pid-file hg.pid
515 $ cat hg.pid >> $DAEMON_PIDS
530 $ cat hg.pid >> $DAEMON_PIDS
516
531
517 $ hg clone http://localhost:$HGPORT/hgwebdir hgwebdir-local
532 $ hg clone http://localhost:$HGPORT/hgwebdir hgwebdir-local
518 requesting all changes
533 requesting all changes
519 adding changesets
534 adding changesets
520 adding manifests
535 adding manifests
521 adding file changes
536 adding file changes
522 added 1 changesets with 1 changes to 1 files
537 added 1 changesets with 1 changes to 1 files
523 new changesets 98a3f8f02ba7
538 new changesets 98a3f8f02ba7
524 updating to branch default
539 updating to branch default
525 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
540 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
526 $ cd hgwebdir-local
541 $ cd hgwebdir-local
527 $ echo commit > a
542 $ echo commit > a
528 $ hg commit -m 'local commit'
543 $ hg commit -m 'local commit'
529
544
530 $ hg push
545 $ hg push
531 pushing to http://localhost:$HGPORT/hgwebdir
546 pushing to http://localhost:$HGPORT/hgwebdir
532 searching for changes
547 searching for changes
533 remote: adding changesets
548 remote: adding changesets
534 remote: adding manifests
549 remote: adding manifests
535 remote: adding file changes
550 remote: adding file changes
536 remote: added 1 changesets with 1 changes to 1 files
551 remote: added 1 changesets with 1 changes to 1 files
537
552
538 $ killdaemons.py
553 $ killdaemons.py
539
554
540 $ cd ..
555 $ cd ..
@@ -1,603 +1,609 b''
1 This test is a duplicate of 'test-http.t' feel free to factor out
1 This test is a duplicate of 'test-http.t' feel free to factor out
2 parts that are not bundle1/bundle2 specific.
2 parts that are not bundle1/bundle2 specific.
3
3
4 #testcases sshv1 sshv2
4 #testcases sshv1 sshv2
5
5
6 #if sshv2
6 #if sshv2
7 $ cat >> $HGRCPATH << EOF
7 $ cat >> $HGRCPATH << EOF
8 > [experimental]
8 > [experimental]
9 > sshpeer.advertise-v2 = true
9 > sshpeer.advertise-v2 = true
10 > sshserver.support-v2 = true
10 > sshserver.support-v2 = true
11 > EOF
11 > EOF
12 #endif
12 #endif
13
13
14 $ cat << EOF >> $HGRCPATH
14 $ cat << EOF >> $HGRCPATH
15 > [devel]
15 > [devel]
16 > # This test is dedicated to interaction through old bundle
16 > # This test is dedicated to interaction through old bundle
17 > legacy.exchange = bundle1
17 > legacy.exchange = bundle1
18 > EOF
18 > EOF
19
19
20
20
21 This test tries to exercise the ssh functionality with a dummy script
21 This test tries to exercise the ssh functionality with a dummy script
22
22
23 creating 'remote' repo
23 creating 'remote' repo
24
24
25 $ hg init remote
25 $ hg init remote
26 $ cd remote
26 $ cd remote
27 $ echo this > foo
27 $ echo this > foo
28 $ echo this > fooO
28 $ echo this > fooO
29 $ hg ci -A -m "init" foo fooO
29 $ hg ci -A -m "init" foo fooO
30
30
31 insert a closed branch (issue4428)
31 insert a closed branch (issue4428)
32
32
33 $ hg up null
33 $ hg up null
34 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
34 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
35 $ hg branch closed
35 $ hg branch closed
36 marked working directory as branch closed
36 marked working directory as branch closed
37 (branches are permanent and global, did you want a bookmark?)
37 (branches are permanent and global, did you want a bookmark?)
38 $ hg ci -mc0
38 $ hg ci -mc0
39 $ hg ci --close-branch -mc1
39 $ hg ci --close-branch -mc1
40 $ hg up -q default
40 $ hg up -q default
41
41
42 configure for serving
42 configure for serving
43
43
44 $ cat <<EOF > .hg/hgrc
44 $ cat <<EOF > .hg/hgrc
45 > [server]
45 > [server]
46 > uncompressed = True
46 > uncompressed = True
47 >
47 >
48 > [hooks]
48 > [hooks]
49 > changegroup = sh -c "printenv.py --line changegroup-in-remote 0 ../dummylog"
49 > changegroup = sh -c "printenv.py --line changegroup-in-remote 0 ../dummylog"
50 > EOF
50 > EOF
51 $ cd $TESTTMP
51 $ cd $TESTTMP
52
52
53 repo not found error
53 repo not found error
54
54
55 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
55 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
56 remote: abort: repository nonexistent not found!
56 remote: abort: repository nonexistent not found!
57 abort: no suitable response from remote hg!
57 abort: no suitable response from remote hg!
58 [255]
58 [255]
59
59
60 non-existent absolute path
60 non-existent absolute path
61
61
62 #if no-msys
62 #if no-msys
63 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
63 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
64 remote: abort: repository /$TESTTMP/nonexistent not found!
64 remote: abort: repository /$TESTTMP/nonexistent not found!
65 abort: no suitable response from remote hg!
65 abort: no suitable response from remote hg!
66 [255]
66 [255]
67 #endif
67 #endif
68
68
69 clone remote via stream
69 clone remote via stream
70
70
71 #if no-reposimplestore
71 #if no-reposimplestore
72
72
73 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --stream ssh://user@dummy/remote local-stream
73 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --stream ssh://user@dummy/remote local-stream
74 streaming all changes
74 streaming all changes
75 4 files to transfer, 602 bytes of data
75 4 files to transfer, 602 bytes of data
76 transferred 602 bytes in * seconds (*) (glob)
76 transferred 602 bytes in * seconds (*) (glob)
77 searching for changes
77 searching for changes
78 no changes found
78 no changes found
79 updating to branch default
79 updating to branch default
80 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
81 $ cd local-stream
81 $ cd local-stream
82 $ hg verify
82 $ hg verify
83 checking changesets
83 checking changesets
84 checking manifests
84 checking manifests
85 crosschecking files in changesets and manifests
85 crosschecking files in changesets and manifests
86 checking files
86 checking files
87 checked 3 changesets with 2 changes to 2 files
87 checked 3 changesets with 2 changes to 2 files
88 $ hg branches
88 $ hg branches
89 default 0:1160648e36ce
89 default 0:1160648e36ce
90 $ cd $TESTTMP
90 $ cd $TESTTMP
91
91
92 clone bookmarks via stream
92 clone bookmarks via stream
93
93
94 $ hg -R local-stream book mybook
94 $ hg -R local-stream book mybook
95 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --stream ssh://user@dummy/local-stream stream2
95 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --stream ssh://user@dummy/local-stream stream2
96 streaming all changes
96 streaming all changes
97 4 files to transfer, 602 bytes of data
97 4 files to transfer, 602 bytes of data
98 transferred 602 bytes in * seconds (*) (glob)
98 transferred 602 bytes in * seconds (*) (glob)
99 searching for changes
99 searching for changes
100 no changes found
100 no changes found
101 updating to branch default
101 updating to branch default
102 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 $ cd stream2
103 $ cd stream2
104 $ hg book
104 $ hg book
105 mybook 0:1160648e36ce
105 mybook 0:1160648e36ce
106 $ cd $TESTTMP
106 $ cd $TESTTMP
107 $ rm -rf local-stream stream2
107 $ rm -rf local-stream stream2
108
108
109 #endif
109 #endif
110
110
111 clone remote via pull
111 clone remote via pull
112
112
113 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
113 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
114 requesting all changes
114 requesting all changes
115 adding changesets
115 adding changesets
116 adding manifests
116 adding manifests
117 adding file changes
117 adding file changes
118 added 3 changesets with 2 changes to 2 files
118 added 3 changesets with 2 changes to 2 files
119 new changesets 1160648e36ce:ad076bfb429d
119 new changesets 1160648e36ce:ad076bfb429d
120 updating to branch default
120 updating to branch default
121 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
122
122
123 verify
123 verify
124
124
125 $ cd local
125 $ cd local
126 $ hg verify
126 $ hg verify
127 checking changesets
127 checking changesets
128 checking manifests
128 checking manifests
129 crosschecking files in changesets and manifests
129 crosschecking files in changesets and manifests
130 checking files
130 checking files
131 checked 3 changesets with 2 changes to 2 files
131 checked 3 changesets with 2 changes to 2 files
132 $ cat >> .hg/hgrc <<EOF
132 $ cat >> .hg/hgrc <<EOF
133 > [hooks]
133 > [hooks]
134 > changegroup = sh -c "printenv.py --line changegroup-in-local 0 ../dummylog"
134 > changegroup = sh -c "printenv.py --line changegroup-in-local 0 ../dummylog"
135 > EOF
135 > EOF
136
136
137 empty default pull
137 empty default pull
138
138
139 $ hg paths
139 $ hg paths
140 default = ssh://user@dummy/remote
140 default = ssh://user@dummy/remote
141 $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\""
141 $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\""
142 pulling from ssh://user@dummy/remote
142 pulling from ssh://user@dummy/remote
143 searching for changes
143 searching for changes
144 no changes found
144 no changes found
145
145
146 pull from wrong ssh URL
146 pull from wrong ssh URL
147
147
148 $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
148 $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
149 pulling from ssh://user@dummy/doesnotexist
149 pulling from ssh://user@dummy/doesnotexist
150 remote: abort: repository doesnotexist not found!
150 remote: abort: repository doesnotexist not found!
151 abort: no suitable response from remote hg!
151 abort: no suitable response from remote hg!
152 [255]
152 [255]
153
153
154 local change
154 local change
155
155
156 $ echo bleah > foo
156 $ echo bleah > foo
157 $ hg ci -m "add"
157 $ hg ci -m "add"
158
158
159 updating rc
159 updating rc
160
160
161 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
161 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
162 $ echo "[ui]" >> .hg/hgrc
162 $ echo "[ui]" >> .hg/hgrc
163 $ echo "ssh = \"$PYTHON\" \"$TESTDIR/dummyssh\"" >> .hg/hgrc
163 $ echo "ssh = \"$PYTHON\" \"$TESTDIR/dummyssh\"" >> .hg/hgrc
164
164
165 find outgoing
165 find outgoing
166
166
167 $ hg out ssh://user@dummy/remote
167 $ hg out ssh://user@dummy/remote
168 comparing with ssh://user@dummy/remote
168 comparing with ssh://user@dummy/remote
169 searching for changes
169 searching for changes
170 changeset: 3:a28a9d1a809c
170 changeset: 3:a28a9d1a809c
171 tag: tip
171 tag: tip
172 parent: 0:1160648e36ce
172 parent: 0:1160648e36ce
173 user: test
173 user: test
174 date: Thu Jan 01 00:00:00 1970 +0000
174 date: Thu Jan 01 00:00:00 1970 +0000
175 summary: add
175 summary: add
176
176
177
177
178 find incoming on the remote side
178 find incoming on the remote side
179
179
180 $ hg incoming -R ../remote -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
180 $ hg incoming -R ../remote -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
181 comparing with ssh://user@dummy/local
181 comparing with ssh://user@dummy/local
182 searching for changes
182 searching for changes
183 changeset: 3:a28a9d1a809c
183 changeset: 3:a28a9d1a809c
184 tag: tip
184 tag: tip
185 parent: 0:1160648e36ce
185 parent: 0:1160648e36ce
186 user: test
186 user: test
187 date: Thu Jan 01 00:00:00 1970 +0000
187 date: Thu Jan 01 00:00:00 1970 +0000
188 summary: add
188 summary: add
189
189
190
190
191 find incoming on the remote side (using absolute path)
191 find incoming on the remote side (using absolute path)
192
192
193 $ hg incoming -R ../remote -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
193 $ hg incoming -R ../remote -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
194 comparing with ssh://user@dummy/$TESTTMP/local
194 comparing with ssh://user@dummy/$TESTTMP/local
195 searching for changes
195 searching for changes
196 changeset: 3:a28a9d1a809c
196 changeset: 3:a28a9d1a809c
197 tag: tip
197 tag: tip
198 parent: 0:1160648e36ce
198 parent: 0:1160648e36ce
199 user: test
199 user: test
200 date: Thu Jan 01 00:00:00 1970 +0000
200 date: Thu Jan 01 00:00:00 1970 +0000
201 summary: add
201 summary: add
202
202
203
203
204 push
204 push
205
205
206 $ hg push
206 $ hg push
207 pushing to ssh://user@dummy/remote
207 pushing to ssh://user@dummy/remote
208 searching for changes
208 searching for changes
209 remote: adding changesets
209 remote: adding changesets
210 remote: adding manifests
210 remote: adding manifests
211 remote: adding file changes
211 remote: adding file changes
212 remote: added 1 changesets with 1 changes to 1 files
212 remote: added 1 changesets with 1 changes to 1 files
213 $ cd $TESTTMP/remote
213 $ cd $TESTTMP/remote
214
214
215 check remote tip
215 check remote tip
216
216
217 $ hg tip
217 $ hg tip
218 changeset: 3:a28a9d1a809c
218 changeset: 3:a28a9d1a809c
219 tag: tip
219 tag: tip
220 parent: 0:1160648e36ce
220 parent: 0:1160648e36ce
221 user: test
221 user: test
222 date: Thu Jan 01 00:00:00 1970 +0000
222 date: Thu Jan 01 00:00:00 1970 +0000
223 summary: add
223 summary: add
224
224
225 $ hg verify
225 $ hg verify
226 checking changesets
226 checking changesets
227 checking manifests
227 checking manifests
228 crosschecking files in changesets and manifests
228 crosschecking files in changesets and manifests
229 checking files
229 checking files
230 checked 4 changesets with 3 changes to 2 files
230 checked 4 changesets with 3 changes to 2 files
231 $ hg cat -r tip foo
231 $ hg cat -r tip foo
232 bleah
232 bleah
233 $ echo z > z
233 $ echo z > z
234 $ hg ci -A -m z z
234 $ hg ci -A -m z z
235 created new head
235 created new head
236
236
237 test pushkeys and bookmarks
237 test pushkeys and bookmarks
238
238
239 $ cd $TESTTMP/local
239 $ cd $TESTTMP/local
240 $ hg debugpushkey --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
240 $ hg debugpushkey --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
241 bookmarks
241 bookmarks
242 namespaces
242 namespaces
243 phases
243 phases
244 $ hg book foo -r 0
244 $ hg book foo -r 0
245 $ hg out -B
245 $ hg out -B
246 comparing with ssh://user@dummy/remote
246 comparing with ssh://user@dummy/remote
247 searching for changed bookmarks
247 searching for changed bookmarks
248 foo 1160648e36ce
248 foo 1160648e36ce
249 $ hg push -B foo
249 $ hg push -B foo
250 pushing to ssh://user@dummy/remote
250 pushing to ssh://user@dummy/remote
251 searching for changes
251 searching for changes
252 no changes found
252 no changes found
253 exporting bookmark foo
253 exporting bookmark foo
254 [1]
254 [1]
255 $ hg debugpushkey --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
255 $ hg debugpushkey --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
256 foo 1160648e36cec0054048a7edc4110c6f84fde594
256 foo 1160648e36cec0054048a7edc4110c6f84fde594
257 $ hg book -f foo
257 $ hg book -f foo
258 $ hg push --traceback
258 $ hg push --traceback
259 pushing to ssh://user@dummy/remote
259 pushing to ssh://user@dummy/remote
260 searching for changes
260 searching for changes
261 no changes found
261 no changes found
262 updating bookmark foo
262 updating bookmark foo
263 [1]
263 [1]
264 $ hg book -d foo
264 $ hg book -d foo
265 $ hg in -B
265 $ hg in -B
266 comparing with ssh://user@dummy/remote
266 comparing with ssh://user@dummy/remote
267 searching for changed bookmarks
267 searching for changed bookmarks
268 foo a28a9d1a809c
268 foo a28a9d1a809c
269 $ hg book -f -r 0 foo
269 $ hg book -f -r 0 foo
270 $ hg pull -B foo
270 $ hg pull -B foo
271 pulling from ssh://user@dummy/remote
271 pulling from ssh://user@dummy/remote
272 no changes found
272 no changes found
273 updating bookmark foo
273 updating bookmark foo
274 $ hg book -d foo
274 $ hg book -d foo
275 $ hg push -B foo
275 $ hg push -B foo
276 pushing to ssh://user@dummy/remote
276 pushing to ssh://user@dummy/remote
277 searching for changes
277 searching for changes
278 no changes found
278 no changes found
279 deleting remote bookmark foo
279 deleting remote bookmark foo
280 [1]
280 [1]
281
281
282 a bad, evil hook that prints to stdout
282 a bad, evil hook that prints to stdout
283
283
284 $ cat <<EOF > $TESTTMP/badhook
284 $ cat <<EOF > $TESTTMP/badhook
285 > import sys
285 > import sys
286 > sys.stdout.write("KABOOM\n")
286 > sys.stdout.write("KABOOM\n")
287 > EOF
287 > EOF
288
288
289 $ echo '[hooks]' >> ../remote/.hg/hgrc
289 $ echo '[hooks]' >> ../remote/.hg/hgrc
290 $ echo "changegroup.stdout = \"$PYTHON\" $TESTTMP/badhook" >> ../remote/.hg/hgrc
290 $ echo "changegroup.stdout = \"$PYTHON\" $TESTTMP/badhook" >> ../remote/.hg/hgrc
291 $ echo r > r
291 $ echo r > r
292 $ hg ci -A -m z r
292 $ hg ci -A -m z r
293
293
294 push should succeed even though it has an unexpected response
294 push should succeed even though it has an unexpected response
295
295
296 $ hg push
296 $ hg push
297 pushing to ssh://user@dummy/remote
297 pushing to ssh://user@dummy/remote
298 searching for changes
298 searching for changes
299 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
299 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
300 remote: adding changesets
300 remote: adding changesets
301 remote: adding manifests
301 remote: adding manifests
302 remote: adding file changes
302 remote: adding file changes
303 remote: added 1 changesets with 1 changes to 1 files
303 remote: added 1 changesets with 1 changes to 1 files
304 remote: KABOOM
304 remote: KABOOM
305 $ hg -R ../remote heads
305 $ hg -R ../remote heads
306 changeset: 5:1383141674ec
306 changeset: 5:1383141674ec
307 tag: tip
307 tag: tip
308 parent: 3:a28a9d1a809c
308 parent: 3:a28a9d1a809c
309 user: test
309 user: test
310 date: Thu Jan 01 00:00:00 1970 +0000
310 date: Thu Jan 01 00:00:00 1970 +0000
311 summary: z
311 summary: z
312
312
313 changeset: 4:6c0482d977a3
313 changeset: 4:6c0482d977a3
314 parent: 0:1160648e36ce
314 parent: 0:1160648e36ce
315 user: test
315 user: test
316 date: Thu Jan 01 00:00:00 1970 +0000
316 date: Thu Jan 01 00:00:00 1970 +0000
317 summary: z
317 summary: z
318
318
319
319
320 clone bookmarks
320 clone bookmarks
321
321
322 $ hg -R ../remote bookmark test
322 $ hg -R ../remote bookmark test
323 $ hg -R ../remote bookmarks
323 $ hg -R ../remote bookmarks
324 * test 4:6c0482d977a3
324 * test 4:6c0482d977a3
325 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
325 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
326 requesting all changes
326 requesting all changes
327 adding changesets
327 adding changesets
328 adding manifests
328 adding manifests
329 adding file changes
329 adding file changes
330 added 6 changesets with 5 changes to 4 files (+1 heads)
330 added 6 changesets with 5 changes to 4 files (+1 heads)
331 new changesets 1160648e36ce:1383141674ec
331 new changesets 1160648e36ce:1383141674ec
332 updating to branch default
332 updating to branch default
333 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
333 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
334 $ hg -R local-bookmarks bookmarks
334 $ hg -R local-bookmarks bookmarks
335 test 4:6c0482d977a3
335 test 4:6c0482d977a3
336
336
337 passwords in ssh urls are not supported
337 passwords in ssh urls are not supported
338 (we use a glob here because different Python versions give different
338 (we use a glob here because different Python versions give different
339 results here)
339 results here)
340
340
341 $ hg push ssh://user:erroneouspwd@dummy/remote
341 $ hg push ssh://user:erroneouspwd@dummy/remote
342 pushing to ssh://user:*@dummy/remote (glob)
342 pushing to ssh://user:*@dummy/remote (glob)
343 abort: password in URL not supported!
343 abort: password in URL not supported!
344 [255]
344 [255]
345
345
346 $ cd $TESTTMP
346 $ cd $TESTTMP
347
347
348 hide outer repo
348 hide outer repo
349 $ hg init
349 $ hg init
350
350
351 Test remote paths with spaces (issue2983):
351 Test remote paths with spaces (issue2983):
352
352
353 $ hg init --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
353 $ hg init --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
354 $ touch "$TESTTMP/a repo/test"
354 $ touch "$TESTTMP/a repo/test"
355 $ hg -R 'a repo' commit -A -m "test"
355 $ hg -R 'a repo' commit -A -m "test"
356 adding test
356 adding test
357 $ hg -R 'a repo' tag tag
357 $ hg -R 'a repo' tag tag
358 $ hg id --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
358 $ hg id --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
359 73649e48688a
359 73649e48688a
360
360
361 $ hg id --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
361 $ hg id --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
362 abort: unknown revision 'noNoNO'!
362 abort: unknown revision 'noNoNO'!
363 [255]
363 [255]
364
364
365 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
365 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
366
366
367 $ hg clone --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
367 $ hg clone --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
368 destination directory: a repo
368 destination directory: a repo
369 abort: destination 'a repo' is not empty
369 abort: destination 'a repo' is not empty
370 [255]
370 [255]
371
371
372 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
372 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
373 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
373 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
374 parameters:
374 parameters:
375
375
376 $ cat > ssh.sh << EOF
376 $ cat > ssh.sh << EOF
377 > userhost="\$1"
377 > userhost="\$1"
378 > SSH_ORIGINAL_COMMAND="\$2"
378 > SSH_ORIGINAL_COMMAND="\$2"
379 > export SSH_ORIGINAL_COMMAND
379 > export SSH_ORIGINAL_COMMAND
380 > PYTHONPATH="$PYTHONPATH"
380 > PYTHONPATH="$PYTHONPATH"
381 > export PYTHONPATH
381 > export PYTHONPATH
382 > "$PYTHON" "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
382 > "$PYTHON" "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
383 > EOF
383 > EOF
384
384
385 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
385 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
386 73649e48688a
386 73649e48688a
387
387
388 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
388 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
389 remote: Illegal repository "$TESTTMP/a'repo"
389 remote: Illegal repository "$TESTTMP/a'repo"
390 abort: no suitable response from remote hg!
390 abort: no suitable response from remote hg!
391 [255]
391 [255]
392
392
393 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
393 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
394 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
394 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
395 abort: no suitable response from remote hg!
395 abort: no suitable response from remote hg!
396 [255]
396 [255]
397
397
398 $ SSH_ORIGINAL_COMMAND="'hg' serve -R 'a'repo' --stdio" "$PYTHON" "$TESTDIR/../contrib/hg-ssh"
398 $ SSH_ORIGINAL_COMMAND="'hg' serve -R 'a'repo' --stdio" "$PYTHON" "$TESTDIR/../contrib/hg-ssh"
399 Illegal command "'hg' serve -R 'a'repo' --stdio": No closing quotation
399 Illegal command "'hg' serve -R 'a'repo' --stdio": No closing quotation
400 [255]
400 [255]
401
401
402 Test hg-ssh in read-only mode:
402 Test hg-ssh in read-only mode:
403
403
404 $ cat > ssh.sh << EOF
404 $ cat > ssh.sh << EOF
405 > userhost="\$1"
405 > userhost="\$1"
406 > SSH_ORIGINAL_COMMAND="\$2"
406 > SSH_ORIGINAL_COMMAND="\$2"
407 > export SSH_ORIGINAL_COMMAND
407 > export SSH_ORIGINAL_COMMAND
408 > PYTHONPATH="$PYTHONPATH"
408 > PYTHONPATH="$PYTHONPATH"
409 > export PYTHONPATH
409 > export PYTHONPATH
410 > "$PYTHON" "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
410 > "$PYTHON" "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
411 > EOF
411 > EOF
412
412
413 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
413 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
414 requesting all changes
414 requesting all changes
415 adding changesets
415 adding changesets
416 adding manifests
416 adding manifests
417 adding file changes
417 adding file changes
418 added 6 changesets with 5 changes to 4 files (+1 heads)
418 added 6 changesets with 5 changes to 4 files (+1 heads)
419 new changesets 1160648e36ce:1383141674ec
419 new changesets 1160648e36ce:1383141674ec
420 updating to branch default
420 updating to branch default
421 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
421 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
422
422
423 $ cd read-only-local
423 $ cd read-only-local
424 $ echo "baz" > bar
424 $ echo "baz" > bar
425 $ hg ci -A -m "unpushable commit" bar
425 $ hg ci -A -m "unpushable commit" bar
426 $ hg push --ssh "sh ../ssh.sh"
426 $ hg push --ssh "sh ../ssh.sh"
427 pushing to ssh://user@dummy/*/remote (glob)
427 pushing to ssh://user@dummy/*/remote (glob)
428 searching for changes
428 searching for changes
429 remote: Permission denied
429 remote: Permission denied
430 remote: abort: pretxnopen.hg-ssh hook failed
430 remote: abort: pretxnopen.hg-ssh hook failed
431 remote: Permission denied
431 remote: Permission denied
432 remote: pushkey-abort: prepushkey.hg-ssh hook failed
432 remote: pushkey-abort: prepushkey.hg-ssh hook failed
433 updating 6c0482d977a3 to public failed!
433 updating 6c0482d977a3 to public failed!
434 [1]
434 [1]
435
435
436 $ cd $TESTTMP
436 $ cd $TESTTMP
437
437
438 stderr from remote commands should be printed before stdout from local code (issue4336)
438 stderr from remote commands should be printed before stdout from local code (issue4336)
439
439
440 $ hg clone remote stderr-ordering
440 $ hg clone remote stderr-ordering
441 updating to branch default
441 updating to branch default
442 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
442 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
443 $ cd stderr-ordering
443 $ cd stderr-ordering
444 $ cat >> localwrite.py << EOF
444 $ cat >> localwrite.py << EOF
445 > from mercurial import exchange, extensions
445 > from mercurial import exchange, extensions
446 >
446 >
447 > def wrappedpush(orig, repo, *args, **kwargs):
447 > def wrappedpush(orig, repo, *args, **kwargs):
448 > res = orig(repo, *args, **kwargs)
448 > res = orig(repo, *args, **kwargs)
449 > repo.ui.write(b'local stdout\n')
449 > repo.ui.write(b'local stdout\n')
450 > return res
450 > return res
451 >
451 >
452 > def extsetup(ui):
452 > def extsetup(ui):
453 > extensions.wrapfunction(exchange, b'push', wrappedpush)
453 > extensions.wrapfunction(exchange, b'push', wrappedpush)
454 > EOF
454 > EOF
455
455
456 $ cat >> .hg/hgrc << EOF
456 $ cat >> .hg/hgrc << EOF
457 > [paths]
457 > [paths]
458 > default-push = ssh://user@dummy/remote
458 > default-push = ssh://user@dummy/remote
459 > [ui]
459 > [ui]
460 > ssh = "$PYTHON" "$TESTDIR/dummyssh"
460 > ssh = "$PYTHON" "$TESTDIR/dummyssh"
461 > [extensions]
461 > [extensions]
462 > localwrite = localwrite.py
462 > localwrite = localwrite.py
463 > EOF
463 > EOF
464
464
465 $ echo localwrite > foo
465 $ echo localwrite > foo
466 $ hg commit -m 'testing localwrite'
466 $ hg commit -m 'testing localwrite'
467 $ hg push
467 $ hg push
468 pushing to ssh://user@dummy/remote
468 pushing to ssh://user@dummy/remote
469 searching for changes
469 searching for changes
470 remote: adding changesets
470 remote: adding changesets
471 remote: adding manifests
471 remote: adding manifests
472 remote: adding file changes
472 remote: adding file changes
473 remote: added 1 changesets with 1 changes to 1 files
473 remote: added 1 changesets with 1 changes to 1 files
474 remote: KABOOM
474 remote: KABOOM
475 local stdout
475 local stdout
476
476
477 debug output
477 debug output
478
478
479 $ hg pull --debug ssh://user@dummy/remote
479 $ hg pull --debug ssh://user@dummy/remote
480 pulling from ssh://user@dummy/remote
480 pulling from ssh://user@dummy/remote
481 running .* ".*/dummyssh" ['"]user@dummy['"] ('|")hg -R remote serve --stdio('|") (re)
481 running .* ".*/dummyssh" ['"]user@dummy['"] ('|")hg -R remote serve --stdio('|") (re)
482 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
482 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
483 sending hello command
483 sending hello command
484 sending between command
484 sending between command
485 remote: 440 (sshv1 !)
485 remote: 440 (sshv1 !)
486 protocol upgraded to exp-ssh-v2-0003 (sshv2 !)
486 protocol upgraded to exp-ssh-v2-0003 (sshv2 !)
487 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
487 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
488 remote: 1 (sshv1 !)
488 remote: 1 (sshv1 !)
489 sending protocaps command
489 sending protocaps command
490 preparing listkeys for "bookmarks"
490 preparing listkeys for "bookmarks"
491 sending listkeys command
491 sending listkeys command
492 received listkey for "bookmarks": 45 bytes
492 received listkey for "bookmarks": 45 bytes
493 query 1; heads
493 query 1; heads
494 sending batch command
494 sending batch command
495 searching for changes
495 searching for changes
496 all remote heads known locally
496 all remote heads known locally
497 no changes found
497 no changes found
498 preparing listkeys for "phases"
498 preparing listkeys for "phases"
499 sending listkeys command
499 sending listkeys command
500 received listkey for "phases": 15 bytes
500 received listkey for "phases": 15 bytes
501 checking for updated bookmarks
501 checking for updated bookmarks
502
502
503 $ cd $TESTTMP
503 $ cd $TESTTMP
504
504
505 $ cat dummylog
505 $ cat dummylog
506 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
506 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
507 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio (no-msys !)
507 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio (no-msys !)
508 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
508 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
509 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio (no-reposimplestore !)
509 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio (no-reposimplestore !)
510 Got arguments 1:user@dummy 2:hg -R remote serve --stdio (no-reposimplestore !)
510 Got arguments 1:user@dummy 2:hg -R remote serve --stdio (no-reposimplestore !)
511 Got arguments 1:user@dummy 2:hg -R remote serve --stdio (no-reposimplestore !)
511 Got arguments 1:user@dummy 2:hg -R remote serve --stdio (no-reposimplestore !)
512 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
512 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
513 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
513 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
514 Got arguments 1:user@dummy 2:hg -R local serve --stdio
514 Got arguments 1:user@dummy 2:hg -R local serve --stdio
515 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
515 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
516 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
516 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
517 changegroup-in-remote hook: HG_HOOKNAME=changegroup
517 changegroup-in-remote hook: HG_HOOKNAME=changegroup
518 HG_HOOKTYPE=changegroup
518 HG_HOOKTYPE=changegroup
519 HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60
519 HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60
520 HG_NODE_LAST=a28a9d1a809cab7d4e2fde4bee738a9ede948b60
520 HG_NODE_LAST=a28a9d1a809cab7d4e2fde4bee738a9ede948b60
521 HG_SOURCE=serve
521 HG_SOURCE=serve
522 HG_TXNID=TXN:$ID$
522 HG_TXNID=TXN:$ID$
523 HG_TXNNAME=serve
524 remote:ssh:$LOCALIP
523 HG_URL=remote:ssh:$LOCALIP
525 HG_URL=remote:ssh:$LOCALIP
524
526
525 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
527 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
526 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
528 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
527 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
529 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
528 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
530 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
529 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
531 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
530 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
532 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
531 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
533 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
532 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
534 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
533 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
535 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
534 changegroup-in-remote hook: HG_HOOKNAME=changegroup
536 changegroup-in-remote hook: HG_HOOKNAME=changegroup
535 HG_HOOKTYPE=changegroup
537 HG_HOOKTYPE=changegroup
536 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6
538 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6
537 HG_NODE_LAST=1383141674ec756a6056f6a9097618482fe0f4a6
539 HG_NODE_LAST=1383141674ec756a6056f6a9097618482fe0f4a6
538 HG_SOURCE=serve
540 HG_SOURCE=serve
539 HG_TXNID=TXN:$ID$
541 HG_TXNID=TXN:$ID$
542 HG_TXNNAME=serve
543 remote:ssh:$LOCALIP
540 HG_URL=remote:ssh:$LOCALIP
544 HG_URL=remote:ssh:$LOCALIP
541
545
542 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
546 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
543 Got arguments 1:user@dummy 2:hg init 'a repo'
547 Got arguments 1:user@dummy 2:hg init 'a repo'
544 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
548 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
545 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
549 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
546 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
550 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
547 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
551 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
548 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
552 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
549 changegroup-in-remote hook: HG_HOOKNAME=changegroup
553 changegroup-in-remote hook: HG_HOOKNAME=changegroup
550 HG_HOOKTYPE=changegroup
554 HG_HOOKTYPE=changegroup
551 HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8
555 HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8
552 HG_NODE_LAST=65c38f4125f9602c8db4af56530cc221d93b8ef8
556 HG_NODE_LAST=65c38f4125f9602c8db4af56530cc221d93b8ef8
553 HG_SOURCE=serve
557 HG_SOURCE=serve
554 HG_TXNID=TXN:$ID$
558 HG_TXNID=TXN:$ID$
559 HG_TXNNAME=serve
560 remote:ssh:$LOCALIP
555 HG_URL=remote:ssh:$LOCALIP
561 HG_URL=remote:ssh:$LOCALIP
556
562
557 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
563 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
558
564
559 remote hook failure is attributed to remote
565 remote hook failure is attributed to remote
560
566
561 $ cat > $TESTTMP/failhook << EOF
567 $ cat > $TESTTMP/failhook << EOF
562 > def hook(ui, repo, **kwargs):
568 > def hook(ui, repo, **kwargs):
563 > ui.write(b'hook failure!\n')
569 > ui.write(b'hook failure!\n')
564 > ui.flush()
570 > ui.flush()
565 > return 1
571 > return 1
566 > EOF
572 > EOF
567
573
568 $ echo "pretxnchangegroup.fail = python:$TESTTMP/failhook:hook" >> remote/.hg/hgrc
574 $ echo "pretxnchangegroup.fail = python:$TESTTMP/failhook:hook" >> remote/.hg/hgrc
569
575
570 $ hg -q --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" clone ssh://user@dummy/remote hookout
576 $ hg -q --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" clone ssh://user@dummy/remote hookout
571 $ cd hookout
577 $ cd hookout
572 $ touch hookfailure
578 $ touch hookfailure
573 $ hg -q commit -A -m 'remote hook failure'
579 $ hg -q commit -A -m 'remote hook failure'
574 $ hg --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" push
580 $ hg --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" push
575 pushing to ssh://user@dummy/remote
581 pushing to ssh://user@dummy/remote
576 searching for changes
582 searching for changes
577 remote: adding changesets
583 remote: adding changesets
578 remote: adding manifests
584 remote: adding manifests
579 remote: adding file changes
585 remote: adding file changes
580 remote: added 1 changesets with 1 changes to 1 files
586 remote: added 1 changesets with 1 changes to 1 files
581 remote: hook failure!
587 remote: hook failure!
582 remote: transaction abort!
588 remote: transaction abort!
583 remote: rollback completed
589 remote: rollback completed
584 remote: abort: pretxnchangegroup.fail hook failed
590 remote: abort: pretxnchangegroup.fail hook failed
585 [1]
591 [1]
586
592
587 abort during pull is properly reported as such
593 abort during pull is properly reported as such
588
594
589 $ echo morefoo >> ../remote/foo
595 $ echo morefoo >> ../remote/foo
590 $ hg -R ../remote commit --message "more foo to be pulled"
596 $ hg -R ../remote commit --message "more foo to be pulled"
591 $ cat >> ../remote/.hg/hgrc << EOF
597 $ cat >> ../remote/.hg/hgrc << EOF
592 > [extensions]
598 > [extensions]
593 > crash = ${TESTDIR}/crashgetbundler.py
599 > crash = ${TESTDIR}/crashgetbundler.py
594 > EOF
600 > EOF
595 $ hg --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" pull
601 $ hg --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" pull
596 pulling from ssh://user@dummy/remote
602 pulling from ssh://user@dummy/remote
597 searching for changes
603 searching for changes
598 adding changesets
604 adding changesets
599 remote: abort: this is an exercise
605 remote: abort: this is an exercise
600 transaction abort!
606 transaction abort!
601 rollback completed
607 rollback completed
602 abort: stream ended unexpectedly (got 0 bytes, expected 4)
608 abort: stream ended unexpectedly (got 0 bytes, expected 4)
603 [255]
609 [255]
@@ -1,698 +1,702 b''
1 #testcases sshv1 sshv2
1 #testcases sshv1 sshv2
2
2
3 #if sshv2
3 #if sshv2
4 $ cat >> $HGRCPATH << EOF
4 $ cat >> $HGRCPATH << EOF
5 > [experimental]
5 > [experimental]
6 > sshpeer.advertise-v2 = true
6 > sshpeer.advertise-v2 = true
7 > sshserver.support-v2 = true
7 > sshserver.support-v2 = true
8 > EOF
8 > EOF
9 #endif
9 #endif
10
10
11 This test tries to exercise the ssh functionality with a dummy script
11 This test tries to exercise the ssh functionality with a dummy script
12
12
13 creating 'remote' repo
13 creating 'remote' repo
14
14
15 $ hg init remote
15 $ hg init remote
16 $ cd remote
16 $ cd remote
17 $ echo this > foo
17 $ echo this > foo
18 $ echo this > fooO
18 $ echo this > fooO
19 $ hg ci -A -m "init" foo fooO
19 $ hg ci -A -m "init" foo fooO
20
20
21 insert a closed branch (issue4428)
21 insert a closed branch (issue4428)
22
22
23 $ hg up null
23 $ hg up null
24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
25 $ hg branch closed
25 $ hg branch closed
26 marked working directory as branch closed
26 marked working directory as branch closed
27 (branches are permanent and global, did you want a bookmark?)
27 (branches are permanent and global, did you want a bookmark?)
28 $ hg ci -mc0
28 $ hg ci -mc0
29 $ hg ci --close-branch -mc1
29 $ hg ci --close-branch -mc1
30 $ hg up -q default
30 $ hg up -q default
31
31
32 configure for serving
32 configure for serving
33
33
34 $ cat <<EOF > .hg/hgrc
34 $ cat <<EOF > .hg/hgrc
35 > [server]
35 > [server]
36 > uncompressed = True
36 > uncompressed = True
37 >
37 >
38 > [hooks]
38 > [hooks]
39 > changegroup = sh -c "printenv.py --line changegroup-in-remote 0 ../dummylog"
39 > changegroup = sh -c "printenv.py --line changegroup-in-remote 0 ../dummylog"
40 > EOF
40 > EOF
41 $ cd $TESTTMP
41 $ cd $TESTTMP
42
42
43 repo not found error
43 repo not found error
44
44
45 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
45 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
46 remote: abort: repository nonexistent not found!
46 remote: abort: repository nonexistent not found!
47 abort: no suitable response from remote hg!
47 abort: no suitable response from remote hg!
48 [255]
48 [255]
49
49
50 non-existent absolute path
50 non-existent absolute path
51
51
52 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/`pwd`/nonexistent local
52 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/`pwd`/nonexistent local
53 remote: abort: repository $TESTTMP/nonexistent not found!
53 remote: abort: repository $TESTTMP/nonexistent not found!
54 abort: no suitable response from remote hg!
54 abort: no suitable response from remote hg!
55 [255]
55 [255]
56
56
57 clone remote via stream
57 clone remote via stream
58
58
59 #if no-reposimplestore
59 #if no-reposimplestore
60
60
61 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --stream ssh://user@dummy/remote local-stream
61 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --stream ssh://user@dummy/remote local-stream
62 streaming all changes
62 streaming all changes
63 8 files to transfer, 827 bytes of data
63 8 files to transfer, 827 bytes of data
64 transferred 827 bytes in * seconds (*) (glob)
64 transferred 827 bytes in * seconds (*) (glob)
65 updating to branch default
65 updating to branch default
66 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 $ cd local-stream
67 $ cd local-stream
68 $ hg verify
68 $ hg verify
69 checking changesets
69 checking changesets
70 checking manifests
70 checking manifests
71 crosschecking files in changesets and manifests
71 crosschecking files in changesets and manifests
72 checking files
72 checking files
73 checked 3 changesets with 2 changes to 2 files
73 checked 3 changesets with 2 changes to 2 files
74 $ hg branches
74 $ hg branches
75 default 0:1160648e36ce
75 default 0:1160648e36ce
76 $ cd $TESTTMP
76 $ cd $TESTTMP
77
77
78 clone bookmarks via stream
78 clone bookmarks via stream
79
79
80 $ hg -R local-stream book mybook
80 $ hg -R local-stream book mybook
81 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --stream ssh://user@dummy/local-stream stream2
81 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" --stream ssh://user@dummy/local-stream stream2
82 streaming all changes
82 streaming all changes
83 9 files to transfer, 870 bytes of data
83 9 files to transfer, 870 bytes of data
84 transferred 870 bytes in * seconds (*) (glob)
84 transferred 870 bytes in * seconds (*) (glob)
85 updating to branch default
85 updating to branch default
86 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
86 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 $ cd stream2
87 $ cd stream2
88 $ hg book
88 $ hg book
89 mybook 0:1160648e36ce
89 mybook 0:1160648e36ce
90 $ cd $TESTTMP
90 $ cd $TESTTMP
91 $ rm -rf local-stream stream2
91 $ rm -rf local-stream stream2
92
92
93 #endif
93 #endif
94
94
95 clone remote via pull
95 clone remote via pull
96
96
97 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
97 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
98 requesting all changes
98 requesting all changes
99 adding changesets
99 adding changesets
100 adding manifests
100 adding manifests
101 adding file changes
101 adding file changes
102 added 3 changesets with 2 changes to 2 files
102 added 3 changesets with 2 changes to 2 files
103 new changesets 1160648e36ce:ad076bfb429d
103 new changesets 1160648e36ce:ad076bfb429d
104 updating to branch default
104 updating to branch default
105 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
105 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
106
106
107 verify
107 verify
108
108
109 $ cd local
109 $ cd local
110 $ hg verify
110 $ hg verify
111 checking changesets
111 checking changesets
112 checking manifests
112 checking manifests
113 crosschecking files in changesets and manifests
113 crosschecking files in changesets and manifests
114 checking files
114 checking files
115 checked 3 changesets with 2 changes to 2 files
115 checked 3 changesets with 2 changes to 2 files
116 $ cat >> .hg/hgrc <<EOF
116 $ cat >> .hg/hgrc <<EOF
117 > [hooks]
117 > [hooks]
118 > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
118 > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
119 > EOF
119 > EOF
120
120
121 empty default pull
121 empty default pull
122
122
123 $ hg paths
123 $ hg paths
124 default = ssh://user@dummy/remote
124 default = ssh://user@dummy/remote
125 $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\""
125 $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\""
126 pulling from ssh://user@dummy/remote
126 pulling from ssh://user@dummy/remote
127 searching for changes
127 searching for changes
128 no changes found
128 no changes found
129
129
130 pull from wrong ssh URL
130 pull from wrong ssh URL
131
131
132 $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
132 $ hg pull -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
133 pulling from ssh://user@dummy/doesnotexist
133 pulling from ssh://user@dummy/doesnotexist
134 remote: abort: repository doesnotexist not found!
134 remote: abort: repository doesnotexist not found!
135 abort: no suitable response from remote hg!
135 abort: no suitable response from remote hg!
136 [255]
136 [255]
137
137
138 local change
138 local change
139
139
140 $ echo bleah > foo
140 $ echo bleah > foo
141 $ hg ci -m "add"
141 $ hg ci -m "add"
142
142
143 updating rc
143 updating rc
144
144
145 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
145 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
146 $ echo "[ui]" >> .hg/hgrc
146 $ echo "[ui]" >> .hg/hgrc
147 $ echo "ssh = \"$PYTHON\" \"$TESTDIR/dummyssh\"" >> .hg/hgrc
147 $ echo "ssh = \"$PYTHON\" \"$TESTDIR/dummyssh\"" >> .hg/hgrc
148
148
149 find outgoing
149 find outgoing
150
150
151 $ hg out ssh://user@dummy/remote
151 $ hg out ssh://user@dummy/remote
152 comparing with ssh://user@dummy/remote
152 comparing with ssh://user@dummy/remote
153 searching for changes
153 searching for changes
154 changeset: 3:a28a9d1a809c
154 changeset: 3:a28a9d1a809c
155 tag: tip
155 tag: tip
156 parent: 0:1160648e36ce
156 parent: 0:1160648e36ce
157 user: test
157 user: test
158 date: Thu Jan 01 00:00:00 1970 +0000
158 date: Thu Jan 01 00:00:00 1970 +0000
159 summary: add
159 summary: add
160
160
161
161
162 find incoming on the remote side
162 find incoming on the remote side
163
163
164 $ hg incoming -R ../remote -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
164 $ hg incoming -R ../remote -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
165 comparing with ssh://user@dummy/local
165 comparing with ssh://user@dummy/local
166 searching for changes
166 searching for changes
167 changeset: 3:a28a9d1a809c
167 changeset: 3:a28a9d1a809c
168 tag: tip
168 tag: tip
169 parent: 0:1160648e36ce
169 parent: 0:1160648e36ce
170 user: test
170 user: test
171 date: Thu Jan 01 00:00:00 1970 +0000
171 date: Thu Jan 01 00:00:00 1970 +0000
172 summary: add
172 summary: add
173
173
174
174
175 find incoming on the remote side (using absolute path)
175 find incoming on the remote side (using absolute path)
176
176
177 $ hg incoming -R ../remote -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
177 $ hg incoming -R ../remote -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
178 comparing with ssh://user@dummy/$TESTTMP/local
178 comparing with ssh://user@dummy/$TESTTMP/local
179 searching for changes
179 searching for changes
180 changeset: 3:a28a9d1a809c
180 changeset: 3:a28a9d1a809c
181 tag: tip
181 tag: tip
182 parent: 0:1160648e36ce
182 parent: 0:1160648e36ce
183 user: test
183 user: test
184 date: Thu Jan 01 00:00:00 1970 +0000
184 date: Thu Jan 01 00:00:00 1970 +0000
185 summary: add
185 summary: add
186
186
187
187
188 push
188 push
189
189
190 $ hg push
190 $ hg push
191 pushing to ssh://user@dummy/remote
191 pushing to ssh://user@dummy/remote
192 searching for changes
192 searching for changes
193 remote: adding changesets
193 remote: adding changesets
194 remote: adding manifests
194 remote: adding manifests
195 remote: adding file changes
195 remote: adding file changes
196 remote: added 1 changesets with 1 changes to 1 files
196 remote: added 1 changesets with 1 changes to 1 files
197 $ cd $TESTTMP/remote
197 $ cd $TESTTMP/remote
198
198
199 check remote tip
199 check remote tip
200
200
201 $ hg tip
201 $ hg tip
202 changeset: 3:a28a9d1a809c
202 changeset: 3:a28a9d1a809c
203 tag: tip
203 tag: tip
204 parent: 0:1160648e36ce
204 parent: 0:1160648e36ce
205 user: test
205 user: test
206 date: Thu Jan 01 00:00:00 1970 +0000
206 date: Thu Jan 01 00:00:00 1970 +0000
207 summary: add
207 summary: add
208
208
209 $ hg verify
209 $ hg verify
210 checking changesets
210 checking changesets
211 checking manifests
211 checking manifests
212 crosschecking files in changesets and manifests
212 crosschecking files in changesets and manifests
213 checking files
213 checking files
214 checked 4 changesets with 3 changes to 2 files
214 checked 4 changesets with 3 changes to 2 files
215 $ hg cat -r tip foo
215 $ hg cat -r tip foo
216 bleah
216 bleah
217 $ echo z > z
217 $ echo z > z
218 $ hg ci -A -m z z
218 $ hg ci -A -m z z
219 created new head
219 created new head
220
220
221 test pushkeys and bookmarks
221 test pushkeys and bookmarks
222
222
223 $ cd $TESTTMP/local
223 $ cd $TESTTMP/local
224 $ hg debugpushkey --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
224 $ hg debugpushkey --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
225 bookmarks
225 bookmarks
226 namespaces
226 namespaces
227 phases
227 phases
228 $ hg book foo -r 0
228 $ hg book foo -r 0
229 $ hg out -B --config paths.default=bogus://invalid --config paths.default:pushurl=`hg paths default`
229 $ hg out -B --config paths.default=bogus://invalid --config paths.default:pushurl=`hg paths default`
230 comparing with ssh://user@dummy/remote
230 comparing with ssh://user@dummy/remote
231 searching for changed bookmarks
231 searching for changed bookmarks
232 foo 1160648e36ce
232 foo 1160648e36ce
233 $ hg push -B foo
233 $ hg push -B foo
234 pushing to ssh://user@dummy/remote
234 pushing to ssh://user@dummy/remote
235 searching for changes
235 searching for changes
236 no changes found
236 no changes found
237 exporting bookmark foo
237 exporting bookmark foo
238 [1]
238 [1]
239 $ hg debugpushkey --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
239 $ hg debugpushkey --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
240 foo 1160648e36cec0054048a7edc4110c6f84fde594
240 foo 1160648e36cec0054048a7edc4110c6f84fde594
241 $ hg book -f foo
241 $ hg book -f foo
242 $ hg push --traceback
242 $ hg push --traceback
243 pushing to ssh://user@dummy/remote
243 pushing to ssh://user@dummy/remote
244 searching for changes
244 searching for changes
245 no changes found
245 no changes found
246 updating bookmark foo
246 updating bookmark foo
247 [1]
247 [1]
248 $ hg book -d foo
248 $ hg book -d foo
249 $ hg in -B
249 $ hg in -B
250 comparing with ssh://user@dummy/remote
250 comparing with ssh://user@dummy/remote
251 searching for changed bookmarks
251 searching for changed bookmarks
252 foo a28a9d1a809c
252 foo a28a9d1a809c
253 $ hg book -f -r 0 foo
253 $ hg book -f -r 0 foo
254 $ hg pull -B foo
254 $ hg pull -B foo
255 pulling from ssh://user@dummy/remote
255 pulling from ssh://user@dummy/remote
256 no changes found
256 no changes found
257 updating bookmark foo
257 updating bookmark foo
258 $ hg book -d foo
258 $ hg book -d foo
259 $ hg push -B foo
259 $ hg push -B foo
260 pushing to ssh://user@dummy/remote
260 pushing to ssh://user@dummy/remote
261 searching for changes
261 searching for changes
262 no changes found
262 no changes found
263 deleting remote bookmark foo
263 deleting remote bookmark foo
264 [1]
264 [1]
265
265
266 a bad, evil hook that prints to stdout
266 a bad, evil hook that prints to stdout
267
267
268 $ cat <<EOF > $TESTTMP/badhook
268 $ cat <<EOF > $TESTTMP/badhook
269 > import sys
269 > import sys
270 > sys.stdout.write("KABOOM\n")
270 > sys.stdout.write("KABOOM\n")
271 > sys.stdout.flush()
271 > sys.stdout.flush()
272 > EOF
272 > EOF
273
273
274 $ cat <<EOF > $TESTTMP/badpyhook.py
274 $ cat <<EOF > $TESTTMP/badpyhook.py
275 > import sys
275 > import sys
276 > def hook(ui, repo, hooktype, **kwargs):
276 > def hook(ui, repo, hooktype, **kwargs):
277 > sys.stdout.write("KABOOM IN PROCESS\n")
277 > sys.stdout.write("KABOOM IN PROCESS\n")
278 > sys.stdout.flush()
278 > sys.stdout.flush()
279 > EOF
279 > EOF
280
280
281 $ cat <<EOF >> ../remote/.hg/hgrc
281 $ cat <<EOF >> ../remote/.hg/hgrc
282 > [hooks]
282 > [hooks]
283 > changegroup.stdout = "$PYTHON" $TESTTMP/badhook
283 > changegroup.stdout = "$PYTHON" $TESTTMP/badhook
284 > changegroup.pystdout = python:$TESTTMP/badpyhook.py:hook
284 > changegroup.pystdout = python:$TESTTMP/badpyhook.py:hook
285 > EOF
285 > EOF
286 $ echo r > r
286 $ echo r > r
287 $ hg ci -A -m z r
287 $ hg ci -A -m z r
288
288
289 push should succeed even though it has an unexpected response
289 push should succeed even though it has an unexpected response
290
290
291 $ hg push
291 $ hg push
292 pushing to ssh://user@dummy/remote
292 pushing to ssh://user@dummy/remote
293 searching for changes
293 searching for changes
294 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
294 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
295 remote: adding changesets
295 remote: adding changesets
296 remote: adding manifests
296 remote: adding manifests
297 remote: adding file changes
297 remote: adding file changes
298 remote: added 1 changesets with 1 changes to 1 files
298 remote: added 1 changesets with 1 changes to 1 files
299 remote: KABOOM
299 remote: KABOOM
300 remote: KABOOM IN PROCESS
300 remote: KABOOM IN PROCESS
301 $ hg -R ../remote heads
301 $ hg -R ../remote heads
302 changeset: 5:1383141674ec
302 changeset: 5:1383141674ec
303 tag: tip
303 tag: tip
304 parent: 3:a28a9d1a809c
304 parent: 3:a28a9d1a809c
305 user: test
305 user: test
306 date: Thu Jan 01 00:00:00 1970 +0000
306 date: Thu Jan 01 00:00:00 1970 +0000
307 summary: z
307 summary: z
308
308
309 changeset: 4:6c0482d977a3
309 changeset: 4:6c0482d977a3
310 parent: 0:1160648e36ce
310 parent: 0:1160648e36ce
311 user: test
311 user: test
312 date: Thu Jan 01 00:00:00 1970 +0000
312 date: Thu Jan 01 00:00:00 1970 +0000
313 summary: z
313 summary: z
314
314
315
315
316 #if chg
316 #if chg
317
317
318 try again with remote chg, which should succeed as well
318 try again with remote chg, which should succeed as well
319
319
320 $ hg rollback -R ../remote
320 $ hg rollback -R ../remote
321 repository tip rolled back to revision 4 (undo serve)
321 repository tip rolled back to revision 4 (undo serve)
322
322
323 $ hg push --config ui.remotecmd=chg
323 $ hg push --config ui.remotecmd=chg
324 pushing to ssh://user@dummy/remote
324 pushing to ssh://user@dummy/remote
325 searching for changes
325 searching for changes
326 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
326 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
327 remote: adding changesets
327 remote: adding changesets
328 remote: adding manifests
328 remote: adding manifests
329 remote: adding file changes
329 remote: adding file changes
330 remote: added 1 changesets with 1 changes to 1 files
330 remote: added 1 changesets with 1 changes to 1 files
331 remote: KABOOM
331 remote: KABOOM
332 remote: KABOOM IN PROCESS
332 remote: KABOOM IN PROCESS
333
333
334 #endif
334 #endif
335
335
336 clone bookmarks
336 clone bookmarks
337
337
338 $ hg -R ../remote bookmark test
338 $ hg -R ../remote bookmark test
339 $ hg -R ../remote bookmarks
339 $ hg -R ../remote bookmarks
340 * test 4:6c0482d977a3
340 * test 4:6c0482d977a3
341 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
341 $ hg clone -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
342 requesting all changes
342 requesting all changes
343 adding changesets
343 adding changesets
344 adding manifests
344 adding manifests
345 adding file changes
345 adding file changes
346 added 6 changesets with 5 changes to 4 files (+1 heads)
346 added 6 changesets with 5 changes to 4 files (+1 heads)
347 new changesets 1160648e36ce:1383141674ec
347 new changesets 1160648e36ce:1383141674ec
348 updating to branch default
348 updating to branch default
349 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
349 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
350 $ hg -R local-bookmarks bookmarks
350 $ hg -R local-bookmarks bookmarks
351 test 4:6c0482d977a3
351 test 4:6c0482d977a3
352
352
353 passwords in ssh urls are not supported
353 passwords in ssh urls are not supported
354 (we use a glob here because different Python versions give different
354 (we use a glob here because different Python versions give different
355 results here)
355 results here)
356
356
357 $ hg push ssh://user:erroneouspwd@dummy/remote
357 $ hg push ssh://user:erroneouspwd@dummy/remote
358 pushing to ssh://user:*@dummy/remote (glob)
358 pushing to ssh://user:*@dummy/remote (glob)
359 abort: password in URL not supported!
359 abort: password in URL not supported!
360 [255]
360 [255]
361
361
362 $ cd $TESTTMP
362 $ cd $TESTTMP
363
363
364 hide outer repo
364 hide outer repo
365 $ hg init
365 $ hg init
366
366
367 Test remote paths with spaces (issue2983):
367 Test remote paths with spaces (issue2983):
368
368
369 $ hg init --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
369 $ hg init --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
370 $ touch "$TESTTMP/a repo/test"
370 $ touch "$TESTTMP/a repo/test"
371 $ hg -R 'a repo' commit -A -m "test"
371 $ hg -R 'a repo' commit -A -m "test"
372 adding test
372 adding test
373 $ hg -R 'a repo' tag tag
373 $ hg -R 'a repo' tag tag
374 $ hg id --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
374 $ hg id --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
375 73649e48688a
375 73649e48688a
376
376
377 $ hg id --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
377 $ hg id --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
378 abort: unknown revision 'noNoNO'!
378 abort: unknown revision 'noNoNO'!
379 [255]
379 [255]
380
380
381 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
381 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
382
382
383 $ hg clone --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
383 $ hg clone --ssh "\"$PYTHON\" \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
384 destination directory: a repo
384 destination directory: a repo
385 abort: destination 'a repo' is not empty
385 abort: destination 'a repo' is not empty
386 [255]
386 [255]
387
387
388 Make sure hg is really paranoid in serve --stdio mode. It used to be
388 Make sure hg is really paranoid in serve --stdio mode. It used to be
389 possible to get a debugger REPL by specifying a repo named --debugger.
389 possible to get a debugger REPL by specifying a repo named --debugger.
390 $ hg -R --debugger serve --stdio
390 $ hg -R --debugger serve --stdio
391 abort: potentially unsafe serve --stdio invocation: ['-R', '--debugger', 'serve', '--stdio']
391 abort: potentially unsafe serve --stdio invocation: ['-R', '--debugger', 'serve', '--stdio']
392 [255]
392 [255]
393 $ hg -R --config=ui.debugger=yes serve --stdio
393 $ hg -R --config=ui.debugger=yes serve --stdio
394 abort: potentially unsafe serve --stdio invocation: ['-R', '--config=ui.debugger=yes', 'serve', '--stdio']
394 abort: potentially unsafe serve --stdio invocation: ['-R', '--config=ui.debugger=yes', 'serve', '--stdio']
395 [255]
395 [255]
396 Abbreviations of 'serve' also don't work, to avoid shenanigans.
396 Abbreviations of 'serve' also don't work, to avoid shenanigans.
397 $ hg -R narf serv --stdio
397 $ hg -R narf serv --stdio
398 abort: potentially unsafe serve --stdio invocation: ['-R', 'narf', 'serv', '--stdio']
398 abort: potentially unsafe serve --stdio invocation: ['-R', 'narf', 'serv', '--stdio']
399 [255]
399 [255]
400
400
401 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
401 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
402 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
402 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
403 parameters:
403 parameters:
404
404
405 $ cat > ssh.sh << EOF
405 $ cat > ssh.sh << EOF
406 > userhost="\$1"
406 > userhost="\$1"
407 > SSH_ORIGINAL_COMMAND="\$2"
407 > SSH_ORIGINAL_COMMAND="\$2"
408 > export SSH_ORIGINAL_COMMAND
408 > export SSH_ORIGINAL_COMMAND
409 > PYTHONPATH="$PYTHONPATH"
409 > PYTHONPATH="$PYTHONPATH"
410 > export PYTHONPATH
410 > export PYTHONPATH
411 > "$PYTHON" "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
411 > "$PYTHON" "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
412 > EOF
412 > EOF
413
413
414 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
414 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
415 73649e48688a
415 73649e48688a
416
416
417 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
417 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
418 remote: Illegal repository "$TESTTMP/a'repo"
418 remote: Illegal repository "$TESTTMP/a'repo"
419 abort: no suitable response from remote hg!
419 abort: no suitable response from remote hg!
420 [255]
420 [255]
421
421
422 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
422 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
423 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
423 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
424 abort: no suitable response from remote hg!
424 abort: no suitable response from remote hg!
425 [255]
425 [255]
426
426
427 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" "$PYTHON" "$TESTDIR/../contrib/hg-ssh"
427 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" "$PYTHON" "$TESTDIR/../contrib/hg-ssh"
428 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
428 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
429 [255]
429 [255]
430
430
431 Test hg-ssh in read-only mode:
431 Test hg-ssh in read-only mode:
432
432
433 $ cat > ssh.sh << EOF
433 $ cat > ssh.sh << EOF
434 > userhost="\$1"
434 > userhost="\$1"
435 > SSH_ORIGINAL_COMMAND="\$2"
435 > SSH_ORIGINAL_COMMAND="\$2"
436 > export SSH_ORIGINAL_COMMAND
436 > export SSH_ORIGINAL_COMMAND
437 > PYTHONPATH="$PYTHONPATH"
437 > PYTHONPATH="$PYTHONPATH"
438 > export PYTHONPATH
438 > export PYTHONPATH
439 > "$PYTHON" "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
439 > "$PYTHON" "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
440 > EOF
440 > EOF
441
441
442 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
442 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
443 requesting all changes
443 requesting all changes
444 adding changesets
444 adding changesets
445 adding manifests
445 adding manifests
446 adding file changes
446 adding file changes
447 added 6 changesets with 5 changes to 4 files (+1 heads)
447 added 6 changesets with 5 changes to 4 files (+1 heads)
448 new changesets 1160648e36ce:1383141674ec
448 new changesets 1160648e36ce:1383141674ec
449 updating to branch default
449 updating to branch default
450 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
450 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
451
451
452 $ cd read-only-local
452 $ cd read-only-local
453 $ echo "baz" > bar
453 $ echo "baz" > bar
454 $ hg ci -A -m "unpushable commit" bar
454 $ hg ci -A -m "unpushable commit" bar
455 $ hg push --ssh "sh ../ssh.sh"
455 $ hg push --ssh "sh ../ssh.sh"
456 pushing to ssh://user@dummy/*/remote (glob)
456 pushing to ssh://user@dummy/*/remote (glob)
457 searching for changes
457 searching for changes
458 remote: Permission denied
458 remote: Permission denied
459 remote: pretxnopen.hg-ssh hook failed
459 remote: pretxnopen.hg-ssh hook failed
460 abort: push failed on remote
460 abort: push failed on remote
461 [255]
461 [255]
462
462
463 $ cd $TESTTMP
463 $ cd $TESTTMP
464
464
465 stderr from remote commands should be printed before stdout from local code (issue4336)
465 stderr from remote commands should be printed before stdout from local code (issue4336)
466
466
467 $ hg clone remote stderr-ordering
467 $ hg clone remote stderr-ordering
468 updating to branch default
468 updating to branch default
469 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
469 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 $ cd stderr-ordering
470 $ cd stderr-ordering
471 $ cat >> localwrite.py << EOF
471 $ cat >> localwrite.py << EOF
472 > from mercurial import exchange, extensions
472 > from mercurial import exchange, extensions
473 >
473 >
474 > def wrappedpush(orig, repo, *args, **kwargs):
474 > def wrappedpush(orig, repo, *args, **kwargs):
475 > res = orig(repo, *args, **kwargs)
475 > res = orig(repo, *args, **kwargs)
476 > repo.ui.write(b'local stdout\n')
476 > repo.ui.write(b'local stdout\n')
477 > repo.ui.flush()
477 > repo.ui.flush()
478 > return res
478 > return res
479 >
479 >
480 > def extsetup(ui):
480 > def extsetup(ui):
481 > extensions.wrapfunction(exchange, b'push', wrappedpush)
481 > extensions.wrapfunction(exchange, b'push', wrappedpush)
482 > EOF
482 > EOF
483
483
484 $ cat >> .hg/hgrc << EOF
484 $ cat >> .hg/hgrc << EOF
485 > [paths]
485 > [paths]
486 > default-push = ssh://user@dummy/remote
486 > default-push = ssh://user@dummy/remote
487 > [ui]
487 > [ui]
488 > ssh = "$PYTHON" "$TESTDIR/dummyssh"
488 > ssh = "$PYTHON" "$TESTDIR/dummyssh"
489 > [extensions]
489 > [extensions]
490 > localwrite = localwrite.py
490 > localwrite = localwrite.py
491 > EOF
491 > EOF
492
492
493 $ echo localwrite > foo
493 $ echo localwrite > foo
494 $ hg commit -m 'testing localwrite'
494 $ hg commit -m 'testing localwrite'
495 $ hg push
495 $ hg push
496 pushing to ssh://user@dummy/remote
496 pushing to ssh://user@dummy/remote
497 searching for changes
497 searching for changes
498 remote: adding changesets
498 remote: adding changesets
499 remote: adding manifests
499 remote: adding manifests
500 remote: adding file changes
500 remote: adding file changes
501 remote: added 1 changesets with 1 changes to 1 files
501 remote: added 1 changesets with 1 changes to 1 files
502 remote: KABOOM
502 remote: KABOOM
503 remote: KABOOM IN PROCESS
503 remote: KABOOM IN PROCESS
504 local stdout
504 local stdout
505
505
506 debug output
506 debug output
507
507
508 $ hg pull --debug ssh://user@dummy/remote --config devel.debug.peer-request=yes
508 $ hg pull --debug ssh://user@dummy/remote --config devel.debug.peer-request=yes
509 pulling from ssh://user@dummy/remote
509 pulling from ssh://user@dummy/remote
510 running .* ".*/dummyssh" ['"]user@dummy['"] ('|")hg -R remote serve --stdio('|") (re)
510 running .* ".*/dummyssh" ['"]user@dummy['"] ('|")hg -R remote serve --stdio('|") (re)
511 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
511 sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
512 devel-peer-request: hello+between
512 devel-peer-request: hello+between
513 devel-peer-request: pairs: 81 bytes
513 devel-peer-request: pairs: 81 bytes
514 sending hello command
514 sending hello command
515 sending between command
515 sending between command
516 remote: 440 (sshv1 !)
516 remote: 440 (sshv1 !)
517 protocol upgraded to exp-ssh-v2-0003 (sshv2 !)
517 protocol upgraded to exp-ssh-v2-0003 (sshv2 !)
518 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
518 remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
519 remote: 1 (sshv1 !)
519 remote: 1 (sshv1 !)
520 devel-peer-request: protocaps
520 devel-peer-request: protocaps
521 devel-peer-request: caps: * bytes (glob)
521 devel-peer-request: caps: * bytes (glob)
522 sending protocaps command
522 sending protocaps command
523 query 1; heads
523 query 1; heads
524 devel-peer-request: batched-content
524 devel-peer-request: batched-content
525 devel-peer-request: - heads (0 arguments)
525 devel-peer-request: - heads (0 arguments)
526 devel-peer-request: - known (1 arguments)
526 devel-peer-request: - known (1 arguments)
527 devel-peer-request: batch
527 devel-peer-request: batch
528 devel-peer-request: cmds: 141 bytes
528 devel-peer-request: cmds: 141 bytes
529 sending batch command
529 sending batch command
530 searching for changes
530 searching for changes
531 all remote heads known locally
531 all remote heads known locally
532 no changes found
532 no changes found
533 devel-peer-request: getbundle
533 devel-peer-request: getbundle
534 devel-peer-request: bookmarks: 1 bytes
534 devel-peer-request: bookmarks: 1 bytes
535 devel-peer-request: bundlecaps: 266 bytes
535 devel-peer-request: bundlecaps: 266 bytes
536 devel-peer-request: cg: 1 bytes
536 devel-peer-request: cg: 1 bytes
537 devel-peer-request: common: 122 bytes
537 devel-peer-request: common: 122 bytes
538 devel-peer-request: heads: 122 bytes
538 devel-peer-request: heads: 122 bytes
539 devel-peer-request: listkeys: 9 bytes
539 devel-peer-request: listkeys: 9 bytes
540 devel-peer-request: phases: 1 bytes
540 devel-peer-request: phases: 1 bytes
541 sending getbundle command
541 sending getbundle command
542 bundle2-input-bundle: with-transaction
542 bundle2-input-bundle: with-transaction
543 bundle2-input-part: "bookmarks" supported
543 bundle2-input-part: "bookmarks" supported
544 bundle2-input-part: total payload size 26
544 bundle2-input-part: total payload size 26
545 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
545 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
546 bundle2-input-part: total payload size 45
546 bundle2-input-part: total payload size 45
547 bundle2-input-part: "phase-heads" supported
547 bundle2-input-part: "phase-heads" supported
548 bundle2-input-part: total payload size 72
548 bundle2-input-part: total payload size 72
549 bundle2-input-bundle: 2 parts total
549 bundle2-input-bundle: 2 parts total
550 checking for updated bookmarks
550 checking for updated bookmarks
551
551
552 $ cd $TESTTMP
552 $ cd $TESTTMP
553
553
554 $ cat dummylog
554 $ cat dummylog
555 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
555 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
556 Got arguments 1:user@dummy 2:hg -R $TESTTMP/nonexistent serve --stdio
556 Got arguments 1:user@dummy 2:hg -R $TESTTMP/nonexistent serve --stdio
557 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
557 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
558 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio (no-reposimplestore !)
558 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio (no-reposimplestore !)
559 Got arguments 1:user@dummy 2:hg -R remote serve --stdio (no-reposimplestore !)
559 Got arguments 1:user@dummy 2:hg -R remote serve --stdio (no-reposimplestore !)
560 Got arguments 1:user@dummy 2:hg -R remote serve --stdio (no-reposimplestore !)
560 Got arguments 1:user@dummy 2:hg -R remote serve --stdio (no-reposimplestore !)
561 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
561 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
562 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
562 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
563 Got arguments 1:user@dummy 2:hg -R local serve --stdio
563 Got arguments 1:user@dummy 2:hg -R local serve --stdio
564 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
564 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
565 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
565 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
566 changegroup-in-remote hook: HG_BUNDLE2=1
566 changegroup-in-remote hook: HG_BUNDLE2=1
567 HG_HOOKNAME=changegroup
567 HG_HOOKNAME=changegroup
568 HG_HOOKTYPE=changegroup
568 HG_HOOKTYPE=changegroup
569 HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60
569 HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60
570 HG_NODE_LAST=a28a9d1a809cab7d4e2fde4bee738a9ede948b60
570 HG_NODE_LAST=a28a9d1a809cab7d4e2fde4bee738a9ede948b60
571 HG_SOURCE=serve
571 HG_SOURCE=serve
572 HG_TXNID=TXN:$ID$
572 HG_TXNID=TXN:$ID$
573 HG_TXNNAME=serve
573 HG_URL=remote:ssh:$LOCALIP
574 HG_URL=remote:ssh:$LOCALIP
574
575
575 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
576 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
576 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
577 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
577 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
578 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
578 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
579 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
579 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
580 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
580 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
581 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
581 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
582 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
582 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
583 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
583 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
584 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
584 changegroup-in-remote hook: HG_BUNDLE2=1
585 changegroup-in-remote hook: HG_BUNDLE2=1
585 HG_HOOKNAME=changegroup
586 HG_HOOKNAME=changegroup
586 HG_HOOKTYPE=changegroup
587 HG_HOOKTYPE=changegroup
587 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6
588 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6
588 HG_NODE_LAST=1383141674ec756a6056f6a9097618482fe0f4a6
589 HG_NODE_LAST=1383141674ec756a6056f6a9097618482fe0f4a6
589 HG_SOURCE=serve
590 HG_SOURCE=serve
590 HG_TXNID=TXN:$ID$
591 HG_TXNID=TXN:$ID$
592 HG_TXNNAME=serve
591 HG_URL=remote:ssh:$LOCALIP
593 HG_URL=remote:ssh:$LOCALIP
592
594
593 Got arguments 1:user@dummy 2:chg -R remote serve --stdio (chg !)
595 Got arguments 1:user@dummy 2:chg -R remote serve --stdio (chg !)
594 changegroup-in-remote hook: HG_BUNDLE2=1 (chg !)
596 changegroup-in-remote hook: HG_BUNDLE2=1 (chg !)
595 HG_HOOKNAME=changegroup (chg !)
597 HG_HOOKNAME=changegroup (chg !)
596 HG_HOOKTYPE=changegroup (chg !)
598 HG_HOOKTYPE=changegroup (chg !)
597 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 (chg !)
599 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 (chg !)
598 HG_NODE_LAST=1383141674ec756a6056f6a9097618482fe0f4a6 (chg !)
600 HG_NODE_LAST=1383141674ec756a6056f6a9097618482fe0f4a6 (chg !)
599 HG_SOURCE=serve (chg !)
601 HG_SOURCE=serve (chg !)
600 HG_TXNID=TXN:$ID$ (chg !)
602 HG_TXNID=TXN:$ID$ (chg !)
603 HG_TXNNAME=serve (chg !)
601 HG_URL=remote:ssh:$LOCALIP (chg !)
604 HG_URL=remote:ssh:$LOCALIP (chg !)
602 (chg !)
605 (chg !)
603 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
606 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
604 Got arguments 1:user@dummy 2:hg init 'a repo'
607 Got arguments 1:user@dummy 2:hg init 'a repo'
605 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
608 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
606 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
609 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
607 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
610 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
608 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
611 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
609 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
612 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
610 changegroup-in-remote hook: HG_BUNDLE2=1
613 changegroup-in-remote hook: HG_BUNDLE2=1
611 HG_HOOKNAME=changegroup
614 HG_HOOKNAME=changegroup
612 HG_HOOKTYPE=changegroup
615 HG_HOOKTYPE=changegroup
613 HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8
616 HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8
614 HG_NODE_LAST=65c38f4125f9602c8db4af56530cc221d93b8ef8
617 HG_NODE_LAST=65c38f4125f9602c8db4af56530cc221d93b8ef8
615 HG_SOURCE=serve
618 HG_SOURCE=serve
616 HG_TXNID=TXN:$ID$
619 HG_TXNID=TXN:$ID$
620 HG_TXNNAME=serve
617 HG_URL=remote:ssh:$LOCALIP
621 HG_URL=remote:ssh:$LOCALIP
618
622
619 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
623 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
620
624
621
625
622 remote hook failure is attributed to remote
626 remote hook failure is attributed to remote
623
627
624 $ cat > $TESTTMP/failhook << EOF
628 $ cat > $TESTTMP/failhook << EOF
625 > def hook(ui, repo, **kwargs):
629 > def hook(ui, repo, **kwargs):
626 > ui.write(b'hook failure!\n')
630 > ui.write(b'hook failure!\n')
627 > ui.flush()
631 > ui.flush()
628 > return 1
632 > return 1
629 > EOF
633 > EOF
630
634
631 $ echo "pretxnchangegroup.fail = python:$TESTTMP/failhook:hook" >> remote/.hg/hgrc
635 $ echo "pretxnchangegroup.fail = python:$TESTTMP/failhook:hook" >> remote/.hg/hgrc
632
636
633 $ hg -q --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" clone ssh://user@dummy/remote hookout
637 $ hg -q --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" clone ssh://user@dummy/remote hookout
634 $ cd hookout
638 $ cd hookout
635 $ touch hookfailure
639 $ touch hookfailure
636 $ hg -q commit -A -m 'remote hook failure'
640 $ hg -q commit -A -m 'remote hook failure'
637 $ hg --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" push
641 $ hg --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" push
638 pushing to ssh://user@dummy/remote
642 pushing to ssh://user@dummy/remote
639 searching for changes
643 searching for changes
640 remote: adding changesets
644 remote: adding changesets
641 remote: adding manifests
645 remote: adding manifests
642 remote: adding file changes
646 remote: adding file changes
643 remote: added 1 changesets with 1 changes to 1 files
647 remote: added 1 changesets with 1 changes to 1 files
644 remote: hook failure!
648 remote: hook failure!
645 remote: transaction abort!
649 remote: transaction abort!
646 remote: rollback completed
650 remote: rollback completed
647 remote: pretxnchangegroup.fail hook failed
651 remote: pretxnchangegroup.fail hook failed
648 abort: push failed on remote
652 abort: push failed on remote
649 [255]
653 [255]
650
654
651 abort during pull is properly reported as such
655 abort during pull is properly reported as such
652
656
653 $ echo morefoo >> ../remote/foo
657 $ echo morefoo >> ../remote/foo
654 $ hg -R ../remote commit --message "more foo to be pulled"
658 $ hg -R ../remote commit --message "more foo to be pulled"
655 $ cat >> ../remote/.hg/hgrc << EOF
659 $ cat >> ../remote/.hg/hgrc << EOF
656 > [extensions]
660 > [extensions]
657 > crash = ${TESTDIR}/crashgetbundler.py
661 > crash = ${TESTDIR}/crashgetbundler.py
658 > EOF
662 > EOF
659 $ hg --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" pull
663 $ hg --config ui.ssh="\"$PYTHON\" $TESTDIR/dummyssh" pull
660 pulling from ssh://user@dummy/remote
664 pulling from ssh://user@dummy/remote
661 searching for changes
665 searching for changes
662 remote: abort: this is an exercise
666 remote: abort: this is an exercise
663 abort: pull failed on remote
667 abort: pull failed on remote
664 [255]
668 [255]
665
669
666 abort with no error hint when there is a ssh problem when pulling
670 abort with no error hint when there is a ssh problem when pulling
667
671
668 $ hg pull ssh://brokenrepository -e "\"$PYTHON\" \"$TESTDIR/dummyssh\""
672 $ hg pull ssh://brokenrepository -e "\"$PYTHON\" \"$TESTDIR/dummyssh\""
669 pulling from ssh://brokenrepository/
673 pulling from ssh://brokenrepository/
670 abort: no suitable response from remote hg!
674 abort: no suitable response from remote hg!
671 [255]
675 [255]
672
676
673 abort with configured error hint when there is a ssh problem when pulling
677 abort with configured error hint when there is a ssh problem when pulling
674
678
675 $ hg pull ssh://brokenrepository -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" \
679 $ hg pull ssh://brokenrepository -e "\"$PYTHON\" \"$TESTDIR/dummyssh\"" \
676 > --config ui.ssherrorhint="Please see http://company/internalwiki/ssh.html"
680 > --config ui.ssherrorhint="Please see http://company/internalwiki/ssh.html"
677 pulling from ssh://brokenrepository/
681 pulling from ssh://brokenrepository/
678 abort: no suitable response from remote hg!
682 abort: no suitable response from remote hg!
679 (Please see http://company/internalwiki/ssh.html)
683 (Please see http://company/internalwiki/ssh.html)
680 [255]
684 [255]
681
685
682 test that custom environment is passed down to ssh executable
686 test that custom environment is passed down to ssh executable
683 $ cat >>dumpenv <<EOF
687 $ cat >>dumpenv <<EOF
684 > #! /bin/sh
688 > #! /bin/sh
685 > echo \$VAR >&2
689 > echo \$VAR >&2
686 > EOF
690 > EOF
687 $ chmod +x dumpenv
691 $ chmod +x dumpenv
688 $ hg pull ssh://something --config ui.ssh="sh dumpenv"
692 $ hg pull ssh://something --config ui.ssh="sh dumpenv"
689 pulling from ssh://something/
693 pulling from ssh://something/
690 remote:
694 remote:
691 abort: no suitable response from remote hg!
695 abort: no suitable response from remote hg!
692 [255]
696 [255]
693 $ hg pull ssh://something --config ui.ssh="sh dumpenv" --config sshenv.VAR=17
697 $ hg pull ssh://something --config ui.ssh="sh dumpenv" --config sshenv.VAR=17
694 pulling from ssh://something/
698 pulling from ssh://something/
695 remote: 17
699 remote: 17
696 abort: no suitable response from remote hg!
700 abort: no suitable response from remote hg!
697 [255]
701 [255]
698
702
@@ -1,292 +1,294 b''
1 #require no-reposimplestore
1 #require no-reposimplestore
2
2
3 $ hg clone http://localhost:$HGPORT/ copy
3 $ hg clone http://localhost:$HGPORT/ copy
4 abort: * (glob)
4 abort: * (glob)
5 [255]
5 [255]
6 $ test -d copy
6 $ test -d copy
7 [1]
7 [1]
8
8
9 This server doesn't do range requests so it's basically only good for
9 This server doesn't do range requests so it's basically only good for
10 one pull
10 one pull
11
11
12 $ "$PYTHON" "$TESTDIR/dumbhttp.py" -p $HGPORT --pid dumb.pid \
12 $ "$PYTHON" "$TESTDIR/dumbhttp.py" -p $HGPORT --pid dumb.pid \
13 > --logfile server.log
13 > --logfile server.log
14 $ cat dumb.pid >> $DAEMON_PIDS
14 $ cat dumb.pid >> $DAEMON_PIDS
15 $ hg init remote
15 $ hg init remote
16 $ cd remote
16 $ cd remote
17 $ echo foo > bar
17 $ echo foo > bar
18 $ echo c2 > '.dotfile with spaces'
18 $ echo c2 > '.dotfile with spaces'
19 $ hg add
19 $ hg add
20 adding .dotfile with spaces
20 adding .dotfile with spaces
21 adding bar
21 adding bar
22 $ hg commit -m"test"
22 $ hg commit -m"test"
23 $ hg tip
23 $ hg tip
24 changeset: 0:02770d679fb8
24 changeset: 0:02770d679fb8
25 tag: tip
25 tag: tip
26 user: test
26 user: test
27 date: Thu Jan 01 00:00:00 1970 +0000
27 date: Thu Jan 01 00:00:00 1970 +0000
28 summary: test
28 summary: test
29
29
30 $ cd ..
30 $ cd ..
31 $ hg clone static-http://localhost:$HGPORT/remote local
31 $ hg clone static-http://localhost:$HGPORT/remote local
32 requesting all changes
32 requesting all changes
33 adding changesets
33 adding changesets
34 adding manifests
34 adding manifests
35 adding file changes
35 adding file changes
36 added 1 changesets with 2 changes to 2 files
36 added 1 changesets with 2 changes to 2 files
37 new changesets 02770d679fb8
37 new changesets 02770d679fb8
38 updating to branch default
38 updating to branch default
39 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
39 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
40 $ cd local
40 $ cd local
41 $ hg verify
41 $ hg verify
42 checking changesets
42 checking changesets
43 checking manifests
43 checking manifests
44 crosschecking files in changesets and manifests
44 crosschecking files in changesets and manifests
45 checking files
45 checking files
46 checked 1 changesets with 2 changes to 2 files
46 checked 1 changesets with 2 changes to 2 files
47 $ cat bar
47 $ cat bar
48 foo
48 foo
49 $ cd ../remote
49 $ cd ../remote
50 $ echo baz > quux
50 $ echo baz > quux
51 $ hg commit -A -mtest2
51 $ hg commit -A -mtest2
52 adding quux
52 adding quux
53
53
54 check for HTTP opener failures when cachefile does not exist
54 check for HTTP opener failures when cachefile does not exist
55
55
56 $ rm .hg/cache/*
56 $ rm .hg/cache/*
57 $ cd ../local
57 $ cd ../local
58 $ cat >> .hg/hgrc <<EOF
58 $ cat >> .hg/hgrc <<EOF
59 > [hooks]
59 > [hooks]
60 > changegroup = sh -c "printenv.py --line changegroup"
60 > changegroup = sh -c "printenv.py --line changegroup"
61 > EOF
61 > EOF
62 $ hg pull
62 $ hg pull
63 pulling from static-http://localhost:$HGPORT/remote
63 pulling from static-http://localhost:$HGPORT/remote
64 searching for changes
64 searching for changes
65 adding changesets
65 adding changesets
66 adding manifests
66 adding manifests
67 adding file changes
67 adding file changes
68 added 1 changesets with 1 changes to 1 files
68 added 1 changesets with 1 changes to 1 files
69 new changesets 4ac2e3648604
69 new changesets 4ac2e3648604
70 changegroup hook: HG_HOOKNAME=changegroup
70 changegroup hook: HG_HOOKNAME=changegroup
71 HG_HOOKTYPE=changegroup
71 HG_HOOKTYPE=changegroup
72 HG_NODE=4ac2e3648604439c580c69b09ec9d93a88d93432
72 HG_NODE=4ac2e3648604439c580c69b09ec9d93a88d93432
73 HG_NODE_LAST=4ac2e3648604439c580c69b09ec9d93a88d93432
73 HG_NODE_LAST=4ac2e3648604439c580c69b09ec9d93a88d93432
74 HG_SOURCE=pull
74 HG_SOURCE=pull
75 HG_TXNID=TXN:$ID$
75 HG_TXNID=TXN:$ID$
76 HG_TXNNAME=pull
77 http://localhost:$HGPORT/remote
76 HG_URL=http://localhost:$HGPORT/remote
78 HG_URL=http://localhost:$HGPORT/remote
77
79
78 (run 'hg update' to get a working copy)
80 (run 'hg update' to get a working copy)
79
81
80 trying to push
82 trying to push
81
83
82 $ hg update
84 $ hg update
83 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
85 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 $ echo more foo >> bar
86 $ echo more foo >> bar
85 $ hg commit -m"test"
87 $ hg commit -m"test"
86 $ hg push
88 $ hg push
87 pushing to static-http://localhost:$HGPORT/remote
89 pushing to static-http://localhost:$HGPORT/remote
88 abort: destination does not support push
90 abort: destination does not support push
89 [255]
91 [255]
90
92
91 trying clone -r
93 trying clone -r
92
94
93 $ cd ..
95 $ cd ..
94 $ hg clone -r doesnotexist static-http://localhost:$HGPORT/remote local0
96 $ hg clone -r doesnotexist static-http://localhost:$HGPORT/remote local0
95 abort: unknown revision 'doesnotexist'!
97 abort: unknown revision 'doesnotexist'!
96 [255]
98 [255]
97 $ hg clone -r 0 static-http://localhost:$HGPORT/remote local0
99 $ hg clone -r 0 static-http://localhost:$HGPORT/remote local0
98 adding changesets
100 adding changesets
99 adding manifests
101 adding manifests
100 adding file changes
102 adding file changes
101 added 1 changesets with 2 changes to 2 files
103 added 1 changesets with 2 changes to 2 files
102 new changesets 02770d679fb8
104 new changesets 02770d679fb8
103 updating to branch default
105 updating to branch default
104 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
105
107
106 test with "/" URI (issue747) and subrepo
108 test with "/" URI (issue747) and subrepo
107
109
108 $ hg init
110 $ hg init
109 $ hg init sub
111 $ hg init sub
110 $ touch sub/test
112 $ touch sub/test
111 $ hg -R sub commit -A -m "test"
113 $ hg -R sub commit -A -m "test"
112 adding test
114 adding test
113 $ hg -R sub tag not-empty
115 $ hg -R sub tag not-empty
114 $ echo sub=sub > .hgsub
116 $ echo sub=sub > .hgsub
115 $ echo a > a
117 $ echo a > a
116 $ hg add a .hgsub
118 $ hg add a .hgsub
117 $ hg -q ci -ma
119 $ hg -q ci -ma
118 $ hg clone static-http://localhost:$HGPORT/ local2
120 $ hg clone static-http://localhost:$HGPORT/ local2
119 requesting all changes
121 requesting all changes
120 adding changesets
122 adding changesets
121 adding manifests
123 adding manifests
122 adding file changes
124 adding file changes
123 added 1 changesets with 3 changes to 3 files
125 added 1 changesets with 3 changes to 3 files
124 new changesets a9ebfbe8e587
126 new changesets a9ebfbe8e587
125 updating to branch default
127 updating to branch default
126 cloning subrepo sub from static-http://localhost:$HGPORT/sub
128 cloning subrepo sub from static-http://localhost:$HGPORT/sub
127 requesting all changes
129 requesting all changes
128 adding changesets
130 adding changesets
129 adding manifests
131 adding manifests
130 adding file changes
132 adding file changes
131 added 2 changesets with 2 changes to 2 files
133 added 2 changesets with 2 changes to 2 files
132 new changesets be090ea66256:322ea90975df
134 new changesets be090ea66256:322ea90975df
133 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
135 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
134 $ cd local2
136 $ cd local2
135 $ hg verify
137 $ hg verify
136 checking changesets
138 checking changesets
137 checking manifests
139 checking manifests
138 crosschecking files in changesets and manifests
140 crosschecking files in changesets and manifests
139 checking files
141 checking files
140 checked 1 changesets with 3 changes to 3 files
142 checked 1 changesets with 3 changes to 3 files
141 checking subrepo links
143 checking subrepo links
142 $ cat a
144 $ cat a
143 a
145 a
144 $ hg paths
146 $ hg paths
145 default = static-http://localhost:$HGPORT/
147 default = static-http://localhost:$HGPORT/
146
148
147 test with empty repo (issue965)
149 test with empty repo (issue965)
148
150
149 $ cd ..
151 $ cd ..
150 $ hg init remotempty
152 $ hg init remotempty
151 $ hg clone static-http://localhost:$HGPORT/remotempty local3
153 $ hg clone static-http://localhost:$HGPORT/remotempty local3
152 no changes found
154 no changes found
153 updating to branch default
155 updating to branch default
154 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
156 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 $ cd local3
157 $ cd local3
156 $ hg verify
158 $ hg verify
157 checking changesets
159 checking changesets
158 checking manifests
160 checking manifests
159 crosschecking files in changesets and manifests
161 crosschecking files in changesets and manifests
160 checking files
162 checking files
161 checked 0 changesets with 0 changes to 0 files
163 checked 0 changesets with 0 changes to 0 files
162 $ hg paths
164 $ hg paths
163 default = static-http://localhost:$HGPORT/remotempty
165 default = static-http://localhost:$HGPORT/remotempty
164
166
165 test with non-repo
167 test with non-repo
166
168
167 $ cd ..
169 $ cd ..
168 $ mkdir notarepo
170 $ mkdir notarepo
169 $ hg clone static-http://localhost:$HGPORT/notarepo local3
171 $ hg clone static-http://localhost:$HGPORT/notarepo local3
170 abort: 'http://localhost:$HGPORT/notarepo' does not appear to be an hg repository!
172 abort: 'http://localhost:$HGPORT/notarepo' does not appear to be an hg repository!
171 [255]
173 [255]
172
174
173 Clone with tags and branches works
175 Clone with tags and branches works
174
176
175 $ hg init remote-with-names
177 $ hg init remote-with-names
176 $ cd remote-with-names
178 $ cd remote-with-names
177 $ echo 0 > foo
179 $ echo 0 > foo
178 $ hg -q commit -A -m initial
180 $ hg -q commit -A -m initial
179 $ echo 1 > foo
181 $ echo 1 > foo
180 $ hg commit -m 'commit 1'
182 $ hg commit -m 'commit 1'
181 $ hg -q up 0
183 $ hg -q up 0
182 $ hg branch mybranch
184 $ hg branch mybranch
183 marked working directory as branch mybranch
185 marked working directory as branch mybranch
184 (branches are permanent and global, did you want a bookmark?)
186 (branches are permanent and global, did you want a bookmark?)
185 $ echo 2 > foo
187 $ echo 2 > foo
186 $ hg commit -m 'commit 2 (mybranch)'
188 $ hg commit -m 'commit 2 (mybranch)'
187 $ hg tag -r 1 'default-tag'
189 $ hg tag -r 1 'default-tag'
188 $ hg tag -r 2 'branch-tag'
190 $ hg tag -r 2 'branch-tag'
189
191
190 $ cd ..
192 $ cd ..
191
193
192 $ hg clone static-http://localhost:$HGPORT/remote-with-names local-with-names
194 $ hg clone static-http://localhost:$HGPORT/remote-with-names local-with-names
193 requesting all changes
195 requesting all changes
194 adding changesets
196 adding changesets
195 adding manifests
197 adding manifests
196 adding file changes
198 adding file changes
197 added 5 changesets with 5 changes to 2 files (+1 heads)
199 added 5 changesets with 5 changes to 2 files (+1 heads)
198 new changesets 68986213bd44:0c325bd2b5a7
200 new changesets 68986213bd44:0c325bd2b5a7
199 updating to branch default
201 updating to branch default
200 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
202 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
201
203
202 Clone a specific branch works
204 Clone a specific branch works
203
205
204 $ hg clone -r mybranch static-http://localhost:$HGPORT/remote-with-names local-with-names-branch
206 $ hg clone -r mybranch static-http://localhost:$HGPORT/remote-with-names local-with-names-branch
205 adding changesets
207 adding changesets
206 adding manifests
208 adding manifests
207 adding file changes
209 adding file changes
208 added 4 changesets with 4 changes to 2 files
210 added 4 changesets with 4 changes to 2 files
209 new changesets 68986213bd44:0c325bd2b5a7
211 new changesets 68986213bd44:0c325bd2b5a7
210 updating to branch mybranch
212 updating to branch mybranch
211 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
213 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
212
214
213 Clone a specific tag works
215 Clone a specific tag works
214
216
215 $ hg clone -r default-tag static-http://localhost:$HGPORT/remote-with-names local-with-names-tag
217 $ hg clone -r default-tag static-http://localhost:$HGPORT/remote-with-names local-with-names-tag
216 adding changesets
218 adding changesets
217 adding manifests
219 adding manifests
218 adding file changes
220 adding file changes
219 added 2 changesets with 2 changes to 1 files
221 added 2 changesets with 2 changes to 1 files
220 new changesets 68986213bd44:4ee3fcef1c80
222 new changesets 68986213bd44:4ee3fcef1c80
221 updating to branch default
223 updating to branch default
222 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
224 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
223
225
224 $ killdaemons.py
226 $ killdaemons.py
225
227
226 List of files accessed over HTTP:
228 List of files accessed over HTTP:
227
229
228 $ cat server.log | sed -n -e 's|.*GET \(/[^ ]*\).*|\1|p' | sort -u
230 $ cat server.log | sed -n -e 's|.*GET \(/[^ ]*\).*|\1|p' | sort -u
229 /.hg/bookmarks
231 /.hg/bookmarks
230 /.hg/bookmarks.current
232 /.hg/bookmarks.current
231 /.hg/cache/hgtagsfnodes1
233 /.hg/cache/hgtagsfnodes1
232 /.hg/cache/rbc-names-v1
234 /.hg/cache/rbc-names-v1
233 /.hg/cache/rbc-revs-v1
235 /.hg/cache/rbc-revs-v1
234 /.hg/requires
236 /.hg/requires
235 /.hg/store/00changelog.i
237 /.hg/store/00changelog.i
236 /.hg/store/00manifest.i
238 /.hg/store/00manifest.i
237 /.hg/store/data/%7E2ehgsub.i (no-py37 !)
239 /.hg/store/data/%7E2ehgsub.i (no-py37 !)
238 /.hg/store/data/%7E2ehgsubstate.i (no-py37 !)
240 /.hg/store/data/%7E2ehgsubstate.i (no-py37 !)
239 /.hg/store/data/a.i
241 /.hg/store/data/a.i
240 /.hg/store/data/~2ehgsub.i (py37 !)
242 /.hg/store/data/~2ehgsub.i (py37 !)
241 /.hg/store/data/~2ehgsubstate.i (py37 !)
243 /.hg/store/data/~2ehgsubstate.i (py37 !)
242 /notarepo/.hg/00changelog.i
244 /notarepo/.hg/00changelog.i
243 /notarepo/.hg/requires
245 /notarepo/.hg/requires
244 /remote-with-names/.hg/bookmarks
246 /remote-with-names/.hg/bookmarks
245 /remote-with-names/.hg/bookmarks.current
247 /remote-with-names/.hg/bookmarks.current
246 /remote-with-names/.hg/cache/branch2-served
248 /remote-with-names/.hg/cache/branch2-served
247 /remote-with-names/.hg/cache/hgtagsfnodes1
249 /remote-with-names/.hg/cache/hgtagsfnodes1
248 /remote-with-names/.hg/cache/rbc-names-v1
250 /remote-with-names/.hg/cache/rbc-names-v1
249 /remote-with-names/.hg/cache/rbc-revs-v1
251 /remote-with-names/.hg/cache/rbc-revs-v1
250 /remote-with-names/.hg/cache/tags2-served
252 /remote-with-names/.hg/cache/tags2-served
251 /remote-with-names/.hg/localtags
253 /remote-with-names/.hg/localtags
252 /remote-with-names/.hg/requires
254 /remote-with-names/.hg/requires
253 /remote-with-names/.hg/store/00changelog.i
255 /remote-with-names/.hg/store/00changelog.i
254 /remote-with-names/.hg/store/00manifest.i
256 /remote-with-names/.hg/store/00manifest.i
255 /remote-with-names/.hg/store/data/%7E2ehgtags.i (no-py37 !)
257 /remote-with-names/.hg/store/data/%7E2ehgtags.i (no-py37 !)
256 /remote-with-names/.hg/store/data/foo.i
258 /remote-with-names/.hg/store/data/foo.i
257 /remote-with-names/.hg/store/data/~2ehgtags.i (py37 !)
259 /remote-with-names/.hg/store/data/~2ehgtags.i (py37 !)
258 /remote/.hg/bookmarks
260 /remote/.hg/bookmarks
259 /remote/.hg/bookmarks.current
261 /remote/.hg/bookmarks.current
260 /remote/.hg/cache/branch2-base
262 /remote/.hg/cache/branch2-base
261 /remote/.hg/cache/branch2-immutable
263 /remote/.hg/cache/branch2-immutable
262 /remote/.hg/cache/branch2-served
264 /remote/.hg/cache/branch2-served
263 /remote/.hg/cache/hgtagsfnodes1
265 /remote/.hg/cache/hgtagsfnodes1
264 /remote/.hg/cache/rbc-names-v1
266 /remote/.hg/cache/rbc-names-v1
265 /remote/.hg/cache/rbc-revs-v1
267 /remote/.hg/cache/rbc-revs-v1
266 /remote/.hg/cache/tags2-served
268 /remote/.hg/cache/tags2-served
267 /remote/.hg/localtags
269 /remote/.hg/localtags
268 /remote/.hg/requires
270 /remote/.hg/requires
269 /remote/.hg/store/00changelog.i
271 /remote/.hg/store/00changelog.i
270 /remote/.hg/store/00manifest.i
272 /remote/.hg/store/00manifest.i
271 /remote/.hg/store/data/%7E2edotfile%20with%20spaces.i (no-py37 !)
273 /remote/.hg/store/data/%7E2edotfile%20with%20spaces.i (no-py37 !)
272 /remote/.hg/store/data/%7E2ehgtags.i (no-py37 !)
274 /remote/.hg/store/data/%7E2ehgtags.i (no-py37 !)
273 /remote/.hg/store/data/bar.i
275 /remote/.hg/store/data/bar.i
274 /remote/.hg/store/data/quux.i
276 /remote/.hg/store/data/quux.i
275 /remote/.hg/store/data/~2edotfile%20with%20spaces.i (py37 !)
277 /remote/.hg/store/data/~2edotfile%20with%20spaces.i (py37 !)
276 /remote/.hg/store/data/~2ehgtags.i (py37 !)
278 /remote/.hg/store/data/~2ehgtags.i (py37 !)
277 /remotempty/.hg/bookmarks
279 /remotempty/.hg/bookmarks
278 /remotempty/.hg/bookmarks.current
280 /remotempty/.hg/bookmarks.current
279 /remotempty/.hg/requires
281 /remotempty/.hg/requires
280 /remotempty/.hg/store/00changelog.i
282 /remotempty/.hg/store/00changelog.i
281 /remotempty/.hg/store/00manifest.i
283 /remotempty/.hg/store/00manifest.i
282 /sub/.hg/bookmarks
284 /sub/.hg/bookmarks
283 /sub/.hg/bookmarks.current
285 /sub/.hg/bookmarks.current
284 /sub/.hg/cache/hgtagsfnodes1
286 /sub/.hg/cache/hgtagsfnodes1
285 /sub/.hg/cache/rbc-names-v1
287 /sub/.hg/cache/rbc-names-v1
286 /sub/.hg/cache/rbc-revs-v1
288 /sub/.hg/cache/rbc-revs-v1
287 /sub/.hg/requires
289 /sub/.hg/requires
288 /sub/.hg/store/00changelog.i
290 /sub/.hg/store/00changelog.i
289 /sub/.hg/store/00manifest.i
291 /sub/.hg/store/00manifest.i
290 /sub/.hg/store/data/%7E2ehgtags.i (no-py37 !)
292 /sub/.hg/store/data/%7E2ehgtags.i (no-py37 !)
291 /sub/.hg/store/data/test.i
293 /sub/.hg/store/data/test.i
292 /sub/.hg/store/data/~2ehgtags.i (py37 !)
294 /sub/.hg/store/data/~2ehgtags.i (py37 !)
General Comments 0
You need to be logged in to leave comments. Login now