##// END OF EJS Templates
debugwalk: show matcher output only if -v/--verbose...
Yuya Nishihara -
r38281:7c3a59e2 default
parent child Browse files
Show More
@@ -1,3137 +1,3138 b''
1 # debugcommands.py - command processing for debug* commands
1 # debugcommands.py - command processing for debug* commands
2 #
2 #
3 # Copyright 2005-2016 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2016 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 codecs
10 import codecs
11 import collections
11 import collections
12 import difflib
12 import difflib
13 import errno
13 import errno
14 import operator
14 import operator
15 import os
15 import os
16 import random
16 import random
17 import re
17 import re
18 import socket
18 import socket
19 import ssl
19 import ssl
20 import stat
20 import stat
21 import string
21 import string
22 import subprocess
22 import subprocess
23 import sys
23 import sys
24 import time
24 import time
25
25
26 from .i18n import _
26 from .i18n import _
27 from .node import (
27 from .node import (
28 bin,
28 bin,
29 hex,
29 hex,
30 nullhex,
30 nullhex,
31 nullid,
31 nullid,
32 nullrev,
32 nullrev,
33 short,
33 short,
34 )
34 )
35 from .thirdparty import (
35 from .thirdparty import (
36 cbor,
36 cbor,
37 )
37 )
38 from . import (
38 from . import (
39 bundle2,
39 bundle2,
40 changegroup,
40 changegroup,
41 cmdutil,
41 cmdutil,
42 color,
42 color,
43 context,
43 context,
44 dagparser,
44 dagparser,
45 dagutil,
45 dagutil,
46 encoding,
46 encoding,
47 error,
47 error,
48 exchange,
48 exchange,
49 extensions,
49 extensions,
50 filemerge,
50 filemerge,
51 fileset,
51 fileset,
52 formatter,
52 formatter,
53 hg,
53 hg,
54 httppeer,
54 httppeer,
55 localrepo,
55 localrepo,
56 lock as lockmod,
56 lock as lockmod,
57 logcmdutil,
57 logcmdutil,
58 merge as mergemod,
58 merge as mergemod,
59 obsolete,
59 obsolete,
60 obsutil,
60 obsutil,
61 phases,
61 phases,
62 policy,
62 policy,
63 pvec,
63 pvec,
64 pycompat,
64 pycompat,
65 registrar,
65 registrar,
66 repair,
66 repair,
67 revlog,
67 revlog,
68 revset,
68 revset,
69 revsetlang,
69 revsetlang,
70 scmutil,
70 scmutil,
71 setdiscovery,
71 setdiscovery,
72 simplemerge,
72 simplemerge,
73 sshpeer,
73 sshpeer,
74 sslutil,
74 sslutil,
75 streamclone,
75 streamclone,
76 templater,
76 templater,
77 treediscovery,
77 treediscovery,
78 upgrade,
78 upgrade,
79 url as urlmod,
79 url as urlmod,
80 util,
80 util,
81 vfs as vfsmod,
81 vfs as vfsmod,
82 wireprotoframing,
82 wireprotoframing,
83 wireprotoserver,
83 wireprotoserver,
84 wireprotov2peer,
84 wireprotov2peer,
85 )
85 )
86 from .utils import (
86 from .utils import (
87 dateutil,
87 dateutil,
88 procutil,
88 procutil,
89 stringutil,
89 stringutil,
90 )
90 )
91
91
92 release = lockmod.release
92 release = lockmod.release
93
93
94 command = registrar.command()
94 command = registrar.command()
95
95
96 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
96 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
97 def debugancestor(ui, repo, *args):
97 def debugancestor(ui, repo, *args):
98 """find the ancestor revision of two revisions in a given index"""
98 """find the ancestor revision of two revisions in a given index"""
99 if len(args) == 3:
99 if len(args) == 3:
100 index, rev1, rev2 = args
100 index, rev1, rev2 = args
101 r = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False), index)
101 r = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False), index)
102 lookup = r.lookup
102 lookup = r.lookup
103 elif len(args) == 2:
103 elif len(args) == 2:
104 if not repo:
104 if not repo:
105 raise error.Abort(_('there is no Mercurial repository here '
105 raise error.Abort(_('there is no Mercurial repository here '
106 '(.hg not found)'))
106 '(.hg not found)'))
107 rev1, rev2 = args
107 rev1, rev2 = args
108 r = repo.changelog
108 r = repo.changelog
109 lookup = repo.lookup
109 lookup = repo.lookup
110 else:
110 else:
111 raise error.Abort(_('either two or three arguments required'))
111 raise error.Abort(_('either two or three arguments required'))
112 a = r.ancestor(lookup(rev1), lookup(rev2))
112 a = r.ancestor(lookup(rev1), lookup(rev2))
113 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
113 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
114
114
115 @command('debugapplystreamclonebundle', [], 'FILE')
115 @command('debugapplystreamclonebundle', [], 'FILE')
116 def debugapplystreamclonebundle(ui, repo, fname):
116 def debugapplystreamclonebundle(ui, repo, fname):
117 """apply a stream clone bundle file"""
117 """apply a stream clone bundle file"""
118 f = hg.openpath(ui, fname)
118 f = hg.openpath(ui, fname)
119 gen = exchange.readbundle(ui, f, fname)
119 gen = exchange.readbundle(ui, f, fname)
120 gen.apply(repo)
120 gen.apply(repo)
121
121
122 @command('debugbuilddag',
122 @command('debugbuilddag',
123 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
123 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
124 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
124 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
125 ('n', 'new-file', None, _('add new file at each rev'))],
125 ('n', 'new-file', None, _('add new file at each rev'))],
126 _('[OPTION]... [TEXT]'))
126 _('[OPTION]... [TEXT]'))
127 def debugbuilddag(ui, repo, text=None,
127 def debugbuilddag(ui, repo, text=None,
128 mergeable_file=False,
128 mergeable_file=False,
129 overwritten_file=False,
129 overwritten_file=False,
130 new_file=False):
130 new_file=False):
131 """builds a repo with a given DAG from scratch in the current empty repo
131 """builds a repo with a given DAG from scratch in the current empty repo
132
132
133 The description of the DAG is read from stdin if not given on the
133 The description of the DAG is read from stdin if not given on the
134 command line.
134 command line.
135
135
136 Elements:
136 Elements:
137
137
138 - "+n" is a linear run of n nodes based on the current default parent
138 - "+n" is a linear run of n nodes based on the current default parent
139 - "." is a single node based on the current default parent
139 - "." is a single node based on the current default parent
140 - "$" resets the default parent to null (implied at the start);
140 - "$" resets the default parent to null (implied at the start);
141 otherwise the default parent is always the last node created
141 otherwise the default parent is always the last node created
142 - "<p" sets the default parent to the backref p
142 - "<p" sets the default parent to the backref p
143 - "*p" is a fork at parent p, which is a backref
143 - "*p" is a fork at parent p, which is a backref
144 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
144 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
145 - "/p2" is a merge of the preceding node and p2
145 - "/p2" is a merge of the preceding node and p2
146 - ":tag" defines a local tag for the preceding node
146 - ":tag" defines a local tag for the preceding node
147 - "@branch" sets the named branch for subsequent nodes
147 - "@branch" sets the named branch for subsequent nodes
148 - "#...\\n" is a comment up to the end of the line
148 - "#...\\n" is a comment up to the end of the line
149
149
150 Whitespace between the above elements is ignored.
150 Whitespace between the above elements is ignored.
151
151
152 A backref is either
152 A backref is either
153
153
154 - a number n, which references the node curr-n, where curr is the current
154 - a number n, which references the node curr-n, where curr is the current
155 node, or
155 node, or
156 - the name of a local tag you placed earlier using ":tag", or
156 - the name of a local tag you placed earlier using ":tag", or
157 - empty to denote the default parent.
157 - empty to denote the default parent.
158
158
159 All string valued-elements are either strictly alphanumeric, or must
159 All string valued-elements are either strictly alphanumeric, or must
160 be enclosed in double quotes ("..."), with "\\" as escape character.
160 be enclosed in double quotes ("..."), with "\\" as escape character.
161 """
161 """
162
162
163 if text is None:
163 if text is None:
164 ui.status(_("reading DAG from stdin\n"))
164 ui.status(_("reading DAG from stdin\n"))
165 text = ui.fin.read()
165 text = ui.fin.read()
166
166
167 cl = repo.changelog
167 cl = repo.changelog
168 if len(cl) > 0:
168 if len(cl) > 0:
169 raise error.Abort(_('repository is not empty'))
169 raise error.Abort(_('repository is not empty'))
170
170
171 # determine number of revs in DAG
171 # determine number of revs in DAG
172 total = 0
172 total = 0
173 for type, data in dagparser.parsedag(text):
173 for type, data in dagparser.parsedag(text):
174 if type == 'n':
174 if type == 'n':
175 total += 1
175 total += 1
176
176
177 if mergeable_file:
177 if mergeable_file:
178 linesperrev = 2
178 linesperrev = 2
179 # make a file with k lines per rev
179 # make a file with k lines per rev
180 initialmergedlines = ['%d' % i for i in xrange(0, total * linesperrev)]
180 initialmergedlines = ['%d' % i for i in xrange(0, total * linesperrev)]
181 initialmergedlines.append("")
181 initialmergedlines.append("")
182
182
183 tags = []
183 tags = []
184
184
185 wlock = lock = tr = None
185 wlock = lock = tr = None
186 try:
186 try:
187 wlock = repo.wlock()
187 wlock = repo.wlock()
188 lock = repo.lock()
188 lock = repo.lock()
189 tr = repo.transaction("builddag")
189 tr = repo.transaction("builddag")
190
190
191 at = -1
191 at = -1
192 atbranch = 'default'
192 atbranch = 'default'
193 nodeids = []
193 nodeids = []
194 id = 0
194 id = 0
195 ui.progress(_('building'), id, unit=_('revisions'), total=total)
195 ui.progress(_('building'), id, unit=_('revisions'), total=total)
196 for type, data in dagparser.parsedag(text):
196 for type, data in dagparser.parsedag(text):
197 if type == 'n':
197 if type == 'n':
198 ui.note(('node %s\n' % pycompat.bytestr(data)))
198 ui.note(('node %s\n' % pycompat.bytestr(data)))
199 id, ps = data
199 id, ps = data
200
200
201 files = []
201 files = []
202 filecontent = {}
202 filecontent = {}
203
203
204 p2 = None
204 p2 = None
205 if mergeable_file:
205 if mergeable_file:
206 fn = "mf"
206 fn = "mf"
207 p1 = repo[ps[0]]
207 p1 = repo[ps[0]]
208 if len(ps) > 1:
208 if len(ps) > 1:
209 p2 = repo[ps[1]]
209 p2 = repo[ps[1]]
210 pa = p1.ancestor(p2)
210 pa = p1.ancestor(p2)
211 base, local, other = [x[fn].data() for x in (pa, p1,
211 base, local, other = [x[fn].data() for x in (pa, p1,
212 p2)]
212 p2)]
213 m3 = simplemerge.Merge3Text(base, local, other)
213 m3 = simplemerge.Merge3Text(base, local, other)
214 ml = [l.strip() for l in m3.merge_lines()]
214 ml = [l.strip() for l in m3.merge_lines()]
215 ml.append("")
215 ml.append("")
216 elif at > 0:
216 elif at > 0:
217 ml = p1[fn].data().split("\n")
217 ml = p1[fn].data().split("\n")
218 else:
218 else:
219 ml = initialmergedlines
219 ml = initialmergedlines
220 ml[id * linesperrev] += " r%i" % id
220 ml[id * linesperrev] += " r%i" % id
221 mergedtext = "\n".join(ml)
221 mergedtext = "\n".join(ml)
222 files.append(fn)
222 files.append(fn)
223 filecontent[fn] = mergedtext
223 filecontent[fn] = mergedtext
224
224
225 if overwritten_file:
225 if overwritten_file:
226 fn = "of"
226 fn = "of"
227 files.append(fn)
227 files.append(fn)
228 filecontent[fn] = "r%i\n" % id
228 filecontent[fn] = "r%i\n" % id
229
229
230 if new_file:
230 if new_file:
231 fn = "nf%i" % id
231 fn = "nf%i" % id
232 files.append(fn)
232 files.append(fn)
233 filecontent[fn] = "r%i\n" % id
233 filecontent[fn] = "r%i\n" % id
234 if len(ps) > 1:
234 if len(ps) > 1:
235 if not p2:
235 if not p2:
236 p2 = repo[ps[1]]
236 p2 = repo[ps[1]]
237 for fn in p2:
237 for fn in p2:
238 if fn.startswith("nf"):
238 if fn.startswith("nf"):
239 files.append(fn)
239 files.append(fn)
240 filecontent[fn] = p2[fn].data()
240 filecontent[fn] = p2[fn].data()
241
241
242 def fctxfn(repo, cx, path):
242 def fctxfn(repo, cx, path):
243 if path in filecontent:
243 if path in filecontent:
244 return context.memfilectx(repo, cx, path,
244 return context.memfilectx(repo, cx, path,
245 filecontent[path])
245 filecontent[path])
246 return None
246 return None
247
247
248 if len(ps) == 0 or ps[0] < 0:
248 if len(ps) == 0 or ps[0] < 0:
249 pars = [None, None]
249 pars = [None, None]
250 elif len(ps) == 1:
250 elif len(ps) == 1:
251 pars = [nodeids[ps[0]], None]
251 pars = [nodeids[ps[0]], None]
252 else:
252 else:
253 pars = [nodeids[p] for p in ps]
253 pars = [nodeids[p] for p in ps]
254 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
254 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
255 date=(id, 0),
255 date=(id, 0),
256 user="debugbuilddag",
256 user="debugbuilddag",
257 extra={'branch': atbranch})
257 extra={'branch': atbranch})
258 nodeid = repo.commitctx(cx)
258 nodeid = repo.commitctx(cx)
259 nodeids.append(nodeid)
259 nodeids.append(nodeid)
260 at = id
260 at = id
261 elif type == 'l':
261 elif type == 'l':
262 id, name = data
262 id, name = data
263 ui.note(('tag %s\n' % name))
263 ui.note(('tag %s\n' % name))
264 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
264 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
265 elif type == 'a':
265 elif type == 'a':
266 ui.note(('branch %s\n' % data))
266 ui.note(('branch %s\n' % data))
267 atbranch = data
267 atbranch = data
268 ui.progress(_('building'), id, unit=_('revisions'), total=total)
268 ui.progress(_('building'), id, unit=_('revisions'), total=total)
269 tr.close()
269 tr.close()
270
270
271 if tags:
271 if tags:
272 repo.vfs.write("localtags", "".join(tags))
272 repo.vfs.write("localtags", "".join(tags))
273 finally:
273 finally:
274 ui.progress(_('building'), None)
274 ui.progress(_('building'), None)
275 release(tr, lock, wlock)
275 release(tr, lock, wlock)
276
276
277 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
277 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
278 indent_string = ' ' * indent
278 indent_string = ' ' * indent
279 if all:
279 if all:
280 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
280 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
281 % indent_string)
281 % indent_string)
282
282
283 def showchunks(named):
283 def showchunks(named):
284 ui.write("\n%s%s\n" % (indent_string, named))
284 ui.write("\n%s%s\n" % (indent_string, named))
285 for deltadata in gen.deltaiter():
285 for deltadata in gen.deltaiter():
286 node, p1, p2, cs, deltabase, delta, flags = deltadata
286 node, p1, p2, cs, deltabase, delta, flags = deltadata
287 ui.write("%s%s %s %s %s %s %d\n" %
287 ui.write("%s%s %s %s %s %s %d\n" %
288 (indent_string, hex(node), hex(p1), hex(p2),
288 (indent_string, hex(node), hex(p1), hex(p2),
289 hex(cs), hex(deltabase), len(delta)))
289 hex(cs), hex(deltabase), len(delta)))
290
290
291 chunkdata = gen.changelogheader()
291 chunkdata = gen.changelogheader()
292 showchunks("changelog")
292 showchunks("changelog")
293 chunkdata = gen.manifestheader()
293 chunkdata = gen.manifestheader()
294 showchunks("manifest")
294 showchunks("manifest")
295 for chunkdata in iter(gen.filelogheader, {}):
295 for chunkdata in iter(gen.filelogheader, {}):
296 fname = chunkdata['filename']
296 fname = chunkdata['filename']
297 showchunks(fname)
297 showchunks(fname)
298 else:
298 else:
299 if isinstance(gen, bundle2.unbundle20):
299 if isinstance(gen, bundle2.unbundle20):
300 raise error.Abort(_('use debugbundle2 for this file'))
300 raise error.Abort(_('use debugbundle2 for this file'))
301 chunkdata = gen.changelogheader()
301 chunkdata = gen.changelogheader()
302 for deltadata in gen.deltaiter():
302 for deltadata in gen.deltaiter():
303 node, p1, p2, cs, deltabase, delta, flags = deltadata
303 node, p1, p2, cs, deltabase, delta, flags = deltadata
304 ui.write("%s%s\n" % (indent_string, hex(node)))
304 ui.write("%s%s\n" % (indent_string, hex(node)))
305
305
306 def _debugobsmarkers(ui, part, indent=0, **opts):
306 def _debugobsmarkers(ui, part, indent=0, **opts):
307 """display version and markers contained in 'data'"""
307 """display version and markers contained in 'data'"""
308 opts = pycompat.byteskwargs(opts)
308 opts = pycompat.byteskwargs(opts)
309 data = part.read()
309 data = part.read()
310 indent_string = ' ' * indent
310 indent_string = ' ' * indent
311 try:
311 try:
312 version, markers = obsolete._readmarkers(data)
312 version, markers = obsolete._readmarkers(data)
313 except error.UnknownVersion as exc:
313 except error.UnknownVersion as exc:
314 msg = "%sunsupported version: %s (%d bytes)\n"
314 msg = "%sunsupported version: %s (%d bytes)\n"
315 msg %= indent_string, exc.version, len(data)
315 msg %= indent_string, exc.version, len(data)
316 ui.write(msg)
316 ui.write(msg)
317 else:
317 else:
318 msg = "%sversion: %d (%d bytes)\n"
318 msg = "%sversion: %d (%d bytes)\n"
319 msg %= indent_string, version, len(data)
319 msg %= indent_string, version, len(data)
320 ui.write(msg)
320 ui.write(msg)
321 fm = ui.formatter('debugobsolete', opts)
321 fm = ui.formatter('debugobsolete', opts)
322 for rawmarker in sorted(markers):
322 for rawmarker in sorted(markers):
323 m = obsutil.marker(None, rawmarker)
323 m = obsutil.marker(None, rawmarker)
324 fm.startitem()
324 fm.startitem()
325 fm.plain(indent_string)
325 fm.plain(indent_string)
326 cmdutil.showmarker(fm, m)
326 cmdutil.showmarker(fm, m)
327 fm.end()
327 fm.end()
328
328
329 def _debugphaseheads(ui, data, indent=0):
329 def _debugphaseheads(ui, data, indent=0):
330 """display version and markers contained in 'data'"""
330 """display version and markers contained in 'data'"""
331 indent_string = ' ' * indent
331 indent_string = ' ' * indent
332 headsbyphase = phases.binarydecode(data)
332 headsbyphase = phases.binarydecode(data)
333 for phase in phases.allphases:
333 for phase in phases.allphases:
334 for head in headsbyphase[phase]:
334 for head in headsbyphase[phase]:
335 ui.write(indent_string)
335 ui.write(indent_string)
336 ui.write('%s %s\n' % (hex(head), phases.phasenames[phase]))
336 ui.write('%s %s\n' % (hex(head), phases.phasenames[phase]))
337
337
338 def _quasirepr(thing):
338 def _quasirepr(thing):
339 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
339 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
340 return '{%s}' % (
340 return '{%s}' % (
341 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing)))
341 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing)))
342 return pycompat.bytestr(repr(thing))
342 return pycompat.bytestr(repr(thing))
343
343
344 def _debugbundle2(ui, gen, all=None, **opts):
344 def _debugbundle2(ui, gen, all=None, **opts):
345 """lists the contents of a bundle2"""
345 """lists the contents of a bundle2"""
346 if not isinstance(gen, bundle2.unbundle20):
346 if not isinstance(gen, bundle2.unbundle20):
347 raise error.Abort(_('not a bundle2 file'))
347 raise error.Abort(_('not a bundle2 file'))
348 ui.write(('Stream params: %s\n' % _quasirepr(gen.params)))
348 ui.write(('Stream params: %s\n' % _quasirepr(gen.params)))
349 parttypes = opts.get(r'part_type', [])
349 parttypes = opts.get(r'part_type', [])
350 for part in gen.iterparts():
350 for part in gen.iterparts():
351 if parttypes and part.type not in parttypes:
351 if parttypes and part.type not in parttypes:
352 continue
352 continue
353 msg = '%s -- %s (mandatory: %r)\n'
353 msg = '%s -- %s (mandatory: %r)\n'
354 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
354 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
355 if part.type == 'changegroup':
355 if part.type == 'changegroup':
356 version = part.params.get('version', '01')
356 version = part.params.get('version', '01')
357 cg = changegroup.getunbundler(version, part, 'UN')
357 cg = changegroup.getunbundler(version, part, 'UN')
358 if not ui.quiet:
358 if not ui.quiet:
359 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
359 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
360 if part.type == 'obsmarkers':
360 if part.type == 'obsmarkers':
361 if not ui.quiet:
361 if not ui.quiet:
362 _debugobsmarkers(ui, part, indent=4, **opts)
362 _debugobsmarkers(ui, part, indent=4, **opts)
363 if part.type == 'phase-heads':
363 if part.type == 'phase-heads':
364 if not ui.quiet:
364 if not ui.quiet:
365 _debugphaseheads(ui, part, indent=4)
365 _debugphaseheads(ui, part, indent=4)
366
366
367 @command('debugbundle',
367 @command('debugbundle',
368 [('a', 'all', None, _('show all details')),
368 [('a', 'all', None, _('show all details')),
369 ('', 'part-type', [], _('show only the named part type')),
369 ('', 'part-type', [], _('show only the named part type')),
370 ('', 'spec', None, _('print the bundlespec of the bundle'))],
370 ('', 'spec', None, _('print the bundlespec of the bundle'))],
371 _('FILE'),
371 _('FILE'),
372 norepo=True)
372 norepo=True)
373 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
373 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
374 """lists the contents of a bundle"""
374 """lists the contents of a bundle"""
375 with hg.openpath(ui, bundlepath) as f:
375 with hg.openpath(ui, bundlepath) as f:
376 if spec:
376 if spec:
377 spec = exchange.getbundlespec(ui, f)
377 spec = exchange.getbundlespec(ui, f)
378 ui.write('%s\n' % spec)
378 ui.write('%s\n' % spec)
379 return
379 return
380
380
381 gen = exchange.readbundle(ui, f, bundlepath)
381 gen = exchange.readbundle(ui, f, bundlepath)
382 if isinstance(gen, bundle2.unbundle20):
382 if isinstance(gen, bundle2.unbundle20):
383 return _debugbundle2(ui, gen, all=all, **opts)
383 return _debugbundle2(ui, gen, all=all, **opts)
384 _debugchangegroup(ui, gen, all=all, **opts)
384 _debugchangegroup(ui, gen, all=all, **opts)
385
385
386 @command('debugcapabilities',
386 @command('debugcapabilities',
387 [], _('PATH'),
387 [], _('PATH'),
388 norepo=True)
388 norepo=True)
389 def debugcapabilities(ui, path, **opts):
389 def debugcapabilities(ui, path, **opts):
390 """lists the capabilities of a remote peer"""
390 """lists the capabilities of a remote peer"""
391 opts = pycompat.byteskwargs(opts)
391 opts = pycompat.byteskwargs(opts)
392 peer = hg.peer(ui, opts, path)
392 peer = hg.peer(ui, opts, path)
393 caps = peer.capabilities()
393 caps = peer.capabilities()
394 ui.write(('Main capabilities:\n'))
394 ui.write(('Main capabilities:\n'))
395 for c in sorted(caps):
395 for c in sorted(caps):
396 ui.write((' %s\n') % c)
396 ui.write((' %s\n') % c)
397 b2caps = bundle2.bundle2caps(peer)
397 b2caps = bundle2.bundle2caps(peer)
398 if b2caps:
398 if b2caps:
399 ui.write(('Bundle2 capabilities:\n'))
399 ui.write(('Bundle2 capabilities:\n'))
400 for key, values in sorted(b2caps.iteritems()):
400 for key, values in sorted(b2caps.iteritems()):
401 ui.write((' %s\n') % key)
401 ui.write((' %s\n') % key)
402 for v in values:
402 for v in values:
403 ui.write((' %s\n') % v)
403 ui.write((' %s\n') % v)
404
404
405 @command('debugcheckstate', [], '')
405 @command('debugcheckstate', [], '')
406 def debugcheckstate(ui, repo):
406 def debugcheckstate(ui, repo):
407 """validate the correctness of the current dirstate"""
407 """validate the correctness of the current dirstate"""
408 parent1, parent2 = repo.dirstate.parents()
408 parent1, parent2 = repo.dirstate.parents()
409 m1 = repo[parent1].manifest()
409 m1 = repo[parent1].manifest()
410 m2 = repo[parent2].manifest()
410 m2 = repo[parent2].manifest()
411 errors = 0
411 errors = 0
412 for f in repo.dirstate:
412 for f in repo.dirstate:
413 state = repo.dirstate[f]
413 state = repo.dirstate[f]
414 if state in "nr" and f not in m1:
414 if state in "nr" and f not in m1:
415 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
415 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
416 errors += 1
416 errors += 1
417 if state in "a" and f in m1:
417 if state in "a" and f in m1:
418 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
418 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
419 errors += 1
419 errors += 1
420 if state in "m" and f not in m1 and f not in m2:
420 if state in "m" and f not in m1 and f not in m2:
421 ui.warn(_("%s in state %s, but not in either manifest\n") %
421 ui.warn(_("%s in state %s, but not in either manifest\n") %
422 (f, state))
422 (f, state))
423 errors += 1
423 errors += 1
424 for f in m1:
424 for f in m1:
425 state = repo.dirstate[f]
425 state = repo.dirstate[f]
426 if state not in "nrm":
426 if state not in "nrm":
427 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
427 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
428 errors += 1
428 errors += 1
429 if errors:
429 if errors:
430 error = _(".hg/dirstate inconsistent with current parent's manifest")
430 error = _(".hg/dirstate inconsistent with current parent's manifest")
431 raise error.Abort(error)
431 raise error.Abort(error)
432
432
433 @command('debugcolor',
433 @command('debugcolor',
434 [('', 'style', None, _('show all configured styles'))],
434 [('', 'style', None, _('show all configured styles'))],
435 'hg debugcolor')
435 'hg debugcolor')
436 def debugcolor(ui, repo, **opts):
436 def debugcolor(ui, repo, **opts):
437 """show available color, effects or style"""
437 """show available color, effects or style"""
438 ui.write(('color mode: %s\n') % ui._colormode)
438 ui.write(('color mode: %s\n') % ui._colormode)
439 if opts.get(r'style'):
439 if opts.get(r'style'):
440 return _debugdisplaystyle(ui)
440 return _debugdisplaystyle(ui)
441 else:
441 else:
442 return _debugdisplaycolor(ui)
442 return _debugdisplaycolor(ui)
443
443
444 def _debugdisplaycolor(ui):
444 def _debugdisplaycolor(ui):
445 ui = ui.copy()
445 ui = ui.copy()
446 ui._styles.clear()
446 ui._styles.clear()
447 for effect in color._activeeffects(ui).keys():
447 for effect in color._activeeffects(ui).keys():
448 ui._styles[effect] = effect
448 ui._styles[effect] = effect
449 if ui._terminfoparams:
449 if ui._terminfoparams:
450 for k, v in ui.configitems('color'):
450 for k, v in ui.configitems('color'):
451 if k.startswith('color.'):
451 if k.startswith('color.'):
452 ui._styles[k] = k[6:]
452 ui._styles[k] = k[6:]
453 elif k.startswith('terminfo.'):
453 elif k.startswith('terminfo.'):
454 ui._styles[k] = k[9:]
454 ui._styles[k] = k[9:]
455 ui.write(_('available colors:\n'))
455 ui.write(_('available colors:\n'))
456 # sort label with a '_' after the other to group '_background' entry.
456 # sort label with a '_' after the other to group '_background' entry.
457 items = sorted(ui._styles.items(),
457 items = sorted(ui._styles.items(),
458 key=lambda i: ('_' in i[0], i[0], i[1]))
458 key=lambda i: ('_' in i[0], i[0], i[1]))
459 for colorname, label in items:
459 for colorname, label in items:
460 ui.write(('%s\n') % colorname, label=label)
460 ui.write(('%s\n') % colorname, label=label)
461
461
462 def _debugdisplaystyle(ui):
462 def _debugdisplaystyle(ui):
463 ui.write(_('available style:\n'))
463 ui.write(_('available style:\n'))
464 if not ui._styles:
464 if not ui._styles:
465 return
465 return
466 width = max(len(s) for s in ui._styles)
466 width = max(len(s) for s in ui._styles)
467 for label, effects in sorted(ui._styles.items()):
467 for label, effects in sorted(ui._styles.items()):
468 ui.write('%s' % label, label=label)
468 ui.write('%s' % label, label=label)
469 if effects:
469 if effects:
470 # 50
470 # 50
471 ui.write(': ')
471 ui.write(': ')
472 ui.write(' ' * (max(0, width - len(label))))
472 ui.write(' ' * (max(0, width - len(label))))
473 ui.write(', '.join(ui.label(e, e) for e in effects.split()))
473 ui.write(', '.join(ui.label(e, e) for e in effects.split()))
474 ui.write('\n')
474 ui.write('\n')
475
475
476 @command('debugcreatestreamclonebundle', [], 'FILE')
476 @command('debugcreatestreamclonebundle', [], 'FILE')
477 def debugcreatestreamclonebundle(ui, repo, fname):
477 def debugcreatestreamclonebundle(ui, repo, fname):
478 """create a stream clone bundle file
478 """create a stream clone bundle file
479
479
480 Stream bundles are special bundles that are essentially archives of
480 Stream bundles are special bundles that are essentially archives of
481 revlog files. They are commonly used for cloning very quickly.
481 revlog files. They are commonly used for cloning very quickly.
482 """
482 """
483 # TODO we may want to turn this into an abort when this functionality
483 # TODO we may want to turn this into an abort when this functionality
484 # is moved into `hg bundle`.
484 # is moved into `hg bundle`.
485 if phases.hassecret(repo):
485 if phases.hassecret(repo):
486 ui.warn(_('(warning: stream clone bundle will contain secret '
486 ui.warn(_('(warning: stream clone bundle will contain secret '
487 'revisions)\n'))
487 'revisions)\n'))
488
488
489 requirements, gen = streamclone.generatebundlev1(repo)
489 requirements, gen = streamclone.generatebundlev1(repo)
490 changegroup.writechunks(ui, gen, fname)
490 changegroup.writechunks(ui, gen, fname)
491
491
492 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
492 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
493
493
494 @command('debugdag',
494 @command('debugdag',
495 [('t', 'tags', None, _('use tags as labels')),
495 [('t', 'tags', None, _('use tags as labels')),
496 ('b', 'branches', None, _('annotate with branch names')),
496 ('b', 'branches', None, _('annotate with branch names')),
497 ('', 'dots', None, _('use dots for runs')),
497 ('', 'dots', None, _('use dots for runs')),
498 ('s', 'spaces', None, _('separate elements by spaces'))],
498 ('s', 'spaces', None, _('separate elements by spaces'))],
499 _('[OPTION]... [FILE [REV]...]'),
499 _('[OPTION]... [FILE [REV]...]'),
500 optionalrepo=True)
500 optionalrepo=True)
501 def debugdag(ui, repo, file_=None, *revs, **opts):
501 def debugdag(ui, repo, file_=None, *revs, **opts):
502 """format the changelog or an index DAG as a concise textual description
502 """format the changelog or an index DAG as a concise textual description
503
503
504 If you pass a revlog index, the revlog's DAG is emitted. If you list
504 If you pass a revlog index, the revlog's DAG is emitted. If you list
505 revision numbers, they get labeled in the output as rN.
505 revision numbers, they get labeled in the output as rN.
506
506
507 Otherwise, the changelog DAG of the current repo is emitted.
507 Otherwise, the changelog DAG of the current repo is emitted.
508 """
508 """
509 spaces = opts.get(r'spaces')
509 spaces = opts.get(r'spaces')
510 dots = opts.get(r'dots')
510 dots = opts.get(r'dots')
511 if file_:
511 if file_:
512 rlog = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False),
512 rlog = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False),
513 file_)
513 file_)
514 revs = set((int(r) for r in revs))
514 revs = set((int(r) for r in revs))
515 def events():
515 def events():
516 for r in rlog:
516 for r in rlog:
517 yield 'n', (r, list(p for p in rlog.parentrevs(r)
517 yield 'n', (r, list(p for p in rlog.parentrevs(r)
518 if p != -1))
518 if p != -1))
519 if r in revs:
519 if r in revs:
520 yield 'l', (r, "r%i" % r)
520 yield 'l', (r, "r%i" % r)
521 elif repo:
521 elif repo:
522 cl = repo.changelog
522 cl = repo.changelog
523 tags = opts.get(r'tags')
523 tags = opts.get(r'tags')
524 branches = opts.get(r'branches')
524 branches = opts.get(r'branches')
525 if tags:
525 if tags:
526 labels = {}
526 labels = {}
527 for l, n in repo.tags().items():
527 for l, n in repo.tags().items():
528 labels.setdefault(cl.rev(n), []).append(l)
528 labels.setdefault(cl.rev(n), []).append(l)
529 def events():
529 def events():
530 b = "default"
530 b = "default"
531 for r in cl:
531 for r in cl:
532 if branches:
532 if branches:
533 newb = cl.read(cl.node(r))[5]['branch']
533 newb = cl.read(cl.node(r))[5]['branch']
534 if newb != b:
534 if newb != b:
535 yield 'a', newb
535 yield 'a', newb
536 b = newb
536 b = newb
537 yield 'n', (r, list(p for p in cl.parentrevs(r)
537 yield 'n', (r, list(p for p in cl.parentrevs(r)
538 if p != -1))
538 if p != -1))
539 if tags:
539 if tags:
540 ls = labels.get(r)
540 ls = labels.get(r)
541 if ls:
541 if ls:
542 for l in ls:
542 for l in ls:
543 yield 'l', (r, l)
543 yield 'l', (r, l)
544 else:
544 else:
545 raise error.Abort(_('need repo for changelog dag'))
545 raise error.Abort(_('need repo for changelog dag'))
546
546
547 for line in dagparser.dagtextlines(events(),
547 for line in dagparser.dagtextlines(events(),
548 addspaces=spaces,
548 addspaces=spaces,
549 wraplabels=True,
549 wraplabels=True,
550 wrapannotations=True,
550 wrapannotations=True,
551 wrapnonlinear=dots,
551 wrapnonlinear=dots,
552 usedots=dots,
552 usedots=dots,
553 maxlinewidth=70):
553 maxlinewidth=70):
554 ui.write(line)
554 ui.write(line)
555 ui.write("\n")
555 ui.write("\n")
556
556
557 @command('debugdata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
557 @command('debugdata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
558 def debugdata(ui, repo, file_, rev=None, **opts):
558 def debugdata(ui, repo, file_, rev=None, **opts):
559 """dump the contents of a data file revision"""
559 """dump the contents of a data file revision"""
560 opts = pycompat.byteskwargs(opts)
560 opts = pycompat.byteskwargs(opts)
561 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
561 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
562 if rev is not None:
562 if rev is not None:
563 raise error.CommandError('debugdata', _('invalid arguments'))
563 raise error.CommandError('debugdata', _('invalid arguments'))
564 file_, rev = None, file_
564 file_, rev = None, file_
565 elif rev is None:
565 elif rev is None:
566 raise error.CommandError('debugdata', _('invalid arguments'))
566 raise error.CommandError('debugdata', _('invalid arguments'))
567 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
567 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
568 try:
568 try:
569 ui.write(r.revision(r.lookup(rev), raw=True))
569 ui.write(r.revision(r.lookup(rev), raw=True))
570 except KeyError:
570 except KeyError:
571 raise error.Abort(_('invalid revision identifier %s') % rev)
571 raise error.Abort(_('invalid revision identifier %s') % rev)
572
572
573 @command('debugdate',
573 @command('debugdate',
574 [('e', 'extended', None, _('try extended date formats'))],
574 [('e', 'extended', None, _('try extended date formats'))],
575 _('[-e] DATE [RANGE]'),
575 _('[-e] DATE [RANGE]'),
576 norepo=True, optionalrepo=True)
576 norepo=True, optionalrepo=True)
577 def debugdate(ui, date, range=None, **opts):
577 def debugdate(ui, date, range=None, **opts):
578 """parse and display a date"""
578 """parse and display a date"""
579 if opts[r"extended"]:
579 if opts[r"extended"]:
580 d = dateutil.parsedate(date, util.extendeddateformats)
580 d = dateutil.parsedate(date, util.extendeddateformats)
581 else:
581 else:
582 d = dateutil.parsedate(date)
582 d = dateutil.parsedate(date)
583 ui.write(("internal: %d %d\n") % d)
583 ui.write(("internal: %d %d\n") % d)
584 ui.write(("standard: %s\n") % dateutil.datestr(d))
584 ui.write(("standard: %s\n") % dateutil.datestr(d))
585 if range:
585 if range:
586 m = dateutil.matchdate(range)
586 m = dateutil.matchdate(range)
587 ui.write(("match: %s\n") % m(d[0]))
587 ui.write(("match: %s\n") % m(d[0]))
588
588
589 @command('debugdeltachain',
589 @command('debugdeltachain',
590 cmdutil.debugrevlogopts + cmdutil.formatteropts,
590 cmdutil.debugrevlogopts + cmdutil.formatteropts,
591 _('-c|-m|FILE'),
591 _('-c|-m|FILE'),
592 optionalrepo=True)
592 optionalrepo=True)
593 def debugdeltachain(ui, repo, file_=None, **opts):
593 def debugdeltachain(ui, repo, file_=None, **opts):
594 """dump information about delta chains in a revlog
594 """dump information about delta chains in a revlog
595
595
596 Output can be templatized. Available template keywords are:
596 Output can be templatized. Available template keywords are:
597
597
598 :``rev``: revision number
598 :``rev``: revision number
599 :``chainid``: delta chain identifier (numbered by unique base)
599 :``chainid``: delta chain identifier (numbered by unique base)
600 :``chainlen``: delta chain length to this revision
600 :``chainlen``: delta chain length to this revision
601 :``prevrev``: previous revision in delta chain
601 :``prevrev``: previous revision in delta chain
602 :``deltatype``: role of delta / how it was computed
602 :``deltatype``: role of delta / how it was computed
603 :``compsize``: compressed size of revision
603 :``compsize``: compressed size of revision
604 :``uncompsize``: uncompressed size of revision
604 :``uncompsize``: uncompressed size of revision
605 :``chainsize``: total size of compressed revisions in chain
605 :``chainsize``: total size of compressed revisions in chain
606 :``chainratio``: total chain size divided by uncompressed revision size
606 :``chainratio``: total chain size divided by uncompressed revision size
607 (new delta chains typically start at ratio 2.00)
607 (new delta chains typically start at ratio 2.00)
608 :``lindist``: linear distance from base revision in delta chain to end
608 :``lindist``: linear distance from base revision in delta chain to end
609 of this revision
609 of this revision
610 :``extradist``: total size of revisions not part of this delta chain from
610 :``extradist``: total size of revisions not part of this delta chain from
611 base of delta chain to end of this revision; a measurement
611 base of delta chain to end of this revision; a measurement
612 of how much extra data we need to read/seek across to read
612 of how much extra data we need to read/seek across to read
613 the delta chain for this revision
613 the delta chain for this revision
614 :``extraratio``: extradist divided by chainsize; another representation of
614 :``extraratio``: extradist divided by chainsize; another representation of
615 how much unrelated data is needed to load this delta chain
615 how much unrelated data is needed to load this delta chain
616
616
617 If the repository is configured to use the sparse read, additional keywords
617 If the repository is configured to use the sparse read, additional keywords
618 are available:
618 are available:
619
619
620 :``readsize``: total size of data read from the disk for a revision
620 :``readsize``: total size of data read from the disk for a revision
621 (sum of the sizes of all the blocks)
621 (sum of the sizes of all the blocks)
622 :``largestblock``: size of the largest block of data read from the disk
622 :``largestblock``: size of the largest block of data read from the disk
623 :``readdensity``: density of useful bytes in the data read from the disk
623 :``readdensity``: density of useful bytes in the data read from the disk
624 :``srchunks``: in how many data hunks the whole revision would be read
624 :``srchunks``: in how many data hunks the whole revision would be read
625
625
626 The sparse read can be enabled with experimental.sparse-read = True
626 The sparse read can be enabled with experimental.sparse-read = True
627 """
627 """
628 opts = pycompat.byteskwargs(opts)
628 opts = pycompat.byteskwargs(opts)
629 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
629 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
630 index = r.index
630 index = r.index
631 start = r.start
631 start = r.start
632 length = r.length
632 length = r.length
633 generaldelta = r.version & revlog.FLAG_GENERALDELTA
633 generaldelta = r.version & revlog.FLAG_GENERALDELTA
634 withsparseread = getattr(r, '_withsparseread', False)
634 withsparseread = getattr(r, '_withsparseread', False)
635
635
636 def revinfo(rev):
636 def revinfo(rev):
637 e = index[rev]
637 e = index[rev]
638 compsize = e[1]
638 compsize = e[1]
639 uncompsize = e[2]
639 uncompsize = e[2]
640 chainsize = 0
640 chainsize = 0
641
641
642 if generaldelta:
642 if generaldelta:
643 if e[3] == e[5]:
643 if e[3] == e[5]:
644 deltatype = 'p1'
644 deltatype = 'p1'
645 elif e[3] == e[6]:
645 elif e[3] == e[6]:
646 deltatype = 'p2'
646 deltatype = 'p2'
647 elif e[3] == rev - 1:
647 elif e[3] == rev - 1:
648 deltatype = 'prev'
648 deltatype = 'prev'
649 elif e[3] == rev:
649 elif e[3] == rev:
650 deltatype = 'base'
650 deltatype = 'base'
651 else:
651 else:
652 deltatype = 'other'
652 deltatype = 'other'
653 else:
653 else:
654 if e[3] == rev:
654 if e[3] == rev:
655 deltatype = 'base'
655 deltatype = 'base'
656 else:
656 else:
657 deltatype = 'prev'
657 deltatype = 'prev'
658
658
659 chain = r._deltachain(rev)[0]
659 chain = r._deltachain(rev)[0]
660 for iterrev in chain:
660 for iterrev in chain:
661 e = index[iterrev]
661 e = index[iterrev]
662 chainsize += e[1]
662 chainsize += e[1]
663
663
664 return compsize, uncompsize, deltatype, chain, chainsize
664 return compsize, uncompsize, deltatype, chain, chainsize
665
665
666 fm = ui.formatter('debugdeltachain', opts)
666 fm = ui.formatter('debugdeltachain', opts)
667
667
668 fm.plain(' rev chain# chainlen prev delta '
668 fm.plain(' rev chain# chainlen prev delta '
669 'size rawsize chainsize ratio lindist extradist '
669 'size rawsize chainsize ratio lindist extradist '
670 'extraratio')
670 'extraratio')
671 if withsparseread:
671 if withsparseread:
672 fm.plain(' readsize largestblk rddensity srchunks')
672 fm.plain(' readsize largestblk rddensity srchunks')
673 fm.plain('\n')
673 fm.plain('\n')
674
674
675 chainbases = {}
675 chainbases = {}
676 for rev in r:
676 for rev in r:
677 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
677 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
678 chainbase = chain[0]
678 chainbase = chain[0]
679 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
679 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
680 basestart = start(chainbase)
680 basestart = start(chainbase)
681 revstart = start(rev)
681 revstart = start(rev)
682 lineardist = revstart + comp - basestart
682 lineardist = revstart + comp - basestart
683 extradist = lineardist - chainsize
683 extradist = lineardist - chainsize
684 try:
684 try:
685 prevrev = chain[-2]
685 prevrev = chain[-2]
686 except IndexError:
686 except IndexError:
687 prevrev = -1
687 prevrev = -1
688
688
689 chainratio = float(chainsize) / float(uncomp)
689 chainratio = float(chainsize) / float(uncomp)
690 extraratio = float(extradist) / float(chainsize)
690 extraratio = float(extradist) / float(chainsize)
691
691
692 fm.startitem()
692 fm.startitem()
693 fm.write('rev chainid chainlen prevrev deltatype compsize '
693 fm.write('rev chainid chainlen prevrev deltatype compsize '
694 'uncompsize chainsize chainratio lindist extradist '
694 'uncompsize chainsize chainratio lindist extradist '
695 'extraratio',
695 'extraratio',
696 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
696 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
697 rev, chainid, len(chain), prevrev, deltatype, comp,
697 rev, chainid, len(chain), prevrev, deltatype, comp,
698 uncomp, chainsize, chainratio, lineardist, extradist,
698 uncomp, chainsize, chainratio, lineardist, extradist,
699 extraratio,
699 extraratio,
700 rev=rev, chainid=chainid, chainlen=len(chain),
700 rev=rev, chainid=chainid, chainlen=len(chain),
701 prevrev=prevrev, deltatype=deltatype, compsize=comp,
701 prevrev=prevrev, deltatype=deltatype, compsize=comp,
702 uncompsize=uncomp, chainsize=chainsize,
702 uncompsize=uncomp, chainsize=chainsize,
703 chainratio=chainratio, lindist=lineardist,
703 chainratio=chainratio, lindist=lineardist,
704 extradist=extradist, extraratio=extraratio)
704 extradist=extradist, extraratio=extraratio)
705 if withsparseread:
705 if withsparseread:
706 readsize = 0
706 readsize = 0
707 largestblock = 0
707 largestblock = 0
708 srchunks = 0
708 srchunks = 0
709
709
710 for revschunk in revlog._slicechunk(r, chain):
710 for revschunk in revlog._slicechunk(r, chain):
711 srchunks += 1
711 srchunks += 1
712 blkend = start(revschunk[-1]) + length(revschunk[-1])
712 blkend = start(revschunk[-1]) + length(revschunk[-1])
713 blksize = blkend - start(revschunk[0])
713 blksize = blkend - start(revschunk[0])
714
714
715 readsize += blksize
715 readsize += blksize
716 if largestblock < blksize:
716 if largestblock < blksize:
717 largestblock = blksize
717 largestblock = blksize
718
718
719 readdensity = float(chainsize) / float(readsize)
719 readdensity = float(chainsize) / float(readsize)
720
720
721 fm.write('readsize largestblock readdensity srchunks',
721 fm.write('readsize largestblock readdensity srchunks',
722 ' %10d %10d %9.5f %8d',
722 ' %10d %10d %9.5f %8d',
723 readsize, largestblock, readdensity, srchunks,
723 readsize, largestblock, readdensity, srchunks,
724 readsize=readsize, largestblock=largestblock,
724 readsize=readsize, largestblock=largestblock,
725 readdensity=readdensity, srchunks=srchunks)
725 readdensity=readdensity, srchunks=srchunks)
726
726
727 fm.plain('\n')
727 fm.plain('\n')
728
728
729 fm.end()
729 fm.end()
730
730
731 @command('debugdirstate|debugstate',
731 @command('debugdirstate|debugstate',
732 [('', 'nodates', None, _('do not display the saved mtime')),
732 [('', 'nodates', None, _('do not display the saved mtime')),
733 ('', 'datesort', None, _('sort by saved mtime'))],
733 ('', 'datesort', None, _('sort by saved mtime'))],
734 _('[OPTION]...'))
734 _('[OPTION]...'))
735 def debugstate(ui, repo, **opts):
735 def debugstate(ui, repo, **opts):
736 """show the contents of the current dirstate"""
736 """show the contents of the current dirstate"""
737
737
738 nodates = opts.get(r'nodates')
738 nodates = opts.get(r'nodates')
739 datesort = opts.get(r'datesort')
739 datesort = opts.get(r'datesort')
740
740
741 timestr = ""
741 timestr = ""
742 if datesort:
742 if datesort:
743 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
743 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
744 else:
744 else:
745 keyfunc = None # sort by filename
745 keyfunc = None # sort by filename
746 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
746 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
747 if ent[3] == -1:
747 if ent[3] == -1:
748 timestr = 'unset '
748 timestr = 'unset '
749 elif nodates:
749 elif nodates:
750 timestr = 'set '
750 timestr = 'set '
751 else:
751 else:
752 timestr = time.strftime(r"%Y-%m-%d %H:%M:%S ",
752 timestr = time.strftime(r"%Y-%m-%d %H:%M:%S ",
753 time.localtime(ent[3]))
753 time.localtime(ent[3]))
754 timestr = encoding.strtolocal(timestr)
754 timestr = encoding.strtolocal(timestr)
755 if ent[1] & 0o20000:
755 if ent[1] & 0o20000:
756 mode = 'lnk'
756 mode = 'lnk'
757 else:
757 else:
758 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
758 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
759 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
759 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
760 for f in repo.dirstate.copies():
760 for f in repo.dirstate.copies():
761 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
761 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
762
762
763 @command('debugdiscovery',
763 @command('debugdiscovery',
764 [('', 'old', None, _('use old-style discovery')),
764 [('', 'old', None, _('use old-style discovery')),
765 ('', 'nonheads', None,
765 ('', 'nonheads', None,
766 _('use old-style discovery with non-heads included')),
766 _('use old-style discovery with non-heads included')),
767 ('', 'rev', [], 'restrict discovery to this set of revs'),
767 ('', 'rev', [], 'restrict discovery to this set of revs'),
768 ] + cmdutil.remoteopts,
768 ] + cmdutil.remoteopts,
769 _('[--rev REV] [OTHER]'))
769 _('[--rev REV] [OTHER]'))
770 def debugdiscovery(ui, repo, remoteurl="default", **opts):
770 def debugdiscovery(ui, repo, remoteurl="default", **opts):
771 """runs the changeset discovery protocol in isolation"""
771 """runs the changeset discovery protocol in isolation"""
772 opts = pycompat.byteskwargs(opts)
772 opts = pycompat.byteskwargs(opts)
773 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl))
773 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl))
774 remote = hg.peer(repo, opts, remoteurl)
774 remote = hg.peer(repo, opts, remoteurl)
775 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
775 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
776
776
777 # make sure tests are repeatable
777 # make sure tests are repeatable
778 random.seed(12323)
778 random.seed(12323)
779
779
780 def doit(pushedrevs, remoteheads, remote=remote):
780 def doit(pushedrevs, remoteheads, remote=remote):
781 if opts.get('old'):
781 if opts.get('old'):
782 if not util.safehasattr(remote, 'branches'):
782 if not util.safehasattr(remote, 'branches'):
783 # enable in-client legacy support
783 # enable in-client legacy support
784 remote = localrepo.locallegacypeer(remote.local())
784 remote = localrepo.locallegacypeer(remote.local())
785 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
785 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
786 force=True)
786 force=True)
787 common = set(common)
787 common = set(common)
788 if not opts.get('nonheads'):
788 if not opts.get('nonheads'):
789 ui.write(("unpruned common: %s\n") %
789 ui.write(("unpruned common: %s\n") %
790 " ".join(sorted(short(n) for n in common)))
790 " ".join(sorted(short(n) for n in common)))
791 dag = dagutil.revlogdag(repo.changelog)
791 dag = dagutil.revlogdag(repo.changelog)
792 all = dag.ancestorset(dag.internalizeall(common))
792 all = dag.ancestorset(dag.internalizeall(common))
793 common = dag.externalizeall(dag.headsetofconnecteds(all))
793 common = dag.externalizeall(dag.headsetofconnecteds(all))
794 else:
794 else:
795 nodes = None
795 nodes = None
796 if pushedrevs:
796 if pushedrevs:
797 revs = scmutil.revrange(repo, pushedrevs)
797 revs = scmutil.revrange(repo, pushedrevs)
798 nodes = [repo[r].node() for r in revs]
798 nodes = [repo[r].node() for r in revs]
799 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote,
799 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote,
800 ancestorsof=nodes)
800 ancestorsof=nodes)
801 common = set(common)
801 common = set(common)
802 rheads = set(hds)
802 rheads = set(hds)
803 lheads = set(repo.heads())
803 lheads = set(repo.heads())
804 ui.write(("common heads: %s\n") %
804 ui.write(("common heads: %s\n") %
805 " ".join(sorted(short(n) for n in common)))
805 " ".join(sorted(short(n) for n in common)))
806 if lheads <= common:
806 if lheads <= common:
807 ui.write(("local is subset\n"))
807 ui.write(("local is subset\n"))
808 elif rheads <= common:
808 elif rheads <= common:
809 ui.write(("remote is subset\n"))
809 ui.write(("remote is subset\n"))
810
810
811 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
811 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
812 localrevs = opts['rev']
812 localrevs = opts['rev']
813 doit(localrevs, remoterevs)
813 doit(localrevs, remoterevs)
814
814
815 _chunksize = 4 << 10
815 _chunksize = 4 << 10
816
816
817 @command('debugdownload',
817 @command('debugdownload',
818 [
818 [
819 ('o', 'output', '', _('path')),
819 ('o', 'output', '', _('path')),
820 ],
820 ],
821 optionalrepo=True)
821 optionalrepo=True)
822 def debugdownload(ui, repo, url, output=None, **opts):
822 def debugdownload(ui, repo, url, output=None, **opts):
823 """download a resource using Mercurial logic and config
823 """download a resource using Mercurial logic and config
824 """
824 """
825 fh = urlmod.open(ui, url, output)
825 fh = urlmod.open(ui, url, output)
826
826
827 dest = ui
827 dest = ui
828 if output:
828 if output:
829 dest = open(output, "wb", _chunksize)
829 dest = open(output, "wb", _chunksize)
830 try:
830 try:
831 data = fh.read(_chunksize)
831 data = fh.read(_chunksize)
832 while data:
832 while data:
833 dest.write(data)
833 dest.write(data)
834 data = fh.read(_chunksize)
834 data = fh.read(_chunksize)
835 finally:
835 finally:
836 if output:
836 if output:
837 dest.close()
837 dest.close()
838
838
839 @command('debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
839 @command('debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
840 def debugextensions(ui, repo, **opts):
840 def debugextensions(ui, repo, **opts):
841 '''show information about active extensions'''
841 '''show information about active extensions'''
842 opts = pycompat.byteskwargs(opts)
842 opts = pycompat.byteskwargs(opts)
843 exts = extensions.extensions(ui)
843 exts = extensions.extensions(ui)
844 hgver = util.version()
844 hgver = util.version()
845 fm = ui.formatter('debugextensions', opts)
845 fm = ui.formatter('debugextensions', opts)
846 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
846 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
847 isinternal = extensions.ismoduleinternal(extmod)
847 isinternal = extensions.ismoduleinternal(extmod)
848 extsource = pycompat.fsencode(extmod.__file__)
848 extsource = pycompat.fsencode(extmod.__file__)
849 if isinternal:
849 if isinternal:
850 exttestedwith = [] # never expose magic string to users
850 exttestedwith = [] # never expose magic string to users
851 else:
851 else:
852 exttestedwith = getattr(extmod, 'testedwith', '').split()
852 exttestedwith = getattr(extmod, 'testedwith', '').split()
853 extbuglink = getattr(extmod, 'buglink', None)
853 extbuglink = getattr(extmod, 'buglink', None)
854
854
855 fm.startitem()
855 fm.startitem()
856
856
857 if ui.quiet or ui.verbose:
857 if ui.quiet or ui.verbose:
858 fm.write('name', '%s\n', extname)
858 fm.write('name', '%s\n', extname)
859 else:
859 else:
860 fm.write('name', '%s', extname)
860 fm.write('name', '%s', extname)
861 if isinternal or hgver in exttestedwith:
861 if isinternal or hgver in exttestedwith:
862 fm.plain('\n')
862 fm.plain('\n')
863 elif not exttestedwith:
863 elif not exttestedwith:
864 fm.plain(_(' (untested!)\n'))
864 fm.plain(_(' (untested!)\n'))
865 else:
865 else:
866 lasttestedversion = exttestedwith[-1]
866 lasttestedversion = exttestedwith[-1]
867 fm.plain(' (%s!)\n' % lasttestedversion)
867 fm.plain(' (%s!)\n' % lasttestedversion)
868
868
869 fm.condwrite(ui.verbose and extsource, 'source',
869 fm.condwrite(ui.verbose and extsource, 'source',
870 _(' location: %s\n'), extsource or "")
870 _(' location: %s\n'), extsource or "")
871
871
872 if ui.verbose:
872 if ui.verbose:
873 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
873 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
874 fm.data(bundled=isinternal)
874 fm.data(bundled=isinternal)
875
875
876 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
876 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
877 _(' tested with: %s\n'),
877 _(' tested with: %s\n'),
878 fm.formatlist(exttestedwith, name='ver'))
878 fm.formatlist(exttestedwith, name='ver'))
879
879
880 fm.condwrite(ui.verbose and extbuglink, 'buglink',
880 fm.condwrite(ui.verbose and extbuglink, 'buglink',
881 _(' bug reporting: %s\n'), extbuglink or "")
881 _(' bug reporting: %s\n'), extbuglink or "")
882
882
883 fm.end()
883 fm.end()
884
884
885 @command('debugfileset',
885 @command('debugfileset',
886 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
886 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
887 _('[-r REV] FILESPEC'))
887 _('[-r REV] FILESPEC'))
888 def debugfileset(ui, repo, expr, **opts):
888 def debugfileset(ui, repo, expr, **opts):
889 '''parse and apply a fileset specification'''
889 '''parse and apply a fileset specification'''
890 ctx = scmutil.revsingle(repo, opts.get(r'rev'), None)
890 ctx = scmutil.revsingle(repo, opts.get(r'rev'), None)
891 if ui.verbose:
891 if ui.verbose:
892 tree = fileset.parse(expr)
892 tree = fileset.parse(expr)
893 ui.note(fileset.prettyformat(tree), "\n")
893 ui.note(fileset.prettyformat(tree), "\n")
894
894
895 for f in ctx.getfileset(expr):
895 for f in ctx.getfileset(expr):
896 ui.write("%s\n" % f)
896 ui.write("%s\n" % f)
897
897
898 @command('debugformat',
898 @command('debugformat',
899 [] + cmdutil.formatteropts,
899 [] + cmdutil.formatteropts,
900 _(''))
900 _(''))
901 def debugformat(ui, repo, **opts):
901 def debugformat(ui, repo, **opts):
902 """display format information about the current repository
902 """display format information about the current repository
903
903
904 Use --verbose to get extra information about current config value and
904 Use --verbose to get extra information about current config value and
905 Mercurial default."""
905 Mercurial default."""
906 opts = pycompat.byteskwargs(opts)
906 opts = pycompat.byteskwargs(opts)
907 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
907 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
908 maxvariantlength = max(len('format-variant'), maxvariantlength)
908 maxvariantlength = max(len('format-variant'), maxvariantlength)
909
909
910 def makeformatname(name):
910 def makeformatname(name):
911 return '%s:' + (' ' * (maxvariantlength - len(name)))
911 return '%s:' + (' ' * (maxvariantlength - len(name)))
912
912
913 fm = ui.formatter('debugformat', opts)
913 fm = ui.formatter('debugformat', opts)
914 if fm.isplain():
914 if fm.isplain():
915 def formatvalue(value):
915 def formatvalue(value):
916 if util.safehasattr(value, 'startswith'):
916 if util.safehasattr(value, 'startswith'):
917 return value
917 return value
918 if value:
918 if value:
919 return 'yes'
919 return 'yes'
920 else:
920 else:
921 return 'no'
921 return 'no'
922 else:
922 else:
923 formatvalue = pycompat.identity
923 formatvalue = pycompat.identity
924
924
925 fm.plain('format-variant')
925 fm.plain('format-variant')
926 fm.plain(' ' * (maxvariantlength - len('format-variant')))
926 fm.plain(' ' * (maxvariantlength - len('format-variant')))
927 fm.plain(' repo')
927 fm.plain(' repo')
928 if ui.verbose:
928 if ui.verbose:
929 fm.plain(' config default')
929 fm.plain(' config default')
930 fm.plain('\n')
930 fm.plain('\n')
931 for fv in upgrade.allformatvariant:
931 for fv in upgrade.allformatvariant:
932 fm.startitem()
932 fm.startitem()
933 repovalue = fv.fromrepo(repo)
933 repovalue = fv.fromrepo(repo)
934 configvalue = fv.fromconfig(repo)
934 configvalue = fv.fromconfig(repo)
935
935
936 if repovalue != configvalue:
936 if repovalue != configvalue:
937 namelabel = 'formatvariant.name.mismatchconfig'
937 namelabel = 'formatvariant.name.mismatchconfig'
938 repolabel = 'formatvariant.repo.mismatchconfig'
938 repolabel = 'formatvariant.repo.mismatchconfig'
939 elif repovalue != fv.default:
939 elif repovalue != fv.default:
940 namelabel = 'formatvariant.name.mismatchdefault'
940 namelabel = 'formatvariant.name.mismatchdefault'
941 repolabel = 'formatvariant.repo.mismatchdefault'
941 repolabel = 'formatvariant.repo.mismatchdefault'
942 else:
942 else:
943 namelabel = 'formatvariant.name.uptodate'
943 namelabel = 'formatvariant.name.uptodate'
944 repolabel = 'formatvariant.repo.uptodate'
944 repolabel = 'formatvariant.repo.uptodate'
945
945
946 fm.write('name', makeformatname(fv.name), fv.name,
946 fm.write('name', makeformatname(fv.name), fv.name,
947 label=namelabel)
947 label=namelabel)
948 fm.write('repo', ' %3s', formatvalue(repovalue),
948 fm.write('repo', ' %3s', formatvalue(repovalue),
949 label=repolabel)
949 label=repolabel)
950 if fv.default != configvalue:
950 if fv.default != configvalue:
951 configlabel = 'formatvariant.config.special'
951 configlabel = 'formatvariant.config.special'
952 else:
952 else:
953 configlabel = 'formatvariant.config.default'
953 configlabel = 'formatvariant.config.default'
954 fm.condwrite(ui.verbose, 'config', ' %6s', formatvalue(configvalue),
954 fm.condwrite(ui.verbose, 'config', ' %6s', formatvalue(configvalue),
955 label=configlabel)
955 label=configlabel)
956 fm.condwrite(ui.verbose, 'default', ' %7s', formatvalue(fv.default),
956 fm.condwrite(ui.verbose, 'default', ' %7s', formatvalue(fv.default),
957 label='formatvariant.default')
957 label='formatvariant.default')
958 fm.plain('\n')
958 fm.plain('\n')
959 fm.end()
959 fm.end()
960
960
961 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
961 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
962 def debugfsinfo(ui, path="."):
962 def debugfsinfo(ui, path="."):
963 """show information detected about current filesystem"""
963 """show information detected about current filesystem"""
964 ui.write(('path: %s\n') % path)
964 ui.write(('path: %s\n') % path)
965 ui.write(('mounted on: %s\n') % (util.getfsmountpoint(path) or '(unknown)'))
965 ui.write(('mounted on: %s\n') % (util.getfsmountpoint(path) or '(unknown)'))
966 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
966 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
967 ui.write(('fstype: %s\n') % (util.getfstype(path) or '(unknown)'))
967 ui.write(('fstype: %s\n') % (util.getfstype(path) or '(unknown)'))
968 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
968 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
969 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
969 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
970 casesensitive = '(unknown)'
970 casesensitive = '(unknown)'
971 try:
971 try:
972 with pycompat.namedtempfile(prefix='.debugfsinfo', dir=path) as f:
972 with pycompat.namedtempfile(prefix='.debugfsinfo', dir=path) as f:
973 casesensitive = util.fscasesensitive(f.name) and 'yes' or 'no'
973 casesensitive = util.fscasesensitive(f.name) and 'yes' or 'no'
974 except OSError:
974 except OSError:
975 pass
975 pass
976 ui.write(('case-sensitive: %s\n') % casesensitive)
976 ui.write(('case-sensitive: %s\n') % casesensitive)
977
977
978 @command('debuggetbundle',
978 @command('debuggetbundle',
979 [('H', 'head', [], _('id of head node'), _('ID')),
979 [('H', 'head', [], _('id of head node'), _('ID')),
980 ('C', 'common', [], _('id of common node'), _('ID')),
980 ('C', 'common', [], _('id of common node'), _('ID')),
981 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
981 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
982 _('REPO FILE [-H|-C ID]...'),
982 _('REPO FILE [-H|-C ID]...'),
983 norepo=True)
983 norepo=True)
984 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
984 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
985 """retrieves a bundle from a repo
985 """retrieves a bundle from a repo
986
986
987 Every ID must be a full-length hex node id string. Saves the bundle to the
987 Every ID must be a full-length hex node id string. Saves the bundle to the
988 given file.
988 given file.
989 """
989 """
990 opts = pycompat.byteskwargs(opts)
990 opts = pycompat.byteskwargs(opts)
991 repo = hg.peer(ui, opts, repopath)
991 repo = hg.peer(ui, opts, repopath)
992 if not repo.capable('getbundle'):
992 if not repo.capable('getbundle'):
993 raise error.Abort("getbundle() not supported by target repository")
993 raise error.Abort("getbundle() not supported by target repository")
994 args = {}
994 args = {}
995 if common:
995 if common:
996 args[r'common'] = [bin(s) for s in common]
996 args[r'common'] = [bin(s) for s in common]
997 if head:
997 if head:
998 args[r'heads'] = [bin(s) for s in head]
998 args[r'heads'] = [bin(s) for s in head]
999 # TODO: get desired bundlecaps from command line.
999 # TODO: get desired bundlecaps from command line.
1000 args[r'bundlecaps'] = None
1000 args[r'bundlecaps'] = None
1001 bundle = repo.getbundle('debug', **args)
1001 bundle = repo.getbundle('debug', **args)
1002
1002
1003 bundletype = opts.get('type', 'bzip2').lower()
1003 bundletype = opts.get('type', 'bzip2').lower()
1004 btypes = {'none': 'HG10UN',
1004 btypes = {'none': 'HG10UN',
1005 'bzip2': 'HG10BZ',
1005 'bzip2': 'HG10BZ',
1006 'gzip': 'HG10GZ',
1006 'gzip': 'HG10GZ',
1007 'bundle2': 'HG20'}
1007 'bundle2': 'HG20'}
1008 bundletype = btypes.get(bundletype)
1008 bundletype = btypes.get(bundletype)
1009 if bundletype not in bundle2.bundletypes:
1009 if bundletype not in bundle2.bundletypes:
1010 raise error.Abort(_('unknown bundle type specified with --type'))
1010 raise error.Abort(_('unknown bundle type specified with --type'))
1011 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1011 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1012
1012
1013 @command('debugignore', [], '[FILE]')
1013 @command('debugignore', [], '[FILE]')
1014 def debugignore(ui, repo, *files, **opts):
1014 def debugignore(ui, repo, *files, **opts):
1015 """display the combined ignore pattern and information about ignored files
1015 """display the combined ignore pattern and information about ignored files
1016
1016
1017 With no argument display the combined ignore pattern.
1017 With no argument display the combined ignore pattern.
1018
1018
1019 Given space separated file names, shows if the given file is ignored and
1019 Given space separated file names, shows if the given file is ignored and
1020 if so, show the ignore rule (file and line number) that matched it.
1020 if so, show the ignore rule (file and line number) that matched it.
1021 """
1021 """
1022 ignore = repo.dirstate._ignore
1022 ignore = repo.dirstate._ignore
1023 if not files:
1023 if not files:
1024 # Show all the patterns
1024 # Show all the patterns
1025 ui.write("%s\n" % pycompat.byterepr(ignore))
1025 ui.write("%s\n" % pycompat.byterepr(ignore))
1026 else:
1026 else:
1027 m = scmutil.match(repo[None], pats=files)
1027 m = scmutil.match(repo[None], pats=files)
1028 for f in m.files():
1028 for f in m.files():
1029 nf = util.normpath(f)
1029 nf = util.normpath(f)
1030 ignored = None
1030 ignored = None
1031 ignoredata = None
1031 ignoredata = None
1032 if nf != '.':
1032 if nf != '.':
1033 if ignore(nf):
1033 if ignore(nf):
1034 ignored = nf
1034 ignored = nf
1035 ignoredata = repo.dirstate._ignorefileandline(nf)
1035 ignoredata = repo.dirstate._ignorefileandline(nf)
1036 else:
1036 else:
1037 for p in util.finddirs(nf):
1037 for p in util.finddirs(nf):
1038 if ignore(p):
1038 if ignore(p):
1039 ignored = p
1039 ignored = p
1040 ignoredata = repo.dirstate._ignorefileandline(p)
1040 ignoredata = repo.dirstate._ignorefileandline(p)
1041 break
1041 break
1042 if ignored:
1042 if ignored:
1043 if ignored == nf:
1043 if ignored == nf:
1044 ui.write(_("%s is ignored\n") % m.uipath(f))
1044 ui.write(_("%s is ignored\n") % m.uipath(f))
1045 else:
1045 else:
1046 ui.write(_("%s is ignored because of "
1046 ui.write(_("%s is ignored because of "
1047 "containing folder %s\n")
1047 "containing folder %s\n")
1048 % (m.uipath(f), ignored))
1048 % (m.uipath(f), ignored))
1049 ignorefile, lineno, line = ignoredata
1049 ignorefile, lineno, line = ignoredata
1050 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
1050 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
1051 % (ignorefile, lineno, line))
1051 % (ignorefile, lineno, line))
1052 else:
1052 else:
1053 ui.write(_("%s is not ignored\n") % m.uipath(f))
1053 ui.write(_("%s is not ignored\n") % m.uipath(f))
1054
1054
1055 @command('debugindex', cmdutil.debugrevlogopts +
1055 @command('debugindex', cmdutil.debugrevlogopts +
1056 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1056 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1057 _('[-f FORMAT] -c|-m|FILE'),
1057 _('[-f FORMAT] -c|-m|FILE'),
1058 optionalrepo=True)
1058 optionalrepo=True)
1059 def debugindex(ui, repo, file_=None, **opts):
1059 def debugindex(ui, repo, file_=None, **opts):
1060 """dump the contents of an index file"""
1060 """dump the contents of an index file"""
1061 opts = pycompat.byteskwargs(opts)
1061 opts = pycompat.byteskwargs(opts)
1062 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1062 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1063 format = opts.get('format', 0)
1063 format = opts.get('format', 0)
1064 if format not in (0, 1):
1064 if format not in (0, 1):
1065 raise error.Abort(_("unknown format %d") % format)
1065 raise error.Abort(_("unknown format %d") % format)
1066
1066
1067 if ui.debugflag:
1067 if ui.debugflag:
1068 shortfn = hex
1068 shortfn = hex
1069 else:
1069 else:
1070 shortfn = short
1070 shortfn = short
1071
1071
1072 # There might not be anything in r, so have a sane default
1072 # There might not be anything in r, so have a sane default
1073 idlen = 12
1073 idlen = 12
1074 for i in r:
1074 for i in r:
1075 idlen = len(shortfn(r.node(i)))
1075 idlen = len(shortfn(r.node(i)))
1076 break
1076 break
1077
1077
1078 if format == 0:
1078 if format == 0:
1079 if ui.verbose:
1079 if ui.verbose:
1080 ui.write((" rev offset length linkrev"
1080 ui.write((" rev offset length linkrev"
1081 " %s %s p2\n") % ("nodeid".ljust(idlen),
1081 " %s %s p2\n") % ("nodeid".ljust(idlen),
1082 "p1".ljust(idlen)))
1082 "p1".ljust(idlen)))
1083 else:
1083 else:
1084 ui.write((" rev linkrev %s %s p2\n") % (
1084 ui.write((" rev linkrev %s %s p2\n") % (
1085 "nodeid".ljust(idlen), "p1".ljust(idlen)))
1085 "nodeid".ljust(idlen), "p1".ljust(idlen)))
1086 elif format == 1:
1086 elif format == 1:
1087 if ui.verbose:
1087 if ui.verbose:
1088 ui.write((" rev flag offset length size link p1"
1088 ui.write((" rev flag offset length size link p1"
1089 " p2 %s\n") % "nodeid".rjust(idlen))
1089 " p2 %s\n") % "nodeid".rjust(idlen))
1090 else:
1090 else:
1091 ui.write((" rev flag size link p1 p2 %s\n") %
1091 ui.write((" rev flag size link p1 p2 %s\n") %
1092 "nodeid".rjust(idlen))
1092 "nodeid".rjust(idlen))
1093
1093
1094 for i in r:
1094 for i in r:
1095 node = r.node(i)
1095 node = r.node(i)
1096 if format == 0:
1096 if format == 0:
1097 try:
1097 try:
1098 pp = r.parents(node)
1098 pp = r.parents(node)
1099 except Exception:
1099 except Exception:
1100 pp = [nullid, nullid]
1100 pp = [nullid, nullid]
1101 if ui.verbose:
1101 if ui.verbose:
1102 ui.write("% 6d % 9d % 7d % 7d %s %s %s\n" % (
1102 ui.write("% 6d % 9d % 7d % 7d %s %s %s\n" % (
1103 i, r.start(i), r.length(i), r.linkrev(i),
1103 i, r.start(i), r.length(i), r.linkrev(i),
1104 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
1104 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
1105 else:
1105 else:
1106 ui.write("% 6d % 7d %s %s %s\n" % (
1106 ui.write("% 6d % 7d %s %s %s\n" % (
1107 i, r.linkrev(i), shortfn(node), shortfn(pp[0]),
1107 i, r.linkrev(i), shortfn(node), shortfn(pp[0]),
1108 shortfn(pp[1])))
1108 shortfn(pp[1])))
1109 elif format == 1:
1109 elif format == 1:
1110 pr = r.parentrevs(i)
1110 pr = r.parentrevs(i)
1111 if ui.verbose:
1111 if ui.verbose:
1112 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n" % (
1112 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n" % (
1113 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1113 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1114 r.linkrev(i), pr[0], pr[1], shortfn(node)))
1114 r.linkrev(i), pr[0], pr[1], shortfn(node)))
1115 else:
1115 else:
1116 ui.write("% 6d %04x % 8d % 6d % 6d % 6d %s\n" % (
1116 ui.write("% 6d %04x % 8d % 6d % 6d % 6d %s\n" % (
1117 i, r.flags(i), r.rawsize(i), r.linkrev(i), pr[0], pr[1],
1117 i, r.flags(i), r.rawsize(i), r.linkrev(i), pr[0], pr[1],
1118 shortfn(node)))
1118 shortfn(node)))
1119
1119
1120 @command('debugindexdot', cmdutil.debugrevlogopts,
1120 @command('debugindexdot', cmdutil.debugrevlogopts,
1121 _('-c|-m|FILE'), optionalrepo=True)
1121 _('-c|-m|FILE'), optionalrepo=True)
1122 def debugindexdot(ui, repo, file_=None, **opts):
1122 def debugindexdot(ui, repo, file_=None, **opts):
1123 """dump an index DAG as a graphviz dot file"""
1123 """dump an index DAG as a graphviz dot file"""
1124 opts = pycompat.byteskwargs(opts)
1124 opts = pycompat.byteskwargs(opts)
1125 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
1125 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
1126 ui.write(("digraph G {\n"))
1126 ui.write(("digraph G {\n"))
1127 for i in r:
1127 for i in r:
1128 node = r.node(i)
1128 node = r.node(i)
1129 pp = r.parents(node)
1129 pp = r.parents(node)
1130 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1130 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1131 if pp[1] != nullid:
1131 if pp[1] != nullid:
1132 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1132 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1133 ui.write("}\n")
1133 ui.write("}\n")
1134
1134
1135 @command('debuginstall', [] + cmdutil.formatteropts, '', norepo=True)
1135 @command('debuginstall', [] + cmdutil.formatteropts, '', norepo=True)
1136 def debuginstall(ui, **opts):
1136 def debuginstall(ui, **opts):
1137 '''test Mercurial installation
1137 '''test Mercurial installation
1138
1138
1139 Returns 0 on success.
1139 Returns 0 on success.
1140 '''
1140 '''
1141 opts = pycompat.byteskwargs(opts)
1141 opts = pycompat.byteskwargs(opts)
1142
1142
1143 def writetemp(contents):
1143 def writetemp(contents):
1144 (fd, name) = pycompat.mkstemp(prefix="hg-debuginstall-")
1144 (fd, name) = pycompat.mkstemp(prefix="hg-debuginstall-")
1145 f = os.fdopen(fd, r"wb")
1145 f = os.fdopen(fd, r"wb")
1146 f.write(contents)
1146 f.write(contents)
1147 f.close()
1147 f.close()
1148 return name
1148 return name
1149
1149
1150 problems = 0
1150 problems = 0
1151
1151
1152 fm = ui.formatter('debuginstall', opts)
1152 fm = ui.formatter('debuginstall', opts)
1153 fm.startitem()
1153 fm.startitem()
1154
1154
1155 # encoding
1155 # encoding
1156 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
1156 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
1157 err = None
1157 err = None
1158 try:
1158 try:
1159 codecs.lookup(pycompat.sysstr(encoding.encoding))
1159 codecs.lookup(pycompat.sysstr(encoding.encoding))
1160 except LookupError as inst:
1160 except LookupError as inst:
1161 err = stringutil.forcebytestr(inst)
1161 err = stringutil.forcebytestr(inst)
1162 problems += 1
1162 problems += 1
1163 fm.condwrite(err, 'encodingerror', _(" %s\n"
1163 fm.condwrite(err, 'encodingerror', _(" %s\n"
1164 " (check that your locale is properly set)\n"), err)
1164 " (check that your locale is properly set)\n"), err)
1165
1165
1166 # Python
1166 # Python
1167 fm.write('pythonexe', _("checking Python executable (%s)\n"),
1167 fm.write('pythonexe', _("checking Python executable (%s)\n"),
1168 pycompat.sysexecutable)
1168 pycompat.sysexecutable)
1169 fm.write('pythonver', _("checking Python version (%s)\n"),
1169 fm.write('pythonver', _("checking Python version (%s)\n"),
1170 ("%d.%d.%d" % sys.version_info[:3]))
1170 ("%d.%d.%d" % sys.version_info[:3]))
1171 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
1171 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
1172 os.path.dirname(pycompat.fsencode(os.__file__)))
1172 os.path.dirname(pycompat.fsencode(os.__file__)))
1173
1173
1174 security = set(sslutil.supportedprotocols)
1174 security = set(sslutil.supportedprotocols)
1175 if sslutil.hassni:
1175 if sslutil.hassni:
1176 security.add('sni')
1176 security.add('sni')
1177
1177
1178 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
1178 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
1179 fm.formatlist(sorted(security), name='protocol',
1179 fm.formatlist(sorted(security), name='protocol',
1180 fmt='%s', sep=','))
1180 fmt='%s', sep=','))
1181
1181
1182 # These are warnings, not errors. So don't increment problem count. This
1182 # These are warnings, not errors. So don't increment problem count. This
1183 # may change in the future.
1183 # may change in the future.
1184 if 'tls1.2' not in security:
1184 if 'tls1.2' not in security:
1185 fm.plain(_(' TLS 1.2 not supported by Python install; '
1185 fm.plain(_(' TLS 1.2 not supported by Python install; '
1186 'network connections lack modern security\n'))
1186 'network connections lack modern security\n'))
1187 if 'sni' not in security:
1187 if 'sni' not in security:
1188 fm.plain(_(' SNI not supported by Python install; may have '
1188 fm.plain(_(' SNI not supported by Python install; may have '
1189 'connectivity issues with some servers\n'))
1189 'connectivity issues with some servers\n'))
1190
1190
1191 # TODO print CA cert info
1191 # TODO print CA cert info
1192
1192
1193 # hg version
1193 # hg version
1194 hgver = util.version()
1194 hgver = util.version()
1195 fm.write('hgver', _("checking Mercurial version (%s)\n"),
1195 fm.write('hgver', _("checking Mercurial version (%s)\n"),
1196 hgver.split('+')[0])
1196 hgver.split('+')[0])
1197 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
1197 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
1198 '+'.join(hgver.split('+')[1:]))
1198 '+'.join(hgver.split('+')[1:]))
1199
1199
1200 # compiled modules
1200 # compiled modules
1201 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
1201 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
1202 policy.policy)
1202 policy.policy)
1203 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
1203 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
1204 os.path.dirname(pycompat.fsencode(__file__)))
1204 os.path.dirname(pycompat.fsencode(__file__)))
1205
1205
1206 if policy.policy in ('c', 'allow'):
1206 if policy.policy in ('c', 'allow'):
1207 err = None
1207 err = None
1208 try:
1208 try:
1209 from .cext import (
1209 from .cext import (
1210 base85,
1210 base85,
1211 bdiff,
1211 bdiff,
1212 mpatch,
1212 mpatch,
1213 osutil,
1213 osutil,
1214 )
1214 )
1215 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1215 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1216 except Exception as inst:
1216 except Exception as inst:
1217 err = stringutil.forcebytestr(inst)
1217 err = stringutil.forcebytestr(inst)
1218 problems += 1
1218 problems += 1
1219 fm.condwrite(err, 'extensionserror', " %s\n", err)
1219 fm.condwrite(err, 'extensionserror', " %s\n", err)
1220
1220
1221 compengines = util.compengines._engines.values()
1221 compengines = util.compengines._engines.values()
1222 fm.write('compengines', _('checking registered compression engines (%s)\n'),
1222 fm.write('compengines', _('checking registered compression engines (%s)\n'),
1223 fm.formatlist(sorted(e.name() for e in compengines),
1223 fm.formatlist(sorted(e.name() for e in compengines),
1224 name='compengine', fmt='%s', sep=', '))
1224 name='compengine', fmt='%s', sep=', '))
1225 fm.write('compenginesavail', _('checking available compression engines '
1225 fm.write('compenginesavail', _('checking available compression engines '
1226 '(%s)\n'),
1226 '(%s)\n'),
1227 fm.formatlist(sorted(e.name() for e in compengines
1227 fm.formatlist(sorted(e.name() for e in compengines
1228 if e.available()),
1228 if e.available()),
1229 name='compengine', fmt='%s', sep=', '))
1229 name='compengine', fmt='%s', sep=', '))
1230 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
1230 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
1231 fm.write('compenginesserver', _('checking available compression engines '
1231 fm.write('compenginesserver', _('checking available compression engines '
1232 'for wire protocol (%s)\n'),
1232 'for wire protocol (%s)\n'),
1233 fm.formatlist([e.name() for e in wirecompengines
1233 fm.formatlist([e.name() for e in wirecompengines
1234 if e.wireprotosupport()],
1234 if e.wireprotosupport()],
1235 name='compengine', fmt='%s', sep=', '))
1235 name='compengine', fmt='%s', sep=', '))
1236 re2 = 'missing'
1236 re2 = 'missing'
1237 if util._re2:
1237 if util._re2:
1238 re2 = 'available'
1238 re2 = 'available'
1239 fm.plain(_('checking "re2" regexp engine (%s)\n') % re2)
1239 fm.plain(_('checking "re2" regexp engine (%s)\n') % re2)
1240 fm.data(re2=bool(util._re2))
1240 fm.data(re2=bool(util._re2))
1241
1241
1242 # templates
1242 # templates
1243 p = templater.templatepaths()
1243 p = templater.templatepaths()
1244 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1244 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1245 fm.condwrite(not p, '', _(" no template directories found\n"))
1245 fm.condwrite(not p, '', _(" no template directories found\n"))
1246 if p:
1246 if p:
1247 m = templater.templatepath("map-cmdline.default")
1247 m = templater.templatepath("map-cmdline.default")
1248 if m:
1248 if m:
1249 # template found, check if it is working
1249 # template found, check if it is working
1250 err = None
1250 err = None
1251 try:
1251 try:
1252 templater.templater.frommapfile(m)
1252 templater.templater.frommapfile(m)
1253 except Exception as inst:
1253 except Exception as inst:
1254 err = stringutil.forcebytestr(inst)
1254 err = stringutil.forcebytestr(inst)
1255 p = None
1255 p = None
1256 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1256 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1257 else:
1257 else:
1258 p = None
1258 p = None
1259 fm.condwrite(p, 'defaulttemplate',
1259 fm.condwrite(p, 'defaulttemplate',
1260 _("checking default template (%s)\n"), m)
1260 _("checking default template (%s)\n"), m)
1261 fm.condwrite(not m, 'defaulttemplatenotfound',
1261 fm.condwrite(not m, 'defaulttemplatenotfound',
1262 _(" template '%s' not found\n"), "default")
1262 _(" template '%s' not found\n"), "default")
1263 if not p:
1263 if not p:
1264 problems += 1
1264 problems += 1
1265 fm.condwrite(not p, '',
1265 fm.condwrite(not p, '',
1266 _(" (templates seem to have been installed incorrectly)\n"))
1266 _(" (templates seem to have been installed incorrectly)\n"))
1267
1267
1268 # editor
1268 # editor
1269 editor = ui.geteditor()
1269 editor = ui.geteditor()
1270 editor = util.expandpath(editor)
1270 editor = util.expandpath(editor)
1271 editorbin = procutil.shellsplit(editor)[0]
1271 editorbin = procutil.shellsplit(editor)[0]
1272 fm.write('editor', _("checking commit editor... (%s)\n"), editorbin)
1272 fm.write('editor', _("checking commit editor... (%s)\n"), editorbin)
1273 cmdpath = procutil.findexe(editorbin)
1273 cmdpath = procutil.findexe(editorbin)
1274 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1274 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1275 _(" No commit editor set and can't find %s in PATH\n"
1275 _(" No commit editor set and can't find %s in PATH\n"
1276 " (specify a commit editor in your configuration"
1276 " (specify a commit editor in your configuration"
1277 " file)\n"), not cmdpath and editor == 'vi' and editorbin)
1277 " file)\n"), not cmdpath and editor == 'vi' and editorbin)
1278 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1278 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1279 _(" Can't find editor '%s' in PATH\n"
1279 _(" Can't find editor '%s' in PATH\n"
1280 " (specify a commit editor in your configuration"
1280 " (specify a commit editor in your configuration"
1281 " file)\n"), not cmdpath and editorbin)
1281 " file)\n"), not cmdpath and editorbin)
1282 if not cmdpath and editor != 'vi':
1282 if not cmdpath and editor != 'vi':
1283 problems += 1
1283 problems += 1
1284
1284
1285 # check username
1285 # check username
1286 username = None
1286 username = None
1287 err = None
1287 err = None
1288 try:
1288 try:
1289 username = ui.username()
1289 username = ui.username()
1290 except error.Abort as e:
1290 except error.Abort as e:
1291 err = stringutil.forcebytestr(e)
1291 err = stringutil.forcebytestr(e)
1292 problems += 1
1292 problems += 1
1293
1293
1294 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1294 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1295 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1295 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1296 " (specify a username in your configuration file)\n"), err)
1296 " (specify a username in your configuration file)\n"), err)
1297
1297
1298 fm.condwrite(not problems, '',
1298 fm.condwrite(not problems, '',
1299 _("no problems detected\n"))
1299 _("no problems detected\n"))
1300 if not problems:
1300 if not problems:
1301 fm.data(problems=problems)
1301 fm.data(problems=problems)
1302 fm.condwrite(problems, 'problems',
1302 fm.condwrite(problems, 'problems',
1303 _("%d problems detected,"
1303 _("%d problems detected,"
1304 " please check your install!\n"), problems)
1304 " please check your install!\n"), problems)
1305 fm.end()
1305 fm.end()
1306
1306
1307 return problems
1307 return problems
1308
1308
1309 @command('debugknown', [], _('REPO ID...'), norepo=True)
1309 @command('debugknown', [], _('REPO ID...'), norepo=True)
1310 def debugknown(ui, repopath, *ids, **opts):
1310 def debugknown(ui, repopath, *ids, **opts):
1311 """test whether node ids are known to a repo
1311 """test whether node ids are known to a repo
1312
1312
1313 Every ID must be a full-length hex node id string. Returns a list of 0s
1313 Every ID must be a full-length hex node id string. Returns a list of 0s
1314 and 1s indicating unknown/known.
1314 and 1s indicating unknown/known.
1315 """
1315 """
1316 opts = pycompat.byteskwargs(opts)
1316 opts = pycompat.byteskwargs(opts)
1317 repo = hg.peer(ui, opts, repopath)
1317 repo = hg.peer(ui, opts, repopath)
1318 if not repo.capable('known'):
1318 if not repo.capable('known'):
1319 raise error.Abort("known() not supported by target repository")
1319 raise error.Abort("known() not supported by target repository")
1320 flags = repo.known([bin(s) for s in ids])
1320 flags = repo.known([bin(s) for s in ids])
1321 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1321 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1322
1322
1323 @command('debuglabelcomplete', [], _('LABEL...'))
1323 @command('debuglabelcomplete', [], _('LABEL...'))
1324 def debuglabelcomplete(ui, repo, *args):
1324 def debuglabelcomplete(ui, repo, *args):
1325 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1325 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1326 debugnamecomplete(ui, repo, *args)
1326 debugnamecomplete(ui, repo, *args)
1327
1327
1328 @command('debuglocks',
1328 @command('debuglocks',
1329 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1329 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1330 ('W', 'force-wlock', None,
1330 ('W', 'force-wlock', None,
1331 _('free the working state lock (DANGEROUS)')),
1331 _('free the working state lock (DANGEROUS)')),
1332 ('s', 'set-lock', None, _('set the store lock until stopped')),
1332 ('s', 'set-lock', None, _('set the store lock until stopped')),
1333 ('S', 'set-wlock', None,
1333 ('S', 'set-wlock', None,
1334 _('set the working state lock until stopped'))],
1334 _('set the working state lock until stopped'))],
1335 _('[OPTION]...'))
1335 _('[OPTION]...'))
1336 def debuglocks(ui, repo, **opts):
1336 def debuglocks(ui, repo, **opts):
1337 """show or modify state of locks
1337 """show or modify state of locks
1338
1338
1339 By default, this command will show which locks are held. This
1339 By default, this command will show which locks are held. This
1340 includes the user and process holding the lock, the amount of time
1340 includes the user and process holding the lock, the amount of time
1341 the lock has been held, and the machine name where the process is
1341 the lock has been held, and the machine name where the process is
1342 running if it's not local.
1342 running if it's not local.
1343
1343
1344 Locks protect the integrity of Mercurial's data, so should be
1344 Locks protect the integrity of Mercurial's data, so should be
1345 treated with care. System crashes or other interruptions may cause
1345 treated with care. System crashes or other interruptions may cause
1346 locks to not be properly released, though Mercurial will usually
1346 locks to not be properly released, though Mercurial will usually
1347 detect and remove such stale locks automatically.
1347 detect and remove such stale locks automatically.
1348
1348
1349 However, detecting stale locks may not always be possible (for
1349 However, detecting stale locks may not always be possible (for
1350 instance, on a shared filesystem). Removing locks may also be
1350 instance, on a shared filesystem). Removing locks may also be
1351 blocked by filesystem permissions.
1351 blocked by filesystem permissions.
1352
1352
1353 Setting a lock will prevent other commands from changing the data.
1353 Setting a lock will prevent other commands from changing the data.
1354 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
1354 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
1355 The set locks are removed when the command exits.
1355 The set locks are removed when the command exits.
1356
1356
1357 Returns 0 if no locks are held.
1357 Returns 0 if no locks are held.
1358
1358
1359 """
1359 """
1360
1360
1361 if opts.get(r'force_lock'):
1361 if opts.get(r'force_lock'):
1362 repo.svfs.unlink('lock')
1362 repo.svfs.unlink('lock')
1363 if opts.get(r'force_wlock'):
1363 if opts.get(r'force_wlock'):
1364 repo.vfs.unlink('wlock')
1364 repo.vfs.unlink('wlock')
1365 if opts.get(r'force_lock') or opts.get(r'force_wlock'):
1365 if opts.get(r'force_lock') or opts.get(r'force_wlock'):
1366 return 0
1366 return 0
1367
1367
1368 locks = []
1368 locks = []
1369 try:
1369 try:
1370 if opts.get(r'set_wlock'):
1370 if opts.get(r'set_wlock'):
1371 try:
1371 try:
1372 locks.append(repo.wlock(False))
1372 locks.append(repo.wlock(False))
1373 except error.LockHeld:
1373 except error.LockHeld:
1374 raise error.Abort(_('wlock is already held'))
1374 raise error.Abort(_('wlock is already held'))
1375 if opts.get(r'set_lock'):
1375 if opts.get(r'set_lock'):
1376 try:
1376 try:
1377 locks.append(repo.lock(False))
1377 locks.append(repo.lock(False))
1378 except error.LockHeld:
1378 except error.LockHeld:
1379 raise error.Abort(_('lock is already held'))
1379 raise error.Abort(_('lock is already held'))
1380 if len(locks):
1380 if len(locks):
1381 ui.promptchoice(_("ready to release the lock (y)? $$ &Yes"))
1381 ui.promptchoice(_("ready to release the lock (y)? $$ &Yes"))
1382 return 0
1382 return 0
1383 finally:
1383 finally:
1384 release(*locks)
1384 release(*locks)
1385
1385
1386 now = time.time()
1386 now = time.time()
1387 held = 0
1387 held = 0
1388
1388
1389 def report(vfs, name, method):
1389 def report(vfs, name, method):
1390 # this causes stale locks to get reaped for more accurate reporting
1390 # this causes stale locks to get reaped for more accurate reporting
1391 try:
1391 try:
1392 l = method(False)
1392 l = method(False)
1393 except error.LockHeld:
1393 except error.LockHeld:
1394 l = None
1394 l = None
1395
1395
1396 if l:
1396 if l:
1397 l.release()
1397 l.release()
1398 else:
1398 else:
1399 try:
1399 try:
1400 st = vfs.lstat(name)
1400 st = vfs.lstat(name)
1401 age = now - st[stat.ST_MTIME]
1401 age = now - st[stat.ST_MTIME]
1402 user = util.username(st.st_uid)
1402 user = util.username(st.st_uid)
1403 locker = vfs.readlock(name)
1403 locker = vfs.readlock(name)
1404 if ":" in locker:
1404 if ":" in locker:
1405 host, pid = locker.split(':')
1405 host, pid = locker.split(':')
1406 if host == socket.gethostname():
1406 if host == socket.gethostname():
1407 locker = 'user %s, process %s' % (user, pid)
1407 locker = 'user %s, process %s' % (user, pid)
1408 else:
1408 else:
1409 locker = 'user %s, process %s, host %s' \
1409 locker = 'user %s, process %s, host %s' \
1410 % (user, pid, host)
1410 % (user, pid, host)
1411 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1411 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1412 return 1
1412 return 1
1413 except OSError as e:
1413 except OSError as e:
1414 if e.errno != errno.ENOENT:
1414 if e.errno != errno.ENOENT:
1415 raise
1415 raise
1416
1416
1417 ui.write(("%-6s free\n") % (name + ":"))
1417 ui.write(("%-6s free\n") % (name + ":"))
1418 return 0
1418 return 0
1419
1419
1420 held += report(repo.svfs, "lock", repo.lock)
1420 held += report(repo.svfs, "lock", repo.lock)
1421 held += report(repo.vfs, "wlock", repo.wlock)
1421 held += report(repo.vfs, "wlock", repo.wlock)
1422
1422
1423 return held
1423 return held
1424
1424
1425 @command('debugmergestate', [], '')
1425 @command('debugmergestate', [], '')
1426 def debugmergestate(ui, repo, *args):
1426 def debugmergestate(ui, repo, *args):
1427 """print merge state
1427 """print merge state
1428
1428
1429 Use --verbose to print out information about whether v1 or v2 merge state
1429 Use --verbose to print out information about whether v1 or v2 merge state
1430 was chosen."""
1430 was chosen."""
1431 def _hashornull(h):
1431 def _hashornull(h):
1432 if h == nullhex:
1432 if h == nullhex:
1433 return 'null'
1433 return 'null'
1434 else:
1434 else:
1435 return h
1435 return h
1436
1436
1437 def printrecords(version):
1437 def printrecords(version):
1438 ui.write(('* version %d records\n') % version)
1438 ui.write(('* version %d records\n') % version)
1439 if version == 1:
1439 if version == 1:
1440 records = v1records
1440 records = v1records
1441 else:
1441 else:
1442 records = v2records
1442 records = v2records
1443
1443
1444 for rtype, record in records:
1444 for rtype, record in records:
1445 # pretty print some record types
1445 # pretty print some record types
1446 if rtype == 'L':
1446 if rtype == 'L':
1447 ui.write(('local: %s\n') % record)
1447 ui.write(('local: %s\n') % record)
1448 elif rtype == 'O':
1448 elif rtype == 'O':
1449 ui.write(('other: %s\n') % record)
1449 ui.write(('other: %s\n') % record)
1450 elif rtype == 'm':
1450 elif rtype == 'm':
1451 driver, mdstate = record.split('\0', 1)
1451 driver, mdstate = record.split('\0', 1)
1452 ui.write(('merge driver: %s (state "%s")\n')
1452 ui.write(('merge driver: %s (state "%s")\n')
1453 % (driver, mdstate))
1453 % (driver, mdstate))
1454 elif rtype in 'FDC':
1454 elif rtype in 'FDC':
1455 r = record.split('\0')
1455 r = record.split('\0')
1456 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1456 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1457 if version == 1:
1457 if version == 1:
1458 onode = 'not stored in v1 format'
1458 onode = 'not stored in v1 format'
1459 flags = r[7]
1459 flags = r[7]
1460 else:
1460 else:
1461 onode, flags = r[7:9]
1461 onode, flags = r[7:9]
1462 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1462 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1463 % (f, rtype, state, _hashornull(hash)))
1463 % (f, rtype, state, _hashornull(hash)))
1464 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1464 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1465 ui.write((' ancestor path: %s (node %s)\n')
1465 ui.write((' ancestor path: %s (node %s)\n')
1466 % (afile, _hashornull(anode)))
1466 % (afile, _hashornull(anode)))
1467 ui.write((' other path: %s (node %s)\n')
1467 ui.write((' other path: %s (node %s)\n')
1468 % (ofile, _hashornull(onode)))
1468 % (ofile, _hashornull(onode)))
1469 elif rtype == 'f':
1469 elif rtype == 'f':
1470 filename, rawextras = record.split('\0', 1)
1470 filename, rawextras = record.split('\0', 1)
1471 extras = rawextras.split('\0')
1471 extras = rawextras.split('\0')
1472 i = 0
1472 i = 0
1473 extrastrings = []
1473 extrastrings = []
1474 while i < len(extras):
1474 while i < len(extras):
1475 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1475 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1476 i += 2
1476 i += 2
1477
1477
1478 ui.write(('file extras: %s (%s)\n')
1478 ui.write(('file extras: %s (%s)\n')
1479 % (filename, ', '.join(extrastrings)))
1479 % (filename, ', '.join(extrastrings)))
1480 elif rtype == 'l':
1480 elif rtype == 'l':
1481 labels = record.split('\0', 2)
1481 labels = record.split('\0', 2)
1482 labels = [l for l in labels if len(l) > 0]
1482 labels = [l for l in labels if len(l) > 0]
1483 ui.write(('labels:\n'))
1483 ui.write(('labels:\n'))
1484 ui.write((' local: %s\n' % labels[0]))
1484 ui.write((' local: %s\n' % labels[0]))
1485 ui.write((' other: %s\n' % labels[1]))
1485 ui.write((' other: %s\n' % labels[1]))
1486 if len(labels) > 2:
1486 if len(labels) > 2:
1487 ui.write((' base: %s\n' % labels[2]))
1487 ui.write((' base: %s\n' % labels[2]))
1488 else:
1488 else:
1489 ui.write(('unrecognized entry: %s\t%s\n')
1489 ui.write(('unrecognized entry: %s\t%s\n')
1490 % (rtype, record.replace('\0', '\t')))
1490 % (rtype, record.replace('\0', '\t')))
1491
1491
1492 # Avoid mergestate.read() since it may raise an exception for unsupported
1492 # Avoid mergestate.read() since it may raise an exception for unsupported
1493 # merge state records. We shouldn't be doing this, but this is OK since this
1493 # merge state records. We shouldn't be doing this, but this is OK since this
1494 # command is pretty low-level.
1494 # command is pretty low-level.
1495 ms = mergemod.mergestate(repo)
1495 ms = mergemod.mergestate(repo)
1496
1496
1497 # sort so that reasonable information is on top
1497 # sort so that reasonable information is on top
1498 v1records = ms._readrecordsv1()
1498 v1records = ms._readrecordsv1()
1499 v2records = ms._readrecordsv2()
1499 v2records = ms._readrecordsv2()
1500 order = 'LOml'
1500 order = 'LOml'
1501 def key(r):
1501 def key(r):
1502 idx = order.find(r[0])
1502 idx = order.find(r[0])
1503 if idx == -1:
1503 if idx == -1:
1504 return (1, r[1])
1504 return (1, r[1])
1505 else:
1505 else:
1506 return (0, idx)
1506 return (0, idx)
1507 v1records.sort(key=key)
1507 v1records.sort(key=key)
1508 v2records.sort(key=key)
1508 v2records.sort(key=key)
1509
1509
1510 if not v1records and not v2records:
1510 if not v1records and not v2records:
1511 ui.write(('no merge state found\n'))
1511 ui.write(('no merge state found\n'))
1512 elif not v2records:
1512 elif not v2records:
1513 ui.note(('no version 2 merge state\n'))
1513 ui.note(('no version 2 merge state\n'))
1514 printrecords(1)
1514 printrecords(1)
1515 elif ms._v1v2match(v1records, v2records):
1515 elif ms._v1v2match(v1records, v2records):
1516 ui.note(('v1 and v2 states match: using v2\n'))
1516 ui.note(('v1 and v2 states match: using v2\n'))
1517 printrecords(2)
1517 printrecords(2)
1518 else:
1518 else:
1519 ui.note(('v1 and v2 states mismatch: using v1\n'))
1519 ui.note(('v1 and v2 states mismatch: using v1\n'))
1520 printrecords(1)
1520 printrecords(1)
1521 if ui.verbose:
1521 if ui.verbose:
1522 printrecords(2)
1522 printrecords(2)
1523
1523
1524 @command('debugnamecomplete', [], _('NAME...'))
1524 @command('debugnamecomplete', [], _('NAME...'))
1525 def debugnamecomplete(ui, repo, *args):
1525 def debugnamecomplete(ui, repo, *args):
1526 '''complete "names" - tags, open branch names, bookmark names'''
1526 '''complete "names" - tags, open branch names, bookmark names'''
1527
1527
1528 names = set()
1528 names = set()
1529 # since we previously only listed open branches, we will handle that
1529 # since we previously only listed open branches, we will handle that
1530 # specially (after this for loop)
1530 # specially (after this for loop)
1531 for name, ns in repo.names.iteritems():
1531 for name, ns in repo.names.iteritems():
1532 if name != 'branches':
1532 if name != 'branches':
1533 names.update(ns.listnames(repo))
1533 names.update(ns.listnames(repo))
1534 names.update(tag for (tag, heads, tip, closed)
1534 names.update(tag for (tag, heads, tip, closed)
1535 in repo.branchmap().iterbranches() if not closed)
1535 in repo.branchmap().iterbranches() if not closed)
1536 completions = set()
1536 completions = set()
1537 if not args:
1537 if not args:
1538 args = ['']
1538 args = ['']
1539 for a in args:
1539 for a in args:
1540 completions.update(n for n in names if n.startswith(a))
1540 completions.update(n for n in names if n.startswith(a))
1541 ui.write('\n'.join(sorted(completions)))
1541 ui.write('\n'.join(sorted(completions)))
1542 ui.write('\n')
1542 ui.write('\n')
1543
1543
1544 @command('debugobsolete',
1544 @command('debugobsolete',
1545 [('', 'flags', 0, _('markers flag')),
1545 [('', 'flags', 0, _('markers flag')),
1546 ('', 'record-parents', False,
1546 ('', 'record-parents', False,
1547 _('record parent information for the precursor')),
1547 _('record parent information for the precursor')),
1548 ('r', 'rev', [], _('display markers relevant to REV')),
1548 ('r', 'rev', [], _('display markers relevant to REV')),
1549 ('', 'exclusive', False, _('restrict display to markers only '
1549 ('', 'exclusive', False, _('restrict display to markers only '
1550 'relevant to REV')),
1550 'relevant to REV')),
1551 ('', 'index', False, _('display index of the marker')),
1551 ('', 'index', False, _('display index of the marker')),
1552 ('', 'delete', [], _('delete markers specified by indices')),
1552 ('', 'delete', [], _('delete markers specified by indices')),
1553 ] + cmdutil.commitopts2 + cmdutil.formatteropts,
1553 ] + cmdutil.commitopts2 + cmdutil.formatteropts,
1554 _('[OBSOLETED [REPLACEMENT ...]]'))
1554 _('[OBSOLETED [REPLACEMENT ...]]'))
1555 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1555 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1556 """create arbitrary obsolete marker
1556 """create arbitrary obsolete marker
1557
1557
1558 With no arguments, displays the list of obsolescence markers."""
1558 With no arguments, displays the list of obsolescence markers."""
1559
1559
1560 opts = pycompat.byteskwargs(opts)
1560 opts = pycompat.byteskwargs(opts)
1561
1561
1562 def parsenodeid(s):
1562 def parsenodeid(s):
1563 try:
1563 try:
1564 # We do not use revsingle/revrange functions here to accept
1564 # We do not use revsingle/revrange functions here to accept
1565 # arbitrary node identifiers, possibly not present in the
1565 # arbitrary node identifiers, possibly not present in the
1566 # local repository.
1566 # local repository.
1567 n = bin(s)
1567 n = bin(s)
1568 if len(n) != len(nullid):
1568 if len(n) != len(nullid):
1569 raise TypeError()
1569 raise TypeError()
1570 return n
1570 return n
1571 except TypeError:
1571 except TypeError:
1572 raise error.Abort('changeset references must be full hexadecimal '
1572 raise error.Abort('changeset references must be full hexadecimal '
1573 'node identifiers')
1573 'node identifiers')
1574
1574
1575 if opts.get('delete'):
1575 if opts.get('delete'):
1576 indices = []
1576 indices = []
1577 for v in opts.get('delete'):
1577 for v in opts.get('delete'):
1578 try:
1578 try:
1579 indices.append(int(v))
1579 indices.append(int(v))
1580 except ValueError:
1580 except ValueError:
1581 raise error.Abort(_('invalid index value: %r') % v,
1581 raise error.Abort(_('invalid index value: %r') % v,
1582 hint=_('use integers for indices'))
1582 hint=_('use integers for indices'))
1583
1583
1584 if repo.currenttransaction():
1584 if repo.currenttransaction():
1585 raise error.Abort(_('cannot delete obsmarkers in the middle '
1585 raise error.Abort(_('cannot delete obsmarkers in the middle '
1586 'of transaction.'))
1586 'of transaction.'))
1587
1587
1588 with repo.lock():
1588 with repo.lock():
1589 n = repair.deleteobsmarkers(repo.obsstore, indices)
1589 n = repair.deleteobsmarkers(repo.obsstore, indices)
1590 ui.write(_('deleted %i obsolescence markers\n') % n)
1590 ui.write(_('deleted %i obsolescence markers\n') % n)
1591
1591
1592 return
1592 return
1593
1593
1594 if precursor is not None:
1594 if precursor is not None:
1595 if opts['rev']:
1595 if opts['rev']:
1596 raise error.Abort('cannot select revision when creating marker')
1596 raise error.Abort('cannot select revision when creating marker')
1597 metadata = {}
1597 metadata = {}
1598 metadata['user'] = opts['user'] or ui.username()
1598 metadata['user'] = opts['user'] or ui.username()
1599 succs = tuple(parsenodeid(succ) for succ in successors)
1599 succs = tuple(parsenodeid(succ) for succ in successors)
1600 l = repo.lock()
1600 l = repo.lock()
1601 try:
1601 try:
1602 tr = repo.transaction('debugobsolete')
1602 tr = repo.transaction('debugobsolete')
1603 try:
1603 try:
1604 date = opts.get('date')
1604 date = opts.get('date')
1605 if date:
1605 if date:
1606 date = dateutil.parsedate(date)
1606 date = dateutil.parsedate(date)
1607 else:
1607 else:
1608 date = None
1608 date = None
1609 prec = parsenodeid(precursor)
1609 prec = parsenodeid(precursor)
1610 parents = None
1610 parents = None
1611 if opts['record_parents']:
1611 if opts['record_parents']:
1612 if prec not in repo.unfiltered():
1612 if prec not in repo.unfiltered():
1613 raise error.Abort('cannot used --record-parents on '
1613 raise error.Abort('cannot used --record-parents on '
1614 'unknown changesets')
1614 'unknown changesets')
1615 parents = repo.unfiltered()[prec].parents()
1615 parents = repo.unfiltered()[prec].parents()
1616 parents = tuple(p.node() for p in parents)
1616 parents = tuple(p.node() for p in parents)
1617 repo.obsstore.create(tr, prec, succs, opts['flags'],
1617 repo.obsstore.create(tr, prec, succs, opts['flags'],
1618 parents=parents, date=date,
1618 parents=parents, date=date,
1619 metadata=metadata, ui=ui)
1619 metadata=metadata, ui=ui)
1620 tr.close()
1620 tr.close()
1621 except ValueError as exc:
1621 except ValueError as exc:
1622 raise error.Abort(_('bad obsmarker input: %s') %
1622 raise error.Abort(_('bad obsmarker input: %s') %
1623 pycompat.bytestr(exc))
1623 pycompat.bytestr(exc))
1624 finally:
1624 finally:
1625 tr.release()
1625 tr.release()
1626 finally:
1626 finally:
1627 l.release()
1627 l.release()
1628 else:
1628 else:
1629 if opts['rev']:
1629 if opts['rev']:
1630 revs = scmutil.revrange(repo, opts['rev'])
1630 revs = scmutil.revrange(repo, opts['rev'])
1631 nodes = [repo[r].node() for r in revs]
1631 nodes = [repo[r].node() for r in revs]
1632 markers = list(obsutil.getmarkers(repo, nodes=nodes,
1632 markers = list(obsutil.getmarkers(repo, nodes=nodes,
1633 exclusive=opts['exclusive']))
1633 exclusive=opts['exclusive']))
1634 markers.sort(key=lambda x: x._data)
1634 markers.sort(key=lambda x: x._data)
1635 else:
1635 else:
1636 markers = obsutil.getmarkers(repo)
1636 markers = obsutil.getmarkers(repo)
1637
1637
1638 markerstoiter = markers
1638 markerstoiter = markers
1639 isrelevant = lambda m: True
1639 isrelevant = lambda m: True
1640 if opts.get('rev') and opts.get('index'):
1640 if opts.get('rev') and opts.get('index'):
1641 markerstoiter = obsutil.getmarkers(repo)
1641 markerstoiter = obsutil.getmarkers(repo)
1642 markerset = set(markers)
1642 markerset = set(markers)
1643 isrelevant = lambda m: m in markerset
1643 isrelevant = lambda m: m in markerset
1644
1644
1645 fm = ui.formatter('debugobsolete', opts)
1645 fm = ui.formatter('debugobsolete', opts)
1646 for i, m in enumerate(markerstoiter):
1646 for i, m in enumerate(markerstoiter):
1647 if not isrelevant(m):
1647 if not isrelevant(m):
1648 # marker can be irrelevant when we're iterating over a set
1648 # marker can be irrelevant when we're iterating over a set
1649 # of markers (markerstoiter) which is bigger than the set
1649 # of markers (markerstoiter) which is bigger than the set
1650 # of markers we want to display (markers)
1650 # of markers we want to display (markers)
1651 # this can happen if both --index and --rev options are
1651 # this can happen if both --index and --rev options are
1652 # provided and thus we need to iterate over all of the markers
1652 # provided and thus we need to iterate over all of the markers
1653 # to get the correct indices, but only display the ones that
1653 # to get the correct indices, but only display the ones that
1654 # are relevant to --rev value
1654 # are relevant to --rev value
1655 continue
1655 continue
1656 fm.startitem()
1656 fm.startitem()
1657 ind = i if opts.get('index') else None
1657 ind = i if opts.get('index') else None
1658 cmdutil.showmarker(fm, m, index=ind)
1658 cmdutil.showmarker(fm, m, index=ind)
1659 fm.end()
1659 fm.end()
1660
1660
1661 @command('debugpathcomplete',
1661 @command('debugpathcomplete',
1662 [('f', 'full', None, _('complete an entire path')),
1662 [('f', 'full', None, _('complete an entire path')),
1663 ('n', 'normal', None, _('show only normal files')),
1663 ('n', 'normal', None, _('show only normal files')),
1664 ('a', 'added', None, _('show only added files')),
1664 ('a', 'added', None, _('show only added files')),
1665 ('r', 'removed', None, _('show only removed files'))],
1665 ('r', 'removed', None, _('show only removed files'))],
1666 _('FILESPEC...'))
1666 _('FILESPEC...'))
1667 def debugpathcomplete(ui, repo, *specs, **opts):
1667 def debugpathcomplete(ui, repo, *specs, **opts):
1668 '''complete part or all of a tracked path
1668 '''complete part or all of a tracked path
1669
1669
1670 This command supports shells that offer path name completion. It
1670 This command supports shells that offer path name completion. It
1671 currently completes only files already known to the dirstate.
1671 currently completes only files already known to the dirstate.
1672
1672
1673 Completion extends only to the next path segment unless
1673 Completion extends only to the next path segment unless
1674 --full is specified, in which case entire paths are used.'''
1674 --full is specified, in which case entire paths are used.'''
1675
1675
1676 def complete(path, acceptable):
1676 def complete(path, acceptable):
1677 dirstate = repo.dirstate
1677 dirstate = repo.dirstate
1678 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1678 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1679 rootdir = repo.root + pycompat.ossep
1679 rootdir = repo.root + pycompat.ossep
1680 if spec != repo.root and not spec.startswith(rootdir):
1680 if spec != repo.root and not spec.startswith(rootdir):
1681 return [], []
1681 return [], []
1682 if os.path.isdir(spec):
1682 if os.path.isdir(spec):
1683 spec += '/'
1683 spec += '/'
1684 spec = spec[len(rootdir):]
1684 spec = spec[len(rootdir):]
1685 fixpaths = pycompat.ossep != '/'
1685 fixpaths = pycompat.ossep != '/'
1686 if fixpaths:
1686 if fixpaths:
1687 spec = spec.replace(pycompat.ossep, '/')
1687 spec = spec.replace(pycompat.ossep, '/')
1688 speclen = len(spec)
1688 speclen = len(spec)
1689 fullpaths = opts[r'full']
1689 fullpaths = opts[r'full']
1690 files, dirs = set(), set()
1690 files, dirs = set(), set()
1691 adddir, addfile = dirs.add, files.add
1691 adddir, addfile = dirs.add, files.add
1692 for f, st in dirstate.iteritems():
1692 for f, st in dirstate.iteritems():
1693 if f.startswith(spec) and st[0] in acceptable:
1693 if f.startswith(spec) and st[0] in acceptable:
1694 if fixpaths:
1694 if fixpaths:
1695 f = f.replace('/', pycompat.ossep)
1695 f = f.replace('/', pycompat.ossep)
1696 if fullpaths:
1696 if fullpaths:
1697 addfile(f)
1697 addfile(f)
1698 continue
1698 continue
1699 s = f.find(pycompat.ossep, speclen)
1699 s = f.find(pycompat.ossep, speclen)
1700 if s >= 0:
1700 if s >= 0:
1701 adddir(f[:s])
1701 adddir(f[:s])
1702 else:
1702 else:
1703 addfile(f)
1703 addfile(f)
1704 return files, dirs
1704 return files, dirs
1705
1705
1706 acceptable = ''
1706 acceptable = ''
1707 if opts[r'normal']:
1707 if opts[r'normal']:
1708 acceptable += 'nm'
1708 acceptable += 'nm'
1709 if opts[r'added']:
1709 if opts[r'added']:
1710 acceptable += 'a'
1710 acceptable += 'a'
1711 if opts[r'removed']:
1711 if opts[r'removed']:
1712 acceptable += 'r'
1712 acceptable += 'r'
1713 cwd = repo.getcwd()
1713 cwd = repo.getcwd()
1714 if not specs:
1714 if not specs:
1715 specs = ['.']
1715 specs = ['.']
1716
1716
1717 files, dirs = set(), set()
1717 files, dirs = set(), set()
1718 for spec in specs:
1718 for spec in specs:
1719 f, d = complete(spec, acceptable or 'nmar')
1719 f, d = complete(spec, acceptable or 'nmar')
1720 files.update(f)
1720 files.update(f)
1721 dirs.update(d)
1721 dirs.update(d)
1722 files.update(dirs)
1722 files.update(dirs)
1723 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1723 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1724 ui.write('\n')
1724 ui.write('\n')
1725
1725
1726 @command('debugpeer', [], _('PATH'), norepo=True)
1726 @command('debugpeer', [], _('PATH'), norepo=True)
1727 def debugpeer(ui, path):
1727 def debugpeer(ui, path):
1728 """establish a connection to a peer repository"""
1728 """establish a connection to a peer repository"""
1729 # Always enable peer request logging. Requires --debug to display
1729 # Always enable peer request logging. Requires --debug to display
1730 # though.
1730 # though.
1731 overrides = {
1731 overrides = {
1732 ('devel', 'debug.peer-request'): True,
1732 ('devel', 'debug.peer-request'): True,
1733 }
1733 }
1734
1734
1735 with ui.configoverride(overrides):
1735 with ui.configoverride(overrides):
1736 peer = hg.peer(ui, {}, path)
1736 peer = hg.peer(ui, {}, path)
1737
1737
1738 local = peer.local() is not None
1738 local = peer.local() is not None
1739 canpush = peer.canpush()
1739 canpush = peer.canpush()
1740
1740
1741 ui.write(_('url: %s\n') % peer.url())
1741 ui.write(_('url: %s\n') % peer.url())
1742 ui.write(_('local: %s\n') % (_('yes') if local else _('no')))
1742 ui.write(_('local: %s\n') % (_('yes') if local else _('no')))
1743 ui.write(_('pushable: %s\n') % (_('yes') if canpush else _('no')))
1743 ui.write(_('pushable: %s\n') % (_('yes') if canpush else _('no')))
1744
1744
1745 @command('debugpickmergetool',
1745 @command('debugpickmergetool',
1746 [('r', 'rev', '', _('check for files in this revision'), _('REV')),
1746 [('r', 'rev', '', _('check for files in this revision'), _('REV')),
1747 ('', 'changedelete', None, _('emulate merging change and delete')),
1747 ('', 'changedelete', None, _('emulate merging change and delete')),
1748 ] + cmdutil.walkopts + cmdutil.mergetoolopts,
1748 ] + cmdutil.walkopts + cmdutil.mergetoolopts,
1749 _('[PATTERN]...'),
1749 _('[PATTERN]...'),
1750 inferrepo=True)
1750 inferrepo=True)
1751 def debugpickmergetool(ui, repo, *pats, **opts):
1751 def debugpickmergetool(ui, repo, *pats, **opts):
1752 """examine which merge tool is chosen for specified file
1752 """examine which merge tool is chosen for specified file
1753
1753
1754 As described in :hg:`help merge-tools`, Mercurial examines
1754 As described in :hg:`help merge-tools`, Mercurial examines
1755 configurations below in this order to decide which merge tool is
1755 configurations below in this order to decide which merge tool is
1756 chosen for specified file.
1756 chosen for specified file.
1757
1757
1758 1. ``--tool`` option
1758 1. ``--tool`` option
1759 2. ``HGMERGE`` environment variable
1759 2. ``HGMERGE`` environment variable
1760 3. configurations in ``merge-patterns`` section
1760 3. configurations in ``merge-patterns`` section
1761 4. configuration of ``ui.merge``
1761 4. configuration of ``ui.merge``
1762 5. configurations in ``merge-tools`` section
1762 5. configurations in ``merge-tools`` section
1763 6. ``hgmerge`` tool (for historical reason only)
1763 6. ``hgmerge`` tool (for historical reason only)
1764 7. default tool for fallback (``:merge`` or ``:prompt``)
1764 7. default tool for fallback (``:merge`` or ``:prompt``)
1765
1765
1766 This command writes out examination result in the style below::
1766 This command writes out examination result in the style below::
1767
1767
1768 FILE = MERGETOOL
1768 FILE = MERGETOOL
1769
1769
1770 By default, all files known in the first parent context of the
1770 By default, all files known in the first parent context of the
1771 working directory are examined. Use file patterns and/or -I/-X
1771 working directory are examined. Use file patterns and/or -I/-X
1772 options to limit target files. -r/--rev is also useful to examine
1772 options to limit target files. -r/--rev is also useful to examine
1773 files in another context without actual updating to it.
1773 files in another context without actual updating to it.
1774
1774
1775 With --debug, this command shows warning messages while matching
1775 With --debug, this command shows warning messages while matching
1776 against ``merge-patterns`` and so on, too. It is recommended to
1776 against ``merge-patterns`` and so on, too. It is recommended to
1777 use this option with explicit file patterns and/or -I/-X options,
1777 use this option with explicit file patterns and/or -I/-X options,
1778 because this option increases amount of output per file according
1778 because this option increases amount of output per file according
1779 to configurations in hgrc.
1779 to configurations in hgrc.
1780
1780
1781 With -v/--verbose, this command shows configurations below at
1781 With -v/--verbose, this command shows configurations below at
1782 first (only if specified).
1782 first (only if specified).
1783
1783
1784 - ``--tool`` option
1784 - ``--tool`` option
1785 - ``HGMERGE`` environment variable
1785 - ``HGMERGE`` environment variable
1786 - configuration of ``ui.merge``
1786 - configuration of ``ui.merge``
1787
1787
1788 If merge tool is chosen before matching against
1788 If merge tool is chosen before matching against
1789 ``merge-patterns``, this command can't show any helpful
1789 ``merge-patterns``, this command can't show any helpful
1790 information, even with --debug. In such case, information above is
1790 information, even with --debug. In such case, information above is
1791 useful to know why a merge tool is chosen.
1791 useful to know why a merge tool is chosen.
1792 """
1792 """
1793 opts = pycompat.byteskwargs(opts)
1793 opts = pycompat.byteskwargs(opts)
1794 overrides = {}
1794 overrides = {}
1795 if opts['tool']:
1795 if opts['tool']:
1796 overrides[('ui', 'forcemerge')] = opts['tool']
1796 overrides[('ui', 'forcemerge')] = opts['tool']
1797 ui.note(('with --tool %r\n') % (pycompat.bytestr(opts['tool'])))
1797 ui.note(('with --tool %r\n') % (pycompat.bytestr(opts['tool'])))
1798
1798
1799 with ui.configoverride(overrides, 'debugmergepatterns'):
1799 with ui.configoverride(overrides, 'debugmergepatterns'):
1800 hgmerge = encoding.environ.get("HGMERGE")
1800 hgmerge = encoding.environ.get("HGMERGE")
1801 if hgmerge is not None:
1801 if hgmerge is not None:
1802 ui.note(('with HGMERGE=%r\n') % (pycompat.bytestr(hgmerge)))
1802 ui.note(('with HGMERGE=%r\n') % (pycompat.bytestr(hgmerge)))
1803 uimerge = ui.config("ui", "merge")
1803 uimerge = ui.config("ui", "merge")
1804 if uimerge:
1804 if uimerge:
1805 ui.note(('with ui.merge=%r\n') % (pycompat.bytestr(uimerge)))
1805 ui.note(('with ui.merge=%r\n') % (pycompat.bytestr(uimerge)))
1806
1806
1807 ctx = scmutil.revsingle(repo, opts.get('rev'))
1807 ctx = scmutil.revsingle(repo, opts.get('rev'))
1808 m = scmutil.match(ctx, pats, opts)
1808 m = scmutil.match(ctx, pats, opts)
1809 changedelete = opts['changedelete']
1809 changedelete = opts['changedelete']
1810 for path in ctx.walk(m):
1810 for path in ctx.walk(m):
1811 fctx = ctx[path]
1811 fctx = ctx[path]
1812 try:
1812 try:
1813 if not ui.debugflag:
1813 if not ui.debugflag:
1814 ui.pushbuffer(error=True)
1814 ui.pushbuffer(error=True)
1815 tool, toolpath = filemerge._picktool(repo, ui, path,
1815 tool, toolpath = filemerge._picktool(repo, ui, path,
1816 fctx.isbinary(),
1816 fctx.isbinary(),
1817 'l' in fctx.flags(),
1817 'l' in fctx.flags(),
1818 changedelete)
1818 changedelete)
1819 finally:
1819 finally:
1820 if not ui.debugflag:
1820 if not ui.debugflag:
1821 ui.popbuffer()
1821 ui.popbuffer()
1822 ui.write(('%s = %s\n') % (path, tool))
1822 ui.write(('%s = %s\n') % (path, tool))
1823
1823
1824 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1824 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1825 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1825 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1826 '''access the pushkey key/value protocol
1826 '''access the pushkey key/value protocol
1827
1827
1828 With two args, list the keys in the given namespace.
1828 With two args, list the keys in the given namespace.
1829
1829
1830 With five args, set a key to new if it currently is set to old.
1830 With five args, set a key to new if it currently is set to old.
1831 Reports success or failure.
1831 Reports success or failure.
1832 '''
1832 '''
1833
1833
1834 target = hg.peer(ui, {}, repopath)
1834 target = hg.peer(ui, {}, repopath)
1835 if keyinfo:
1835 if keyinfo:
1836 key, old, new = keyinfo
1836 key, old, new = keyinfo
1837 with target.commandexecutor() as e:
1837 with target.commandexecutor() as e:
1838 r = e.callcommand('pushkey', {
1838 r = e.callcommand('pushkey', {
1839 'namespace': namespace,
1839 'namespace': namespace,
1840 'key': key,
1840 'key': key,
1841 'old': old,
1841 'old': old,
1842 'new': new,
1842 'new': new,
1843 }).result()
1843 }).result()
1844
1844
1845 ui.status(pycompat.bytestr(r) + '\n')
1845 ui.status(pycompat.bytestr(r) + '\n')
1846 return not r
1846 return not r
1847 else:
1847 else:
1848 for k, v in sorted(target.listkeys(namespace).iteritems()):
1848 for k, v in sorted(target.listkeys(namespace).iteritems()):
1849 ui.write("%s\t%s\n" % (stringutil.escapestr(k),
1849 ui.write("%s\t%s\n" % (stringutil.escapestr(k),
1850 stringutil.escapestr(v)))
1850 stringutil.escapestr(v)))
1851
1851
1852 @command('debugpvec', [], _('A B'))
1852 @command('debugpvec', [], _('A B'))
1853 def debugpvec(ui, repo, a, b=None):
1853 def debugpvec(ui, repo, a, b=None):
1854 ca = scmutil.revsingle(repo, a)
1854 ca = scmutil.revsingle(repo, a)
1855 cb = scmutil.revsingle(repo, b)
1855 cb = scmutil.revsingle(repo, b)
1856 pa = pvec.ctxpvec(ca)
1856 pa = pvec.ctxpvec(ca)
1857 pb = pvec.ctxpvec(cb)
1857 pb = pvec.ctxpvec(cb)
1858 if pa == pb:
1858 if pa == pb:
1859 rel = "="
1859 rel = "="
1860 elif pa > pb:
1860 elif pa > pb:
1861 rel = ">"
1861 rel = ">"
1862 elif pa < pb:
1862 elif pa < pb:
1863 rel = "<"
1863 rel = "<"
1864 elif pa | pb:
1864 elif pa | pb:
1865 rel = "|"
1865 rel = "|"
1866 ui.write(_("a: %s\n") % pa)
1866 ui.write(_("a: %s\n") % pa)
1867 ui.write(_("b: %s\n") % pb)
1867 ui.write(_("b: %s\n") % pb)
1868 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1868 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1869 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1869 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1870 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1870 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1871 pa.distance(pb), rel))
1871 pa.distance(pb), rel))
1872
1872
1873 @command('debugrebuilddirstate|debugrebuildstate',
1873 @command('debugrebuilddirstate|debugrebuildstate',
1874 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1874 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1875 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1875 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1876 'the working copy parent')),
1876 'the working copy parent')),
1877 ],
1877 ],
1878 _('[-r REV]'))
1878 _('[-r REV]'))
1879 def debugrebuilddirstate(ui, repo, rev, **opts):
1879 def debugrebuilddirstate(ui, repo, rev, **opts):
1880 """rebuild the dirstate as it would look like for the given revision
1880 """rebuild the dirstate as it would look like for the given revision
1881
1881
1882 If no revision is specified the first current parent will be used.
1882 If no revision is specified the first current parent will be used.
1883
1883
1884 The dirstate will be set to the files of the given revision.
1884 The dirstate will be set to the files of the given revision.
1885 The actual working directory content or existing dirstate
1885 The actual working directory content or existing dirstate
1886 information such as adds or removes is not considered.
1886 information such as adds or removes is not considered.
1887
1887
1888 ``minimal`` will only rebuild the dirstate status for files that claim to be
1888 ``minimal`` will only rebuild the dirstate status for files that claim to be
1889 tracked but are not in the parent manifest, or that exist in the parent
1889 tracked but are not in the parent manifest, or that exist in the parent
1890 manifest but are not in the dirstate. It will not change adds, removes, or
1890 manifest but are not in the dirstate. It will not change adds, removes, or
1891 modified files that are in the working copy parent.
1891 modified files that are in the working copy parent.
1892
1892
1893 One use of this command is to make the next :hg:`status` invocation
1893 One use of this command is to make the next :hg:`status` invocation
1894 check the actual file content.
1894 check the actual file content.
1895 """
1895 """
1896 ctx = scmutil.revsingle(repo, rev)
1896 ctx = scmutil.revsingle(repo, rev)
1897 with repo.wlock():
1897 with repo.wlock():
1898 dirstate = repo.dirstate
1898 dirstate = repo.dirstate
1899 changedfiles = None
1899 changedfiles = None
1900 # See command doc for what minimal does.
1900 # See command doc for what minimal does.
1901 if opts.get(r'minimal'):
1901 if opts.get(r'minimal'):
1902 manifestfiles = set(ctx.manifest().keys())
1902 manifestfiles = set(ctx.manifest().keys())
1903 dirstatefiles = set(dirstate)
1903 dirstatefiles = set(dirstate)
1904 manifestonly = manifestfiles - dirstatefiles
1904 manifestonly = manifestfiles - dirstatefiles
1905 dsonly = dirstatefiles - manifestfiles
1905 dsonly = dirstatefiles - manifestfiles
1906 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1906 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1907 changedfiles = manifestonly | dsnotadded
1907 changedfiles = manifestonly | dsnotadded
1908
1908
1909 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1909 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1910
1910
1911 @command('debugrebuildfncache', [], '')
1911 @command('debugrebuildfncache', [], '')
1912 def debugrebuildfncache(ui, repo):
1912 def debugrebuildfncache(ui, repo):
1913 """rebuild the fncache file"""
1913 """rebuild the fncache file"""
1914 repair.rebuildfncache(ui, repo)
1914 repair.rebuildfncache(ui, repo)
1915
1915
1916 @command('debugrename',
1916 @command('debugrename',
1917 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1917 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1918 _('[-r REV] FILE'))
1918 _('[-r REV] FILE'))
1919 def debugrename(ui, repo, file1, *pats, **opts):
1919 def debugrename(ui, repo, file1, *pats, **opts):
1920 """dump rename information"""
1920 """dump rename information"""
1921
1921
1922 opts = pycompat.byteskwargs(opts)
1922 opts = pycompat.byteskwargs(opts)
1923 ctx = scmutil.revsingle(repo, opts.get('rev'))
1923 ctx = scmutil.revsingle(repo, opts.get('rev'))
1924 m = scmutil.match(ctx, (file1,) + pats, opts)
1924 m = scmutil.match(ctx, (file1,) + pats, opts)
1925 for abs in ctx.walk(m):
1925 for abs in ctx.walk(m):
1926 fctx = ctx[abs]
1926 fctx = ctx[abs]
1927 o = fctx.filelog().renamed(fctx.filenode())
1927 o = fctx.filelog().renamed(fctx.filenode())
1928 rel = m.rel(abs)
1928 rel = m.rel(abs)
1929 if o:
1929 if o:
1930 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1930 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1931 else:
1931 else:
1932 ui.write(_("%s not renamed\n") % rel)
1932 ui.write(_("%s not renamed\n") % rel)
1933
1933
1934 @command('debugrevlog', cmdutil.debugrevlogopts +
1934 @command('debugrevlog', cmdutil.debugrevlogopts +
1935 [('d', 'dump', False, _('dump index data'))],
1935 [('d', 'dump', False, _('dump index data'))],
1936 _('-c|-m|FILE'),
1936 _('-c|-m|FILE'),
1937 optionalrepo=True)
1937 optionalrepo=True)
1938 def debugrevlog(ui, repo, file_=None, **opts):
1938 def debugrevlog(ui, repo, file_=None, **opts):
1939 """show data and statistics about a revlog"""
1939 """show data and statistics about a revlog"""
1940 opts = pycompat.byteskwargs(opts)
1940 opts = pycompat.byteskwargs(opts)
1941 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1941 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1942
1942
1943 if opts.get("dump"):
1943 if opts.get("dump"):
1944 numrevs = len(r)
1944 numrevs = len(r)
1945 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1945 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1946 " rawsize totalsize compression heads chainlen\n"))
1946 " rawsize totalsize compression heads chainlen\n"))
1947 ts = 0
1947 ts = 0
1948 heads = set()
1948 heads = set()
1949
1949
1950 for rev in xrange(numrevs):
1950 for rev in xrange(numrevs):
1951 dbase = r.deltaparent(rev)
1951 dbase = r.deltaparent(rev)
1952 if dbase == -1:
1952 if dbase == -1:
1953 dbase = rev
1953 dbase = rev
1954 cbase = r.chainbase(rev)
1954 cbase = r.chainbase(rev)
1955 clen = r.chainlen(rev)
1955 clen = r.chainlen(rev)
1956 p1, p2 = r.parentrevs(rev)
1956 p1, p2 = r.parentrevs(rev)
1957 rs = r.rawsize(rev)
1957 rs = r.rawsize(rev)
1958 ts = ts + rs
1958 ts = ts + rs
1959 heads -= set(r.parentrevs(rev))
1959 heads -= set(r.parentrevs(rev))
1960 heads.add(rev)
1960 heads.add(rev)
1961 try:
1961 try:
1962 compression = ts / r.end(rev)
1962 compression = ts / r.end(rev)
1963 except ZeroDivisionError:
1963 except ZeroDivisionError:
1964 compression = 0
1964 compression = 0
1965 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1965 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1966 "%11d %5d %8d\n" %
1966 "%11d %5d %8d\n" %
1967 (rev, p1, p2, r.start(rev), r.end(rev),
1967 (rev, p1, p2, r.start(rev), r.end(rev),
1968 r.start(dbase), r.start(cbase),
1968 r.start(dbase), r.start(cbase),
1969 r.start(p1), r.start(p2),
1969 r.start(p1), r.start(p2),
1970 rs, ts, compression, len(heads), clen))
1970 rs, ts, compression, len(heads), clen))
1971 return 0
1971 return 0
1972
1972
1973 v = r.version
1973 v = r.version
1974 format = v & 0xFFFF
1974 format = v & 0xFFFF
1975 flags = []
1975 flags = []
1976 gdelta = False
1976 gdelta = False
1977 if v & revlog.FLAG_INLINE_DATA:
1977 if v & revlog.FLAG_INLINE_DATA:
1978 flags.append('inline')
1978 flags.append('inline')
1979 if v & revlog.FLAG_GENERALDELTA:
1979 if v & revlog.FLAG_GENERALDELTA:
1980 gdelta = True
1980 gdelta = True
1981 flags.append('generaldelta')
1981 flags.append('generaldelta')
1982 if not flags:
1982 if not flags:
1983 flags = ['(none)']
1983 flags = ['(none)']
1984
1984
1985 nummerges = 0
1985 nummerges = 0
1986 numfull = 0
1986 numfull = 0
1987 numprev = 0
1987 numprev = 0
1988 nump1 = 0
1988 nump1 = 0
1989 nump2 = 0
1989 nump2 = 0
1990 numother = 0
1990 numother = 0
1991 nump1prev = 0
1991 nump1prev = 0
1992 nump2prev = 0
1992 nump2prev = 0
1993 chainlengths = []
1993 chainlengths = []
1994 chainbases = []
1994 chainbases = []
1995 chainspans = []
1995 chainspans = []
1996
1996
1997 datasize = [None, 0, 0]
1997 datasize = [None, 0, 0]
1998 fullsize = [None, 0, 0]
1998 fullsize = [None, 0, 0]
1999 deltasize = [None, 0, 0]
1999 deltasize = [None, 0, 0]
2000 chunktypecounts = {}
2000 chunktypecounts = {}
2001 chunktypesizes = {}
2001 chunktypesizes = {}
2002
2002
2003 def addsize(size, l):
2003 def addsize(size, l):
2004 if l[0] is None or size < l[0]:
2004 if l[0] is None or size < l[0]:
2005 l[0] = size
2005 l[0] = size
2006 if size > l[1]:
2006 if size > l[1]:
2007 l[1] = size
2007 l[1] = size
2008 l[2] += size
2008 l[2] += size
2009
2009
2010 numrevs = len(r)
2010 numrevs = len(r)
2011 for rev in xrange(numrevs):
2011 for rev in xrange(numrevs):
2012 p1, p2 = r.parentrevs(rev)
2012 p1, p2 = r.parentrevs(rev)
2013 delta = r.deltaparent(rev)
2013 delta = r.deltaparent(rev)
2014 if format > 0:
2014 if format > 0:
2015 addsize(r.rawsize(rev), datasize)
2015 addsize(r.rawsize(rev), datasize)
2016 if p2 != nullrev:
2016 if p2 != nullrev:
2017 nummerges += 1
2017 nummerges += 1
2018 size = r.length(rev)
2018 size = r.length(rev)
2019 if delta == nullrev:
2019 if delta == nullrev:
2020 chainlengths.append(0)
2020 chainlengths.append(0)
2021 chainbases.append(r.start(rev))
2021 chainbases.append(r.start(rev))
2022 chainspans.append(size)
2022 chainspans.append(size)
2023 numfull += 1
2023 numfull += 1
2024 addsize(size, fullsize)
2024 addsize(size, fullsize)
2025 else:
2025 else:
2026 chainlengths.append(chainlengths[delta] + 1)
2026 chainlengths.append(chainlengths[delta] + 1)
2027 baseaddr = chainbases[delta]
2027 baseaddr = chainbases[delta]
2028 revaddr = r.start(rev)
2028 revaddr = r.start(rev)
2029 chainbases.append(baseaddr)
2029 chainbases.append(baseaddr)
2030 chainspans.append((revaddr - baseaddr) + size)
2030 chainspans.append((revaddr - baseaddr) + size)
2031 addsize(size, deltasize)
2031 addsize(size, deltasize)
2032 if delta == rev - 1:
2032 if delta == rev - 1:
2033 numprev += 1
2033 numprev += 1
2034 if delta == p1:
2034 if delta == p1:
2035 nump1prev += 1
2035 nump1prev += 1
2036 elif delta == p2:
2036 elif delta == p2:
2037 nump2prev += 1
2037 nump2prev += 1
2038 elif delta == p1:
2038 elif delta == p1:
2039 nump1 += 1
2039 nump1 += 1
2040 elif delta == p2:
2040 elif delta == p2:
2041 nump2 += 1
2041 nump2 += 1
2042 elif delta != nullrev:
2042 elif delta != nullrev:
2043 numother += 1
2043 numother += 1
2044
2044
2045 # Obtain data on the raw chunks in the revlog.
2045 # Obtain data on the raw chunks in the revlog.
2046 segment = r._getsegmentforrevs(rev, rev)[1]
2046 segment = r._getsegmentforrevs(rev, rev)[1]
2047 if segment:
2047 if segment:
2048 chunktype = bytes(segment[0:1])
2048 chunktype = bytes(segment[0:1])
2049 else:
2049 else:
2050 chunktype = 'empty'
2050 chunktype = 'empty'
2051
2051
2052 if chunktype not in chunktypecounts:
2052 if chunktype not in chunktypecounts:
2053 chunktypecounts[chunktype] = 0
2053 chunktypecounts[chunktype] = 0
2054 chunktypesizes[chunktype] = 0
2054 chunktypesizes[chunktype] = 0
2055
2055
2056 chunktypecounts[chunktype] += 1
2056 chunktypecounts[chunktype] += 1
2057 chunktypesizes[chunktype] += size
2057 chunktypesizes[chunktype] += size
2058
2058
2059 # Adjust size min value for empty cases
2059 # Adjust size min value for empty cases
2060 for size in (datasize, fullsize, deltasize):
2060 for size in (datasize, fullsize, deltasize):
2061 if size[0] is None:
2061 if size[0] is None:
2062 size[0] = 0
2062 size[0] = 0
2063
2063
2064 numdeltas = numrevs - numfull
2064 numdeltas = numrevs - numfull
2065 numoprev = numprev - nump1prev - nump2prev
2065 numoprev = numprev - nump1prev - nump2prev
2066 totalrawsize = datasize[2]
2066 totalrawsize = datasize[2]
2067 datasize[2] /= numrevs
2067 datasize[2] /= numrevs
2068 fulltotal = fullsize[2]
2068 fulltotal = fullsize[2]
2069 fullsize[2] /= numfull
2069 fullsize[2] /= numfull
2070 deltatotal = deltasize[2]
2070 deltatotal = deltasize[2]
2071 if numrevs - numfull > 0:
2071 if numrevs - numfull > 0:
2072 deltasize[2] /= numrevs - numfull
2072 deltasize[2] /= numrevs - numfull
2073 totalsize = fulltotal + deltatotal
2073 totalsize = fulltotal + deltatotal
2074 avgchainlen = sum(chainlengths) / numrevs
2074 avgchainlen = sum(chainlengths) / numrevs
2075 maxchainlen = max(chainlengths)
2075 maxchainlen = max(chainlengths)
2076 maxchainspan = max(chainspans)
2076 maxchainspan = max(chainspans)
2077 compratio = 1
2077 compratio = 1
2078 if totalsize:
2078 if totalsize:
2079 compratio = totalrawsize / totalsize
2079 compratio = totalrawsize / totalsize
2080
2080
2081 basedfmtstr = '%%%dd\n'
2081 basedfmtstr = '%%%dd\n'
2082 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2082 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2083
2083
2084 def dfmtstr(max):
2084 def dfmtstr(max):
2085 return basedfmtstr % len(str(max))
2085 return basedfmtstr % len(str(max))
2086 def pcfmtstr(max, padding=0):
2086 def pcfmtstr(max, padding=0):
2087 return basepcfmtstr % (len(str(max)), ' ' * padding)
2087 return basepcfmtstr % (len(str(max)), ' ' * padding)
2088
2088
2089 def pcfmt(value, total):
2089 def pcfmt(value, total):
2090 if total:
2090 if total:
2091 return (value, 100 * float(value) / total)
2091 return (value, 100 * float(value) / total)
2092 else:
2092 else:
2093 return value, 100.0
2093 return value, 100.0
2094
2094
2095 ui.write(('format : %d\n') % format)
2095 ui.write(('format : %d\n') % format)
2096 ui.write(('flags : %s\n') % ', '.join(flags))
2096 ui.write(('flags : %s\n') % ', '.join(flags))
2097
2097
2098 ui.write('\n')
2098 ui.write('\n')
2099 fmt = pcfmtstr(totalsize)
2099 fmt = pcfmtstr(totalsize)
2100 fmt2 = dfmtstr(totalsize)
2100 fmt2 = dfmtstr(totalsize)
2101 ui.write(('revisions : ') + fmt2 % numrevs)
2101 ui.write(('revisions : ') + fmt2 % numrevs)
2102 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2102 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2103 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2103 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2104 ui.write(('revisions : ') + fmt2 % numrevs)
2104 ui.write(('revisions : ') + fmt2 % numrevs)
2105 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2105 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2106 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2106 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2107 ui.write(('revision size : ') + fmt2 % totalsize)
2107 ui.write(('revision size : ') + fmt2 % totalsize)
2108 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2108 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2109 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2109 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2110
2110
2111 def fmtchunktype(chunktype):
2111 def fmtchunktype(chunktype):
2112 if chunktype == 'empty':
2112 if chunktype == 'empty':
2113 return ' %s : ' % chunktype
2113 return ' %s : ' % chunktype
2114 elif chunktype in pycompat.bytestr(string.ascii_letters):
2114 elif chunktype in pycompat.bytestr(string.ascii_letters):
2115 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2115 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2116 else:
2116 else:
2117 return ' 0x%s : ' % hex(chunktype)
2117 return ' 0x%s : ' % hex(chunktype)
2118
2118
2119 ui.write('\n')
2119 ui.write('\n')
2120 ui.write(('chunks : ') + fmt2 % numrevs)
2120 ui.write(('chunks : ') + fmt2 % numrevs)
2121 for chunktype in sorted(chunktypecounts):
2121 for chunktype in sorted(chunktypecounts):
2122 ui.write(fmtchunktype(chunktype))
2122 ui.write(fmtchunktype(chunktype))
2123 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2123 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2124 ui.write(('chunks size : ') + fmt2 % totalsize)
2124 ui.write(('chunks size : ') + fmt2 % totalsize)
2125 for chunktype in sorted(chunktypecounts):
2125 for chunktype in sorted(chunktypecounts):
2126 ui.write(fmtchunktype(chunktype))
2126 ui.write(fmtchunktype(chunktype))
2127 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2127 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2128
2128
2129 ui.write('\n')
2129 ui.write('\n')
2130 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
2130 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
2131 ui.write(('avg chain length : ') + fmt % avgchainlen)
2131 ui.write(('avg chain length : ') + fmt % avgchainlen)
2132 ui.write(('max chain length : ') + fmt % maxchainlen)
2132 ui.write(('max chain length : ') + fmt % maxchainlen)
2133 ui.write(('max chain reach : ') + fmt % maxchainspan)
2133 ui.write(('max chain reach : ') + fmt % maxchainspan)
2134 ui.write(('compression ratio : ') + fmt % compratio)
2134 ui.write(('compression ratio : ') + fmt % compratio)
2135
2135
2136 if format > 0:
2136 if format > 0:
2137 ui.write('\n')
2137 ui.write('\n')
2138 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2138 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2139 % tuple(datasize))
2139 % tuple(datasize))
2140 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2140 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2141 % tuple(fullsize))
2141 % tuple(fullsize))
2142 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2142 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2143 % tuple(deltasize))
2143 % tuple(deltasize))
2144
2144
2145 if numdeltas > 0:
2145 if numdeltas > 0:
2146 ui.write('\n')
2146 ui.write('\n')
2147 fmt = pcfmtstr(numdeltas)
2147 fmt = pcfmtstr(numdeltas)
2148 fmt2 = pcfmtstr(numdeltas, 4)
2148 fmt2 = pcfmtstr(numdeltas, 4)
2149 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2149 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2150 if numprev > 0:
2150 if numprev > 0:
2151 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2151 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2152 numprev))
2152 numprev))
2153 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2153 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2154 numprev))
2154 numprev))
2155 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2155 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2156 numprev))
2156 numprev))
2157 if gdelta:
2157 if gdelta:
2158 ui.write(('deltas against p1 : ')
2158 ui.write(('deltas against p1 : ')
2159 + fmt % pcfmt(nump1, numdeltas))
2159 + fmt % pcfmt(nump1, numdeltas))
2160 ui.write(('deltas against p2 : ')
2160 ui.write(('deltas against p2 : ')
2161 + fmt % pcfmt(nump2, numdeltas))
2161 + fmt % pcfmt(nump2, numdeltas))
2162 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2162 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2163 numdeltas))
2163 numdeltas))
2164
2164
2165 @command('debugrevspec',
2165 @command('debugrevspec',
2166 [('', 'optimize', None,
2166 [('', 'optimize', None,
2167 _('print parsed tree after optimizing (DEPRECATED)')),
2167 _('print parsed tree after optimizing (DEPRECATED)')),
2168 ('', 'show-revs', True, _('print list of result revisions (default)')),
2168 ('', 'show-revs', True, _('print list of result revisions (default)')),
2169 ('s', 'show-set', None, _('print internal representation of result set')),
2169 ('s', 'show-set', None, _('print internal representation of result set')),
2170 ('p', 'show-stage', [],
2170 ('p', 'show-stage', [],
2171 _('print parsed tree at the given stage'), _('NAME')),
2171 _('print parsed tree at the given stage'), _('NAME')),
2172 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2172 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2173 ('', 'verify-optimized', False, _('verify optimized result')),
2173 ('', 'verify-optimized', False, _('verify optimized result')),
2174 ],
2174 ],
2175 ('REVSPEC'))
2175 ('REVSPEC'))
2176 def debugrevspec(ui, repo, expr, **opts):
2176 def debugrevspec(ui, repo, expr, **opts):
2177 """parse and apply a revision specification
2177 """parse and apply a revision specification
2178
2178
2179 Use -p/--show-stage option to print the parsed tree at the given stages.
2179 Use -p/--show-stage option to print the parsed tree at the given stages.
2180 Use -p all to print tree at every stage.
2180 Use -p all to print tree at every stage.
2181
2181
2182 Use --no-show-revs option with -s or -p to print only the set
2182 Use --no-show-revs option with -s or -p to print only the set
2183 representation or the parsed tree respectively.
2183 representation or the parsed tree respectively.
2184
2184
2185 Use --verify-optimized to compare the optimized result with the unoptimized
2185 Use --verify-optimized to compare the optimized result with the unoptimized
2186 one. Returns 1 if the optimized result differs.
2186 one. Returns 1 if the optimized result differs.
2187 """
2187 """
2188 opts = pycompat.byteskwargs(opts)
2188 opts = pycompat.byteskwargs(opts)
2189 aliases = ui.configitems('revsetalias')
2189 aliases = ui.configitems('revsetalias')
2190 stages = [
2190 stages = [
2191 ('parsed', lambda tree: tree),
2191 ('parsed', lambda tree: tree),
2192 ('expanded', lambda tree: revsetlang.expandaliases(tree, aliases,
2192 ('expanded', lambda tree: revsetlang.expandaliases(tree, aliases,
2193 ui.warn)),
2193 ui.warn)),
2194 ('concatenated', revsetlang.foldconcat),
2194 ('concatenated', revsetlang.foldconcat),
2195 ('analyzed', revsetlang.analyze),
2195 ('analyzed', revsetlang.analyze),
2196 ('optimized', revsetlang.optimize),
2196 ('optimized', revsetlang.optimize),
2197 ]
2197 ]
2198 if opts['no_optimized']:
2198 if opts['no_optimized']:
2199 stages = stages[:-1]
2199 stages = stages[:-1]
2200 if opts['verify_optimized'] and opts['no_optimized']:
2200 if opts['verify_optimized'] and opts['no_optimized']:
2201 raise error.Abort(_('cannot use --verify-optimized with '
2201 raise error.Abort(_('cannot use --verify-optimized with '
2202 '--no-optimized'))
2202 '--no-optimized'))
2203 stagenames = set(n for n, f in stages)
2203 stagenames = set(n for n, f in stages)
2204
2204
2205 showalways = set()
2205 showalways = set()
2206 showchanged = set()
2206 showchanged = set()
2207 if ui.verbose and not opts['show_stage']:
2207 if ui.verbose and not opts['show_stage']:
2208 # show parsed tree by --verbose (deprecated)
2208 # show parsed tree by --verbose (deprecated)
2209 showalways.add('parsed')
2209 showalways.add('parsed')
2210 showchanged.update(['expanded', 'concatenated'])
2210 showchanged.update(['expanded', 'concatenated'])
2211 if opts['optimize']:
2211 if opts['optimize']:
2212 showalways.add('optimized')
2212 showalways.add('optimized')
2213 if opts['show_stage'] and opts['optimize']:
2213 if opts['show_stage'] and opts['optimize']:
2214 raise error.Abort(_('cannot use --optimize with --show-stage'))
2214 raise error.Abort(_('cannot use --optimize with --show-stage'))
2215 if opts['show_stage'] == ['all']:
2215 if opts['show_stage'] == ['all']:
2216 showalways.update(stagenames)
2216 showalways.update(stagenames)
2217 else:
2217 else:
2218 for n in opts['show_stage']:
2218 for n in opts['show_stage']:
2219 if n not in stagenames:
2219 if n not in stagenames:
2220 raise error.Abort(_('invalid stage name: %s') % n)
2220 raise error.Abort(_('invalid stage name: %s') % n)
2221 showalways.update(opts['show_stage'])
2221 showalways.update(opts['show_stage'])
2222
2222
2223 treebystage = {}
2223 treebystage = {}
2224 printedtree = None
2224 printedtree = None
2225 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
2225 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
2226 for n, f in stages:
2226 for n, f in stages:
2227 treebystage[n] = tree = f(tree)
2227 treebystage[n] = tree = f(tree)
2228 if n in showalways or (n in showchanged and tree != printedtree):
2228 if n in showalways or (n in showchanged and tree != printedtree):
2229 if opts['show_stage'] or n != 'parsed':
2229 if opts['show_stage'] or n != 'parsed':
2230 ui.write(("* %s:\n") % n)
2230 ui.write(("* %s:\n") % n)
2231 ui.write(revsetlang.prettyformat(tree), "\n")
2231 ui.write(revsetlang.prettyformat(tree), "\n")
2232 printedtree = tree
2232 printedtree = tree
2233
2233
2234 if opts['verify_optimized']:
2234 if opts['verify_optimized']:
2235 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2235 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2236 brevs = revset.makematcher(treebystage['optimized'])(repo)
2236 brevs = revset.makematcher(treebystage['optimized'])(repo)
2237 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2237 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2238 ui.write(("* analyzed set:\n"), stringutil.prettyrepr(arevs), "\n")
2238 ui.write(("* analyzed set:\n"), stringutil.prettyrepr(arevs), "\n")
2239 ui.write(("* optimized set:\n"), stringutil.prettyrepr(brevs), "\n")
2239 ui.write(("* optimized set:\n"), stringutil.prettyrepr(brevs), "\n")
2240 arevs = list(arevs)
2240 arevs = list(arevs)
2241 brevs = list(brevs)
2241 brevs = list(brevs)
2242 if arevs == brevs:
2242 if arevs == brevs:
2243 return 0
2243 return 0
2244 ui.write(('--- analyzed\n'), label='diff.file_a')
2244 ui.write(('--- analyzed\n'), label='diff.file_a')
2245 ui.write(('+++ optimized\n'), label='diff.file_b')
2245 ui.write(('+++ optimized\n'), label='diff.file_b')
2246 sm = difflib.SequenceMatcher(None, arevs, brevs)
2246 sm = difflib.SequenceMatcher(None, arevs, brevs)
2247 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2247 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2248 if tag in ('delete', 'replace'):
2248 if tag in ('delete', 'replace'):
2249 for c in arevs[alo:ahi]:
2249 for c in arevs[alo:ahi]:
2250 ui.write('-%s\n' % c, label='diff.deleted')
2250 ui.write('-%s\n' % c, label='diff.deleted')
2251 if tag in ('insert', 'replace'):
2251 if tag in ('insert', 'replace'):
2252 for c in brevs[blo:bhi]:
2252 for c in brevs[blo:bhi]:
2253 ui.write('+%s\n' % c, label='diff.inserted')
2253 ui.write('+%s\n' % c, label='diff.inserted')
2254 if tag == 'equal':
2254 if tag == 'equal':
2255 for c in arevs[alo:ahi]:
2255 for c in arevs[alo:ahi]:
2256 ui.write(' %s\n' % c)
2256 ui.write(' %s\n' % c)
2257 return 1
2257 return 1
2258
2258
2259 func = revset.makematcher(tree)
2259 func = revset.makematcher(tree)
2260 revs = func(repo)
2260 revs = func(repo)
2261 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2261 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2262 ui.write(("* set:\n"), stringutil.prettyrepr(revs), "\n")
2262 ui.write(("* set:\n"), stringutil.prettyrepr(revs), "\n")
2263 if not opts['show_revs']:
2263 if not opts['show_revs']:
2264 return
2264 return
2265 for c in revs:
2265 for c in revs:
2266 ui.write("%d\n" % c)
2266 ui.write("%d\n" % c)
2267
2267
2268 @command('debugserve', [
2268 @command('debugserve', [
2269 ('', 'sshstdio', False, _('run an SSH server bound to process handles')),
2269 ('', 'sshstdio', False, _('run an SSH server bound to process handles')),
2270 ('', 'logiofd', '', _('file descriptor to log server I/O to')),
2270 ('', 'logiofd', '', _('file descriptor to log server I/O to')),
2271 ('', 'logiofile', '', _('file to log server I/O to')),
2271 ('', 'logiofile', '', _('file to log server I/O to')),
2272 ], '')
2272 ], '')
2273 def debugserve(ui, repo, **opts):
2273 def debugserve(ui, repo, **opts):
2274 """run a server with advanced settings
2274 """run a server with advanced settings
2275
2275
2276 This command is similar to :hg:`serve`. It exists partially as a
2276 This command is similar to :hg:`serve`. It exists partially as a
2277 workaround to the fact that ``hg serve --stdio`` must have specific
2277 workaround to the fact that ``hg serve --stdio`` must have specific
2278 arguments for security reasons.
2278 arguments for security reasons.
2279 """
2279 """
2280 opts = pycompat.byteskwargs(opts)
2280 opts = pycompat.byteskwargs(opts)
2281
2281
2282 if not opts['sshstdio']:
2282 if not opts['sshstdio']:
2283 raise error.Abort(_('only --sshstdio is currently supported'))
2283 raise error.Abort(_('only --sshstdio is currently supported'))
2284
2284
2285 logfh = None
2285 logfh = None
2286
2286
2287 if opts['logiofd'] and opts['logiofile']:
2287 if opts['logiofd'] and opts['logiofile']:
2288 raise error.Abort(_('cannot use both --logiofd and --logiofile'))
2288 raise error.Abort(_('cannot use both --logiofd and --logiofile'))
2289
2289
2290 if opts['logiofd']:
2290 if opts['logiofd']:
2291 # Line buffered because output is line based.
2291 # Line buffered because output is line based.
2292 logfh = os.fdopen(int(opts['logiofd']), r'ab', 1)
2292 logfh = os.fdopen(int(opts['logiofd']), r'ab', 1)
2293 elif opts['logiofile']:
2293 elif opts['logiofile']:
2294 logfh = open(opts['logiofile'], 'ab', 1)
2294 logfh = open(opts['logiofile'], 'ab', 1)
2295
2295
2296 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
2296 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
2297 s.serve_forever()
2297 s.serve_forever()
2298
2298
2299 @command('debugsetparents', [], _('REV1 [REV2]'))
2299 @command('debugsetparents', [], _('REV1 [REV2]'))
2300 def debugsetparents(ui, repo, rev1, rev2=None):
2300 def debugsetparents(ui, repo, rev1, rev2=None):
2301 """manually set the parents of the current working directory
2301 """manually set the parents of the current working directory
2302
2302
2303 This is useful for writing repository conversion tools, but should
2303 This is useful for writing repository conversion tools, but should
2304 be used with care. For example, neither the working directory nor the
2304 be used with care. For example, neither the working directory nor the
2305 dirstate is updated, so file status may be incorrect after running this
2305 dirstate is updated, so file status may be incorrect after running this
2306 command.
2306 command.
2307
2307
2308 Returns 0 on success.
2308 Returns 0 on success.
2309 """
2309 """
2310
2310
2311 node1 = scmutil.revsingle(repo, rev1).node()
2311 node1 = scmutil.revsingle(repo, rev1).node()
2312 node2 = scmutil.revsingle(repo, rev2, 'null').node()
2312 node2 = scmutil.revsingle(repo, rev2, 'null').node()
2313
2313
2314 with repo.wlock():
2314 with repo.wlock():
2315 repo.setparents(node1, node2)
2315 repo.setparents(node1, node2)
2316
2316
2317 @command('debugssl', [], '[SOURCE]', optionalrepo=True)
2317 @command('debugssl', [], '[SOURCE]', optionalrepo=True)
2318 def debugssl(ui, repo, source=None, **opts):
2318 def debugssl(ui, repo, source=None, **opts):
2319 '''test a secure connection to a server
2319 '''test a secure connection to a server
2320
2320
2321 This builds the certificate chain for the server on Windows, installing the
2321 This builds the certificate chain for the server on Windows, installing the
2322 missing intermediates and trusted root via Windows Update if necessary. It
2322 missing intermediates and trusted root via Windows Update if necessary. It
2323 does nothing on other platforms.
2323 does nothing on other platforms.
2324
2324
2325 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
2325 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
2326 that server is used. See :hg:`help urls` for more information.
2326 that server is used. See :hg:`help urls` for more information.
2327
2327
2328 If the update succeeds, retry the original operation. Otherwise, the cause
2328 If the update succeeds, retry the original operation. Otherwise, the cause
2329 of the SSL error is likely another issue.
2329 of the SSL error is likely another issue.
2330 '''
2330 '''
2331 if not pycompat.iswindows:
2331 if not pycompat.iswindows:
2332 raise error.Abort(_('certificate chain building is only possible on '
2332 raise error.Abort(_('certificate chain building is only possible on '
2333 'Windows'))
2333 'Windows'))
2334
2334
2335 if not source:
2335 if not source:
2336 if not repo:
2336 if not repo:
2337 raise error.Abort(_("there is no Mercurial repository here, and no "
2337 raise error.Abort(_("there is no Mercurial repository here, and no "
2338 "server specified"))
2338 "server specified"))
2339 source = "default"
2339 source = "default"
2340
2340
2341 source, branches = hg.parseurl(ui.expandpath(source))
2341 source, branches = hg.parseurl(ui.expandpath(source))
2342 url = util.url(source)
2342 url = util.url(source)
2343 addr = None
2343 addr = None
2344
2344
2345 defaultport = {'https': 443, 'ssh': 22}
2345 defaultport = {'https': 443, 'ssh': 22}
2346 if url.scheme in defaultport:
2346 if url.scheme in defaultport:
2347 try:
2347 try:
2348 addr = (url.host, int(url.port or defaultport[url.scheme]))
2348 addr = (url.host, int(url.port or defaultport[url.scheme]))
2349 except ValueError:
2349 except ValueError:
2350 raise error.Abort(_("malformed port number in URL"))
2350 raise error.Abort(_("malformed port number in URL"))
2351 else:
2351 else:
2352 raise error.Abort(_("only https and ssh connections are supported"))
2352 raise error.Abort(_("only https and ssh connections are supported"))
2353
2353
2354 from . import win32
2354 from . import win32
2355
2355
2356 s = ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_TLS,
2356 s = ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_TLS,
2357 cert_reqs=ssl.CERT_NONE, ca_certs=None)
2357 cert_reqs=ssl.CERT_NONE, ca_certs=None)
2358
2358
2359 try:
2359 try:
2360 s.connect(addr)
2360 s.connect(addr)
2361 cert = s.getpeercert(True)
2361 cert = s.getpeercert(True)
2362
2362
2363 ui.status(_('checking the certificate chain for %s\n') % url.host)
2363 ui.status(_('checking the certificate chain for %s\n') % url.host)
2364
2364
2365 complete = win32.checkcertificatechain(cert, build=False)
2365 complete = win32.checkcertificatechain(cert, build=False)
2366
2366
2367 if not complete:
2367 if not complete:
2368 ui.status(_('certificate chain is incomplete, updating... '))
2368 ui.status(_('certificate chain is incomplete, updating... '))
2369
2369
2370 if not win32.checkcertificatechain(cert):
2370 if not win32.checkcertificatechain(cert):
2371 ui.status(_('failed.\n'))
2371 ui.status(_('failed.\n'))
2372 else:
2372 else:
2373 ui.status(_('done.\n'))
2373 ui.status(_('done.\n'))
2374 else:
2374 else:
2375 ui.status(_('full certificate chain is available\n'))
2375 ui.status(_('full certificate chain is available\n'))
2376 finally:
2376 finally:
2377 s.close()
2377 s.close()
2378
2378
2379 @command('debugsub',
2379 @command('debugsub',
2380 [('r', 'rev', '',
2380 [('r', 'rev', '',
2381 _('revision to check'), _('REV'))],
2381 _('revision to check'), _('REV'))],
2382 _('[-r REV] [REV]'))
2382 _('[-r REV] [REV]'))
2383 def debugsub(ui, repo, rev=None):
2383 def debugsub(ui, repo, rev=None):
2384 ctx = scmutil.revsingle(repo, rev, None)
2384 ctx = scmutil.revsingle(repo, rev, None)
2385 for k, v in sorted(ctx.substate.items()):
2385 for k, v in sorted(ctx.substate.items()):
2386 ui.write(('path %s\n') % k)
2386 ui.write(('path %s\n') % k)
2387 ui.write((' source %s\n') % v[0])
2387 ui.write((' source %s\n') % v[0])
2388 ui.write((' revision %s\n') % v[1])
2388 ui.write((' revision %s\n') % v[1])
2389
2389
2390 @command('debugsuccessorssets',
2390 @command('debugsuccessorssets',
2391 [('', 'closest', False, _('return closest successors sets only'))],
2391 [('', 'closest', False, _('return closest successors sets only'))],
2392 _('[REV]'))
2392 _('[REV]'))
2393 def debugsuccessorssets(ui, repo, *revs, **opts):
2393 def debugsuccessorssets(ui, repo, *revs, **opts):
2394 """show set of successors for revision
2394 """show set of successors for revision
2395
2395
2396 A successors set of changeset A is a consistent group of revisions that
2396 A successors set of changeset A is a consistent group of revisions that
2397 succeed A. It contains non-obsolete changesets only unless closests
2397 succeed A. It contains non-obsolete changesets only unless closests
2398 successors set is set.
2398 successors set is set.
2399
2399
2400 In most cases a changeset A has a single successors set containing a single
2400 In most cases a changeset A has a single successors set containing a single
2401 successor (changeset A replaced by A').
2401 successor (changeset A replaced by A').
2402
2402
2403 A changeset that is made obsolete with no successors are called "pruned".
2403 A changeset that is made obsolete with no successors are called "pruned".
2404 Such changesets have no successors sets at all.
2404 Such changesets have no successors sets at all.
2405
2405
2406 A changeset that has been "split" will have a successors set containing
2406 A changeset that has been "split" will have a successors set containing
2407 more than one successor.
2407 more than one successor.
2408
2408
2409 A changeset that has been rewritten in multiple different ways is called
2409 A changeset that has been rewritten in multiple different ways is called
2410 "divergent". Such changesets have multiple successor sets (each of which
2410 "divergent". Such changesets have multiple successor sets (each of which
2411 may also be split, i.e. have multiple successors).
2411 may also be split, i.e. have multiple successors).
2412
2412
2413 Results are displayed as follows::
2413 Results are displayed as follows::
2414
2414
2415 <rev1>
2415 <rev1>
2416 <successors-1A>
2416 <successors-1A>
2417 <rev2>
2417 <rev2>
2418 <successors-2A>
2418 <successors-2A>
2419 <successors-2B1> <successors-2B2> <successors-2B3>
2419 <successors-2B1> <successors-2B2> <successors-2B3>
2420
2420
2421 Here rev2 has two possible (i.e. divergent) successors sets. The first
2421 Here rev2 has two possible (i.e. divergent) successors sets. The first
2422 holds one element, whereas the second holds three (i.e. the changeset has
2422 holds one element, whereas the second holds three (i.e. the changeset has
2423 been split).
2423 been split).
2424 """
2424 """
2425 # passed to successorssets caching computation from one call to another
2425 # passed to successorssets caching computation from one call to another
2426 cache = {}
2426 cache = {}
2427 ctx2str = bytes
2427 ctx2str = bytes
2428 node2str = short
2428 node2str = short
2429 for rev in scmutil.revrange(repo, revs):
2429 for rev in scmutil.revrange(repo, revs):
2430 ctx = repo[rev]
2430 ctx = repo[rev]
2431 ui.write('%s\n'% ctx2str(ctx))
2431 ui.write('%s\n'% ctx2str(ctx))
2432 for succsset in obsutil.successorssets(repo, ctx.node(),
2432 for succsset in obsutil.successorssets(repo, ctx.node(),
2433 closest=opts[r'closest'],
2433 closest=opts[r'closest'],
2434 cache=cache):
2434 cache=cache):
2435 if succsset:
2435 if succsset:
2436 ui.write(' ')
2436 ui.write(' ')
2437 ui.write(node2str(succsset[0]))
2437 ui.write(node2str(succsset[0]))
2438 for node in succsset[1:]:
2438 for node in succsset[1:]:
2439 ui.write(' ')
2439 ui.write(' ')
2440 ui.write(node2str(node))
2440 ui.write(node2str(node))
2441 ui.write('\n')
2441 ui.write('\n')
2442
2442
2443 @command('debugtemplate',
2443 @command('debugtemplate',
2444 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2444 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2445 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2445 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2446 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2446 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2447 optionalrepo=True)
2447 optionalrepo=True)
2448 def debugtemplate(ui, repo, tmpl, **opts):
2448 def debugtemplate(ui, repo, tmpl, **opts):
2449 """parse and apply a template
2449 """parse and apply a template
2450
2450
2451 If -r/--rev is given, the template is processed as a log template and
2451 If -r/--rev is given, the template is processed as a log template and
2452 applied to the given changesets. Otherwise, it is processed as a generic
2452 applied to the given changesets. Otherwise, it is processed as a generic
2453 template.
2453 template.
2454
2454
2455 Use --verbose to print the parsed tree.
2455 Use --verbose to print the parsed tree.
2456 """
2456 """
2457 revs = None
2457 revs = None
2458 if opts[r'rev']:
2458 if opts[r'rev']:
2459 if repo is None:
2459 if repo is None:
2460 raise error.RepoError(_('there is no Mercurial repository here '
2460 raise error.RepoError(_('there is no Mercurial repository here '
2461 '(.hg not found)'))
2461 '(.hg not found)'))
2462 revs = scmutil.revrange(repo, opts[r'rev'])
2462 revs = scmutil.revrange(repo, opts[r'rev'])
2463
2463
2464 props = {}
2464 props = {}
2465 for d in opts[r'define']:
2465 for d in opts[r'define']:
2466 try:
2466 try:
2467 k, v = (e.strip() for e in d.split('=', 1))
2467 k, v = (e.strip() for e in d.split('=', 1))
2468 if not k or k == 'ui':
2468 if not k or k == 'ui':
2469 raise ValueError
2469 raise ValueError
2470 props[k] = v
2470 props[k] = v
2471 except ValueError:
2471 except ValueError:
2472 raise error.Abort(_('malformed keyword definition: %s') % d)
2472 raise error.Abort(_('malformed keyword definition: %s') % d)
2473
2473
2474 if ui.verbose:
2474 if ui.verbose:
2475 aliases = ui.configitems('templatealias')
2475 aliases = ui.configitems('templatealias')
2476 tree = templater.parse(tmpl)
2476 tree = templater.parse(tmpl)
2477 ui.note(templater.prettyformat(tree), '\n')
2477 ui.note(templater.prettyformat(tree), '\n')
2478 newtree = templater.expandaliases(tree, aliases)
2478 newtree = templater.expandaliases(tree, aliases)
2479 if newtree != tree:
2479 if newtree != tree:
2480 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2480 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2481
2481
2482 if revs is None:
2482 if revs is None:
2483 tres = formatter.templateresources(ui, repo)
2483 tres = formatter.templateresources(ui, repo)
2484 t = formatter.maketemplater(ui, tmpl, resources=tres)
2484 t = formatter.maketemplater(ui, tmpl, resources=tres)
2485 ui.write(t.renderdefault(props))
2485 ui.write(t.renderdefault(props))
2486 else:
2486 else:
2487 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
2487 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
2488 for r in revs:
2488 for r in revs:
2489 displayer.show(repo[r], **pycompat.strkwargs(props))
2489 displayer.show(repo[r], **pycompat.strkwargs(props))
2490 displayer.close()
2490 displayer.close()
2491
2491
2492 @command('debuguigetpass', [
2492 @command('debuguigetpass', [
2493 ('p', 'prompt', '', _('prompt text'), _('TEXT')),
2493 ('p', 'prompt', '', _('prompt text'), _('TEXT')),
2494 ], _('[-p TEXT]'), norepo=True)
2494 ], _('[-p TEXT]'), norepo=True)
2495 def debuguigetpass(ui, prompt=''):
2495 def debuguigetpass(ui, prompt=''):
2496 """show prompt to type password"""
2496 """show prompt to type password"""
2497 r = ui.getpass(prompt)
2497 r = ui.getpass(prompt)
2498 ui.write(('respose: %s\n') % r)
2498 ui.write(('respose: %s\n') % r)
2499
2499
2500 @command('debuguiprompt', [
2500 @command('debuguiprompt', [
2501 ('p', 'prompt', '', _('prompt text'), _('TEXT')),
2501 ('p', 'prompt', '', _('prompt text'), _('TEXT')),
2502 ], _('[-p TEXT]'), norepo=True)
2502 ], _('[-p TEXT]'), norepo=True)
2503 def debuguiprompt(ui, prompt=''):
2503 def debuguiprompt(ui, prompt=''):
2504 """show plain prompt"""
2504 """show plain prompt"""
2505 r = ui.prompt(prompt)
2505 r = ui.prompt(prompt)
2506 ui.write(('response: %s\n') % r)
2506 ui.write(('response: %s\n') % r)
2507
2507
2508 @command('debugupdatecaches', [])
2508 @command('debugupdatecaches', [])
2509 def debugupdatecaches(ui, repo, *pats, **opts):
2509 def debugupdatecaches(ui, repo, *pats, **opts):
2510 """warm all known caches in the repository"""
2510 """warm all known caches in the repository"""
2511 with repo.wlock(), repo.lock():
2511 with repo.wlock(), repo.lock():
2512 repo.updatecaches(full=True)
2512 repo.updatecaches(full=True)
2513
2513
2514 @command('debugupgraderepo', [
2514 @command('debugupgraderepo', [
2515 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
2515 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
2516 ('', 'run', False, _('performs an upgrade')),
2516 ('', 'run', False, _('performs an upgrade')),
2517 ])
2517 ])
2518 def debugupgraderepo(ui, repo, run=False, optimize=None):
2518 def debugupgraderepo(ui, repo, run=False, optimize=None):
2519 """upgrade a repository to use different features
2519 """upgrade a repository to use different features
2520
2520
2521 If no arguments are specified, the repository is evaluated for upgrade
2521 If no arguments are specified, the repository is evaluated for upgrade
2522 and a list of problems and potential optimizations is printed.
2522 and a list of problems and potential optimizations is printed.
2523
2523
2524 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
2524 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
2525 can be influenced via additional arguments. More details will be provided
2525 can be influenced via additional arguments. More details will be provided
2526 by the command output when run without ``--run``.
2526 by the command output when run without ``--run``.
2527
2527
2528 During the upgrade, the repository will be locked and no writes will be
2528 During the upgrade, the repository will be locked and no writes will be
2529 allowed.
2529 allowed.
2530
2530
2531 At the end of the upgrade, the repository may not be readable while new
2531 At the end of the upgrade, the repository may not be readable while new
2532 repository data is swapped in. This window will be as long as it takes to
2532 repository data is swapped in. This window will be as long as it takes to
2533 rename some directories inside the ``.hg`` directory. On most machines, this
2533 rename some directories inside the ``.hg`` directory. On most machines, this
2534 should complete almost instantaneously and the chances of a consumer being
2534 should complete almost instantaneously and the chances of a consumer being
2535 unable to access the repository should be low.
2535 unable to access the repository should be low.
2536 """
2536 """
2537 return upgrade.upgraderepo(ui, repo, run=run, optimize=optimize)
2537 return upgrade.upgraderepo(ui, repo, run=run, optimize=optimize)
2538
2538
2539 @command('debugwalk', cmdutil.walkopts, _('[OPTION]... [FILE]...'),
2539 @command('debugwalk', cmdutil.walkopts, _('[OPTION]... [FILE]...'),
2540 inferrepo=True)
2540 inferrepo=True)
2541 def debugwalk(ui, repo, *pats, **opts):
2541 def debugwalk(ui, repo, *pats, **opts):
2542 """show how files match on given patterns"""
2542 """show how files match on given patterns"""
2543 opts = pycompat.byteskwargs(opts)
2543 opts = pycompat.byteskwargs(opts)
2544 m = scmutil.match(repo[None], pats, opts)
2544 m = scmutil.match(repo[None], pats, opts)
2545 ui.write(('matcher: %r\n' % m))
2545 if ui.verbose:
2546 ui.write(('matcher: %r\n' % m))
2546 items = list(repo[None].walk(m))
2547 items = list(repo[None].walk(m))
2547 if not items:
2548 if not items:
2548 return
2549 return
2549 f = lambda fn: fn
2550 f = lambda fn: fn
2550 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2551 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2551 f = lambda fn: util.normpath(fn)
2552 f = lambda fn: util.normpath(fn)
2552 fmt = 'f %%-%ds %%-%ds %%s' % (
2553 fmt = 'f %%-%ds %%-%ds %%s' % (
2553 max([len(abs) for abs in items]),
2554 max([len(abs) for abs in items]),
2554 max([len(m.rel(abs)) for abs in items]))
2555 max([len(m.rel(abs)) for abs in items]))
2555 for abs in items:
2556 for abs in items:
2556 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2557 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2557 ui.write("%s\n" % line.rstrip())
2558 ui.write("%s\n" % line.rstrip())
2558
2559
2559 @command('debugwhyunstable', [], _('REV'))
2560 @command('debugwhyunstable', [], _('REV'))
2560 def debugwhyunstable(ui, repo, rev):
2561 def debugwhyunstable(ui, repo, rev):
2561 """explain instabilities of a changeset"""
2562 """explain instabilities of a changeset"""
2562 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
2563 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
2563 dnodes = ''
2564 dnodes = ''
2564 if entry.get('divergentnodes'):
2565 if entry.get('divergentnodes'):
2565 dnodes = ' '.join('%s (%s)' % (ctx.hex(), ctx.phasestr())
2566 dnodes = ' '.join('%s (%s)' % (ctx.hex(), ctx.phasestr())
2566 for ctx in entry['divergentnodes']) + ' '
2567 for ctx in entry['divergentnodes']) + ' '
2567 ui.write('%s: %s%s %s\n' % (entry['instability'], dnodes,
2568 ui.write('%s: %s%s %s\n' % (entry['instability'], dnodes,
2568 entry['reason'], entry['node']))
2569 entry['reason'], entry['node']))
2569
2570
2570 @command('debugwireargs',
2571 @command('debugwireargs',
2571 [('', 'three', '', 'three'),
2572 [('', 'three', '', 'three'),
2572 ('', 'four', '', 'four'),
2573 ('', 'four', '', 'four'),
2573 ('', 'five', '', 'five'),
2574 ('', 'five', '', 'five'),
2574 ] + cmdutil.remoteopts,
2575 ] + cmdutil.remoteopts,
2575 _('REPO [OPTIONS]... [ONE [TWO]]'),
2576 _('REPO [OPTIONS]... [ONE [TWO]]'),
2576 norepo=True)
2577 norepo=True)
2577 def debugwireargs(ui, repopath, *vals, **opts):
2578 def debugwireargs(ui, repopath, *vals, **opts):
2578 opts = pycompat.byteskwargs(opts)
2579 opts = pycompat.byteskwargs(opts)
2579 repo = hg.peer(ui, opts, repopath)
2580 repo = hg.peer(ui, opts, repopath)
2580 for opt in cmdutil.remoteopts:
2581 for opt in cmdutil.remoteopts:
2581 del opts[opt[1]]
2582 del opts[opt[1]]
2582 args = {}
2583 args = {}
2583 for k, v in opts.iteritems():
2584 for k, v in opts.iteritems():
2584 if v:
2585 if v:
2585 args[k] = v
2586 args[k] = v
2586 args = pycompat.strkwargs(args)
2587 args = pycompat.strkwargs(args)
2587 # run twice to check that we don't mess up the stream for the next command
2588 # run twice to check that we don't mess up the stream for the next command
2588 res1 = repo.debugwireargs(*vals, **args)
2589 res1 = repo.debugwireargs(*vals, **args)
2589 res2 = repo.debugwireargs(*vals, **args)
2590 res2 = repo.debugwireargs(*vals, **args)
2590 ui.write("%s\n" % res1)
2591 ui.write("%s\n" % res1)
2591 if res1 != res2:
2592 if res1 != res2:
2592 ui.warn("%s\n" % res2)
2593 ui.warn("%s\n" % res2)
2593
2594
2594 def _parsewirelangblocks(fh):
2595 def _parsewirelangblocks(fh):
2595 activeaction = None
2596 activeaction = None
2596 blocklines = []
2597 blocklines = []
2597
2598
2598 for line in fh:
2599 for line in fh:
2599 line = line.rstrip()
2600 line = line.rstrip()
2600 if not line:
2601 if not line:
2601 continue
2602 continue
2602
2603
2603 if line.startswith(b'#'):
2604 if line.startswith(b'#'):
2604 continue
2605 continue
2605
2606
2606 if not line.startswith(' '):
2607 if not line.startswith(' '):
2607 # New block. Flush previous one.
2608 # New block. Flush previous one.
2608 if activeaction:
2609 if activeaction:
2609 yield activeaction, blocklines
2610 yield activeaction, blocklines
2610
2611
2611 activeaction = line
2612 activeaction = line
2612 blocklines = []
2613 blocklines = []
2613 continue
2614 continue
2614
2615
2615 # Else we start with an indent.
2616 # Else we start with an indent.
2616
2617
2617 if not activeaction:
2618 if not activeaction:
2618 raise error.Abort(_('indented line outside of block'))
2619 raise error.Abort(_('indented line outside of block'))
2619
2620
2620 blocklines.append(line)
2621 blocklines.append(line)
2621
2622
2622 # Flush last block.
2623 # Flush last block.
2623 if activeaction:
2624 if activeaction:
2624 yield activeaction, blocklines
2625 yield activeaction, blocklines
2625
2626
2626 @command('debugwireproto',
2627 @command('debugwireproto',
2627 [
2628 [
2628 ('', 'localssh', False, _('start an SSH server for this repo')),
2629 ('', 'localssh', False, _('start an SSH server for this repo')),
2629 ('', 'peer', '', _('construct a specific version of the peer')),
2630 ('', 'peer', '', _('construct a specific version of the peer')),
2630 ('', 'noreadstderr', False, _('do not read from stderr of the remote')),
2631 ('', 'noreadstderr', False, _('do not read from stderr of the remote')),
2631 ('', 'nologhandshake', False,
2632 ('', 'nologhandshake', False,
2632 _('do not log I/O related to the peer handshake')),
2633 _('do not log I/O related to the peer handshake')),
2633 ] + cmdutil.remoteopts,
2634 ] + cmdutil.remoteopts,
2634 _('[PATH]'),
2635 _('[PATH]'),
2635 optionalrepo=True)
2636 optionalrepo=True)
2636 def debugwireproto(ui, repo, path=None, **opts):
2637 def debugwireproto(ui, repo, path=None, **opts):
2637 """send wire protocol commands to a server
2638 """send wire protocol commands to a server
2638
2639
2639 This command can be used to issue wire protocol commands to remote
2640 This command can be used to issue wire protocol commands to remote
2640 peers and to debug the raw data being exchanged.
2641 peers and to debug the raw data being exchanged.
2641
2642
2642 ``--localssh`` will start an SSH server against the current repository
2643 ``--localssh`` will start an SSH server against the current repository
2643 and connect to that. By default, the connection will perform a handshake
2644 and connect to that. By default, the connection will perform a handshake
2644 and establish an appropriate peer instance.
2645 and establish an appropriate peer instance.
2645
2646
2646 ``--peer`` can be used to bypass the handshake protocol and construct a
2647 ``--peer`` can be used to bypass the handshake protocol and construct a
2647 peer instance using the specified class type. Valid values are ``raw``,
2648 peer instance using the specified class type. Valid values are ``raw``,
2648 ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending
2649 ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending
2649 raw data payloads and don't support higher-level command actions.
2650 raw data payloads and don't support higher-level command actions.
2650
2651
2651 ``--noreadstderr`` can be used to disable automatic reading from stderr
2652 ``--noreadstderr`` can be used to disable automatic reading from stderr
2652 of the peer (for SSH connections only). Disabling automatic reading of
2653 of the peer (for SSH connections only). Disabling automatic reading of
2653 stderr is useful for making output more deterministic.
2654 stderr is useful for making output more deterministic.
2654
2655
2655 Commands are issued via a mini language which is specified via stdin.
2656 Commands are issued via a mini language which is specified via stdin.
2656 The language consists of individual actions to perform. An action is
2657 The language consists of individual actions to perform. An action is
2657 defined by a block. A block is defined as a line with no leading
2658 defined by a block. A block is defined as a line with no leading
2658 space followed by 0 or more lines with leading space. Blocks are
2659 space followed by 0 or more lines with leading space. Blocks are
2659 effectively a high-level command with additional metadata.
2660 effectively a high-level command with additional metadata.
2660
2661
2661 Lines beginning with ``#`` are ignored.
2662 Lines beginning with ``#`` are ignored.
2662
2663
2663 The following sections denote available actions.
2664 The following sections denote available actions.
2664
2665
2665 raw
2666 raw
2666 ---
2667 ---
2667
2668
2668 Send raw data to the server.
2669 Send raw data to the server.
2669
2670
2670 The block payload contains the raw data to send as one atomic send
2671 The block payload contains the raw data to send as one atomic send
2671 operation. The data may not actually be delivered in a single system
2672 operation. The data may not actually be delivered in a single system
2672 call: it depends on the abilities of the transport being used.
2673 call: it depends on the abilities of the transport being used.
2673
2674
2674 Each line in the block is de-indented and concatenated. Then, that
2675 Each line in the block is de-indented and concatenated. Then, that
2675 value is evaluated as a Python b'' literal. This allows the use of
2676 value is evaluated as a Python b'' literal. This allows the use of
2676 backslash escaping, etc.
2677 backslash escaping, etc.
2677
2678
2678 raw+
2679 raw+
2679 ----
2680 ----
2680
2681
2681 Behaves like ``raw`` except flushes output afterwards.
2682 Behaves like ``raw`` except flushes output afterwards.
2682
2683
2683 command <X>
2684 command <X>
2684 -----------
2685 -----------
2685
2686
2686 Send a request to run a named command, whose name follows the ``command``
2687 Send a request to run a named command, whose name follows the ``command``
2687 string.
2688 string.
2688
2689
2689 Arguments to the command are defined as lines in this block. The format of
2690 Arguments to the command are defined as lines in this block. The format of
2690 each line is ``<key> <value>``. e.g.::
2691 each line is ``<key> <value>``. e.g.::
2691
2692
2692 command listkeys
2693 command listkeys
2693 namespace bookmarks
2694 namespace bookmarks
2694
2695
2695 If the value begins with ``eval:``, it will be interpreted as a Python
2696 If the value begins with ``eval:``, it will be interpreted as a Python
2696 literal expression. Otherwise values are interpreted as Python b'' literals.
2697 literal expression. Otherwise values are interpreted as Python b'' literals.
2697 This allows sending complex types and encoding special byte sequences via
2698 This allows sending complex types and encoding special byte sequences via
2698 backslash escaping.
2699 backslash escaping.
2699
2700
2700 The following arguments have special meaning:
2701 The following arguments have special meaning:
2701
2702
2702 ``PUSHFILE``
2703 ``PUSHFILE``
2703 When defined, the *push* mechanism of the peer will be used instead
2704 When defined, the *push* mechanism of the peer will be used instead
2704 of the static request-response mechanism and the content of the
2705 of the static request-response mechanism and the content of the
2705 file specified in the value of this argument will be sent as the
2706 file specified in the value of this argument will be sent as the
2706 command payload.
2707 command payload.
2707
2708
2708 This can be used to submit a local bundle file to the remote.
2709 This can be used to submit a local bundle file to the remote.
2709
2710
2710 batchbegin
2711 batchbegin
2711 ----------
2712 ----------
2712
2713
2713 Instruct the peer to begin a batched send.
2714 Instruct the peer to begin a batched send.
2714
2715
2715 All ``command`` blocks are queued for execution until the next
2716 All ``command`` blocks are queued for execution until the next
2716 ``batchsubmit`` block.
2717 ``batchsubmit`` block.
2717
2718
2718 batchsubmit
2719 batchsubmit
2719 -----------
2720 -----------
2720
2721
2721 Submit previously queued ``command`` blocks as a batch request.
2722 Submit previously queued ``command`` blocks as a batch request.
2722
2723
2723 This action MUST be paired with a ``batchbegin`` action.
2724 This action MUST be paired with a ``batchbegin`` action.
2724
2725
2725 httprequest <method> <path>
2726 httprequest <method> <path>
2726 ---------------------------
2727 ---------------------------
2727
2728
2728 (HTTP peer only)
2729 (HTTP peer only)
2729
2730
2730 Send an HTTP request to the peer.
2731 Send an HTTP request to the peer.
2731
2732
2732 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
2733 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
2733
2734
2734 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
2735 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
2735 headers to add to the request. e.g. ``Accept: foo``.
2736 headers to add to the request. e.g. ``Accept: foo``.
2736
2737
2737 The following arguments are special:
2738 The following arguments are special:
2738
2739
2739 ``BODYFILE``
2740 ``BODYFILE``
2740 The content of the file defined as the value to this argument will be
2741 The content of the file defined as the value to this argument will be
2741 transferred verbatim as the HTTP request body.
2742 transferred verbatim as the HTTP request body.
2742
2743
2743 ``frame <type> <flags> <payload>``
2744 ``frame <type> <flags> <payload>``
2744 Send a unified protocol frame as part of the request body.
2745 Send a unified protocol frame as part of the request body.
2745
2746
2746 All frames will be collected and sent as the body to the HTTP
2747 All frames will be collected and sent as the body to the HTTP
2747 request.
2748 request.
2748
2749
2749 close
2750 close
2750 -----
2751 -----
2751
2752
2752 Close the connection to the server.
2753 Close the connection to the server.
2753
2754
2754 flush
2755 flush
2755 -----
2756 -----
2756
2757
2757 Flush data written to the server.
2758 Flush data written to the server.
2758
2759
2759 readavailable
2760 readavailable
2760 -------------
2761 -------------
2761
2762
2762 Close the write end of the connection and read all available data from
2763 Close the write end of the connection and read all available data from
2763 the server.
2764 the server.
2764
2765
2765 If the connection to the server encompasses multiple pipes, we poll both
2766 If the connection to the server encompasses multiple pipes, we poll both
2766 pipes and read available data.
2767 pipes and read available data.
2767
2768
2768 readline
2769 readline
2769 --------
2770 --------
2770
2771
2771 Read a line of output from the server. If there are multiple output
2772 Read a line of output from the server. If there are multiple output
2772 pipes, reads only the main pipe.
2773 pipes, reads only the main pipe.
2773
2774
2774 ereadline
2775 ereadline
2775 ---------
2776 ---------
2776
2777
2777 Like ``readline``, but read from the stderr pipe, if available.
2778 Like ``readline``, but read from the stderr pipe, if available.
2778
2779
2779 read <X>
2780 read <X>
2780 --------
2781 --------
2781
2782
2782 ``read()`` N bytes from the server's main output pipe.
2783 ``read()`` N bytes from the server's main output pipe.
2783
2784
2784 eread <X>
2785 eread <X>
2785 ---------
2786 ---------
2786
2787
2787 ``read()`` N bytes from the server's stderr pipe, if available.
2788 ``read()`` N bytes from the server's stderr pipe, if available.
2788
2789
2789 Specifying Unified Frame-Based Protocol Frames
2790 Specifying Unified Frame-Based Protocol Frames
2790 ----------------------------------------------
2791 ----------------------------------------------
2791
2792
2792 It is possible to emit a *Unified Frame-Based Protocol* by using special
2793 It is possible to emit a *Unified Frame-Based Protocol* by using special
2793 syntax.
2794 syntax.
2794
2795
2795 A frame is composed as a type, flags, and payload. These can be parsed
2796 A frame is composed as a type, flags, and payload. These can be parsed
2796 from a string of the form:
2797 from a string of the form:
2797
2798
2798 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
2799 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
2799
2800
2800 ``request-id`` and ``stream-id`` are integers defining the request and
2801 ``request-id`` and ``stream-id`` are integers defining the request and
2801 stream identifiers.
2802 stream identifiers.
2802
2803
2803 ``type`` can be an integer value for the frame type or the string name
2804 ``type`` can be an integer value for the frame type or the string name
2804 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
2805 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
2805 ``command-name``.
2806 ``command-name``.
2806
2807
2807 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
2808 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
2808 components. Each component (and there can be just one) can be an integer
2809 components. Each component (and there can be just one) can be an integer
2809 or a flag name for stream flags or frame flags, respectively. Values are
2810 or a flag name for stream flags or frame flags, respectively. Values are
2810 resolved to integers and then bitwise OR'd together.
2811 resolved to integers and then bitwise OR'd together.
2811
2812
2812 ``payload`` represents the raw frame payload. If it begins with
2813 ``payload`` represents the raw frame payload. If it begins with
2813 ``cbor:``, the following string is evaluated as Python code and the
2814 ``cbor:``, the following string is evaluated as Python code and the
2814 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
2815 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
2815 as a Python byte string literal.
2816 as a Python byte string literal.
2816 """
2817 """
2817 opts = pycompat.byteskwargs(opts)
2818 opts = pycompat.byteskwargs(opts)
2818
2819
2819 if opts['localssh'] and not repo:
2820 if opts['localssh'] and not repo:
2820 raise error.Abort(_('--localssh requires a repository'))
2821 raise error.Abort(_('--localssh requires a repository'))
2821
2822
2822 if opts['peer'] and opts['peer'] not in ('raw', 'http2', 'ssh1', 'ssh2'):
2823 if opts['peer'] and opts['peer'] not in ('raw', 'http2', 'ssh1', 'ssh2'):
2823 raise error.Abort(_('invalid value for --peer'),
2824 raise error.Abort(_('invalid value for --peer'),
2824 hint=_('valid values are "raw", "ssh1", and "ssh2"'))
2825 hint=_('valid values are "raw", "ssh1", and "ssh2"'))
2825
2826
2826 if path and opts['localssh']:
2827 if path and opts['localssh']:
2827 raise error.Abort(_('cannot specify --localssh with an explicit '
2828 raise error.Abort(_('cannot specify --localssh with an explicit '
2828 'path'))
2829 'path'))
2829
2830
2830 if ui.interactive():
2831 if ui.interactive():
2831 ui.write(_('(waiting for commands on stdin)\n'))
2832 ui.write(_('(waiting for commands on stdin)\n'))
2832
2833
2833 blocks = list(_parsewirelangblocks(ui.fin))
2834 blocks = list(_parsewirelangblocks(ui.fin))
2834
2835
2835 proc = None
2836 proc = None
2836 stdin = None
2837 stdin = None
2837 stdout = None
2838 stdout = None
2838 stderr = None
2839 stderr = None
2839 opener = None
2840 opener = None
2840
2841
2841 if opts['localssh']:
2842 if opts['localssh']:
2842 # We start the SSH server in its own process so there is process
2843 # We start the SSH server in its own process so there is process
2843 # separation. This prevents a whole class of potential bugs around
2844 # separation. This prevents a whole class of potential bugs around
2844 # shared state from interfering with server operation.
2845 # shared state from interfering with server operation.
2845 args = procutil.hgcmd() + [
2846 args = procutil.hgcmd() + [
2846 '-R', repo.root,
2847 '-R', repo.root,
2847 'debugserve', '--sshstdio',
2848 'debugserve', '--sshstdio',
2848 ]
2849 ]
2849 proc = subprocess.Popen(args, stdin=subprocess.PIPE,
2850 proc = subprocess.Popen(args, stdin=subprocess.PIPE,
2850 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
2851 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
2851 bufsize=0)
2852 bufsize=0)
2852
2853
2853 stdin = proc.stdin
2854 stdin = proc.stdin
2854 stdout = proc.stdout
2855 stdout = proc.stdout
2855 stderr = proc.stderr
2856 stderr = proc.stderr
2856
2857
2857 # We turn the pipes into observers so we can log I/O.
2858 # We turn the pipes into observers so we can log I/O.
2858 if ui.verbose or opts['peer'] == 'raw':
2859 if ui.verbose or opts['peer'] == 'raw':
2859 stdin = util.makeloggingfileobject(ui, proc.stdin, b'i',
2860 stdin = util.makeloggingfileobject(ui, proc.stdin, b'i',
2860 logdata=True)
2861 logdata=True)
2861 stdout = util.makeloggingfileobject(ui, proc.stdout, b'o',
2862 stdout = util.makeloggingfileobject(ui, proc.stdout, b'o',
2862 logdata=True)
2863 logdata=True)
2863 stderr = util.makeloggingfileobject(ui, proc.stderr, b'e',
2864 stderr = util.makeloggingfileobject(ui, proc.stderr, b'e',
2864 logdata=True)
2865 logdata=True)
2865
2866
2866 # --localssh also implies the peer connection settings.
2867 # --localssh also implies the peer connection settings.
2867
2868
2868 url = 'ssh://localserver'
2869 url = 'ssh://localserver'
2869 autoreadstderr = not opts['noreadstderr']
2870 autoreadstderr = not opts['noreadstderr']
2870
2871
2871 if opts['peer'] == 'ssh1':
2872 if opts['peer'] == 'ssh1':
2872 ui.write(_('creating ssh peer for wire protocol version 1\n'))
2873 ui.write(_('creating ssh peer for wire protocol version 1\n'))
2873 peer = sshpeer.sshv1peer(ui, url, proc, stdin, stdout, stderr,
2874 peer = sshpeer.sshv1peer(ui, url, proc, stdin, stdout, stderr,
2874 None, autoreadstderr=autoreadstderr)
2875 None, autoreadstderr=autoreadstderr)
2875 elif opts['peer'] == 'ssh2':
2876 elif opts['peer'] == 'ssh2':
2876 ui.write(_('creating ssh peer for wire protocol version 2\n'))
2877 ui.write(_('creating ssh peer for wire protocol version 2\n'))
2877 peer = sshpeer.sshv2peer(ui, url, proc, stdin, stdout, stderr,
2878 peer = sshpeer.sshv2peer(ui, url, proc, stdin, stdout, stderr,
2878 None, autoreadstderr=autoreadstderr)
2879 None, autoreadstderr=autoreadstderr)
2879 elif opts['peer'] == 'raw':
2880 elif opts['peer'] == 'raw':
2880 ui.write(_('using raw connection to peer\n'))
2881 ui.write(_('using raw connection to peer\n'))
2881 peer = None
2882 peer = None
2882 else:
2883 else:
2883 ui.write(_('creating ssh peer from handshake results\n'))
2884 ui.write(_('creating ssh peer from handshake results\n'))
2884 peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr,
2885 peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr,
2885 autoreadstderr=autoreadstderr)
2886 autoreadstderr=autoreadstderr)
2886
2887
2887 elif path:
2888 elif path:
2888 # We bypass hg.peer() so we can proxy the sockets.
2889 # We bypass hg.peer() so we can proxy the sockets.
2889 # TODO consider not doing this because we skip
2890 # TODO consider not doing this because we skip
2890 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
2891 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
2891 u = util.url(path)
2892 u = util.url(path)
2892 if u.scheme != 'http':
2893 if u.scheme != 'http':
2893 raise error.Abort(_('only http:// paths are currently supported'))
2894 raise error.Abort(_('only http:// paths are currently supported'))
2894
2895
2895 url, authinfo = u.authinfo()
2896 url, authinfo = u.authinfo()
2896 openerargs = {
2897 openerargs = {
2897 r'useragent': b'Mercurial debugwireproto',
2898 r'useragent': b'Mercurial debugwireproto',
2898 }
2899 }
2899
2900
2900 # Turn pipes/sockets into observers so we can log I/O.
2901 # Turn pipes/sockets into observers so we can log I/O.
2901 if ui.verbose:
2902 if ui.verbose:
2902 openerargs.update({
2903 openerargs.update({
2903 r'loggingfh': ui,
2904 r'loggingfh': ui,
2904 r'loggingname': b's',
2905 r'loggingname': b's',
2905 r'loggingopts': {
2906 r'loggingopts': {
2906 r'logdata': True,
2907 r'logdata': True,
2907 r'logdataapis': False,
2908 r'logdataapis': False,
2908 },
2909 },
2909 })
2910 })
2910
2911
2911 if ui.debugflag:
2912 if ui.debugflag:
2912 openerargs[r'loggingopts'][r'logdataapis'] = True
2913 openerargs[r'loggingopts'][r'logdataapis'] = True
2913
2914
2914 # Don't send default headers when in raw mode. This allows us to
2915 # Don't send default headers when in raw mode. This allows us to
2915 # bypass most of the behavior of our URL handling code so we can
2916 # bypass most of the behavior of our URL handling code so we can
2916 # have near complete control over what's sent on the wire.
2917 # have near complete control over what's sent on the wire.
2917 if opts['peer'] == 'raw':
2918 if opts['peer'] == 'raw':
2918 openerargs[r'sendaccept'] = False
2919 openerargs[r'sendaccept'] = False
2919
2920
2920 opener = urlmod.opener(ui, authinfo, **openerargs)
2921 opener = urlmod.opener(ui, authinfo, **openerargs)
2921
2922
2922 if opts['peer'] == 'http2':
2923 if opts['peer'] == 'http2':
2923 ui.write(_('creating http peer for wire protocol version 2\n'))
2924 ui.write(_('creating http peer for wire protocol version 2\n'))
2924 # We go through makepeer() because we need an API descriptor for
2925 # We go through makepeer() because we need an API descriptor for
2925 # the peer instance to be useful.
2926 # the peer instance to be useful.
2926 with ui.configoverride({
2927 with ui.configoverride({
2927 ('experimental', 'httppeer.advertise-v2'): True}):
2928 ('experimental', 'httppeer.advertise-v2'): True}):
2928 if opts['nologhandshake']:
2929 if opts['nologhandshake']:
2929 ui.pushbuffer()
2930 ui.pushbuffer()
2930
2931
2931 peer = httppeer.makepeer(ui, path, opener=opener)
2932 peer = httppeer.makepeer(ui, path, opener=opener)
2932
2933
2933 if opts['nologhandshake']:
2934 if opts['nologhandshake']:
2934 ui.popbuffer()
2935 ui.popbuffer()
2935
2936
2936 if not isinstance(peer, httppeer.httpv2peer):
2937 if not isinstance(peer, httppeer.httpv2peer):
2937 raise error.Abort(_('could not instantiate HTTP peer for '
2938 raise error.Abort(_('could not instantiate HTTP peer for '
2938 'wire protocol version 2'),
2939 'wire protocol version 2'),
2939 hint=_('the server may not have the feature '
2940 hint=_('the server may not have the feature '
2940 'enabled or is not allowing this '
2941 'enabled or is not allowing this '
2941 'client version'))
2942 'client version'))
2942
2943
2943 elif opts['peer'] == 'raw':
2944 elif opts['peer'] == 'raw':
2944 ui.write(_('using raw connection to peer\n'))
2945 ui.write(_('using raw connection to peer\n'))
2945 peer = None
2946 peer = None
2946 elif opts['peer']:
2947 elif opts['peer']:
2947 raise error.Abort(_('--peer %s not supported with HTTP peers') %
2948 raise error.Abort(_('--peer %s not supported with HTTP peers') %
2948 opts['peer'])
2949 opts['peer'])
2949 else:
2950 else:
2950 peer = httppeer.makepeer(ui, path, opener=opener)
2951 peer = httppeer.makepeer(ui, path, opener=opener)
2951
2952
2952 # We /could/ populate stdin/stdout with sock.makefile()...
2953 # We /could/ populate stdin/stdout with sock.makefile()...
2953 else:
2954 else:
2954 raise error.Abort(_('unsupported connection configuration'))
2955 raise error.Abort(_('unsupported connection configuration'))
2955
2956
2956 batchedcommands = None
2957 batchedcommands = None
2957
2958
2958 # Now perform actions based on the parsed wire language instructions.
2959 # Now perform actions based on the parsed wire language instructions.
2959 for action, lines in blocks:
2960 for action, lines in blocks:
2960 if action in ('raw', 'raw+'):
2961 if action in ('raw', 'raw+'):
2961 if not stdin:
2962 if not stdin:
2962 raise error.Abort(_('cannot call raw/raw+ on this peer'))
2963 raise error.Abort(_('cannot call raw/raw+ on this peer'))
2963
2964
2964 # Concatenate the data together.
2965 # Concatenate the data together.
2965 data = ''.join(l.lstrip() for l in lines)
2966 data = ''.join(l.lstrip() for l in lines)
2966 data = stringutil.unescapestr(data)
2967 data = stringutil.unescapestr(data)
2967 stdin.write(data)
2968 stdin.write(data)
2968
2969
2969 if action == 'raw+':
2970 if action == 'raw+':
2970 stdin.flush()
2971 stdin.flush()
2971 elif action == 'flush':
2972 elif action == 'flush':
2972 if not stdin:
2973 if not stdin:
2973 raise error.Abort(_('cannot call flush on this peer'))
2974 raise error.Abort(_('cannot call flush on this peer'))
2974 stdin.flush()
2975 stdin.flush()
2975 elif action.startswith('command'):
2976 elif action.startswith('command'):
2976 if not peer:
2977 if not peer:
2977 raise error.Abort(_('cannot send commands unless peer instance '
2978 raise error.Abort(_('cannot send commands unless peer instance '
2978 'is available'))
2979 'is available'))
2979
2980
2980 command = action.split(' ', 1)[1]
2981 command = action.split(' ', 1)[1]
2981
2982
2982 args = {}
2983 args = {}
2983 for line in lines:
2984 for line in lines:
2984 # We need to allow empty values.
2985 # We need to allow empty values.
2985 fields = line.lstrip().split(' ', 1)
2986 fields = line.lstrip().split(' ', 1)
2986 if len(fields) == 1:
2987 if len(fields) == 1:
2987 key = fields[0]
2988 key = fields[0]
2988 value = ''
2989 value = ''
2989 else:
2990 else:
2990 key, value = fields
2991 key, value = fields
2991
2992
2992 if value.startswith('eval:'):
2993 if value.startswith('eval:'):
2993 value = stringutil.evalpythonliteral(value[5:])
2994 value = stringutil.evalpythonliteral(value[5:])
2994 else:
2995 else:
2995 value = stringutil.unescapestr(value)
2996 value = stringutil.unescapestr(value)
2996
2997
2997 args[key] = value
2998 args[key] = value
2998
2999
2999 if batchedcommands is not None:
3000 if batchedcommands is not None:
3000 batchedcommands.append((command, args))
3001 batchedcommands.append((command, args))
3001 continue
3002 continue
3002
3003
3003 ui.status(_('sending %s command\n') % command)
3004 ui.status(_('sending %s command\n') % command)
3004
3005
3005 if 'PUSHFILE' in args:
3006 if 'PUSHFILE' in args:
3006 with open(args['PUSHFILE'], r'rb') as fh:
3007 with open(args['PUSHFILE'], r'rb') as fh:
3007 del args['PUSHFILE']
3008 del args['PUSHFILE']
3008 res, output = peer._callpush(command, fh,
3009 res, output = peer._callpush(command, fh,
3009 **pycompat.strkwargs(args))
3010 **pycompat.strkwargs(args))
3010 ui.status(_('result: %s\n') % stringutil.escapestr(res))
3011 ui.status(_('result: %s\n') % stringutil.escapestr(res))
3011 ui.status(_('remote output: %s\n') %
3012 ui.status(_('remote output: %s\n') %
3012 stringutil.escapestr(output))
3013 stringutil.escapestr(output))
3013 else:
3014 else:
3014 with peer.commandexecutor() as e:
3015 with peer.commandexecutor() as e:
3015 res = e.callcommand(command, args).result()
3016 res = e.callcommand(command, args).result()
3016
3017
3017 if isinstance(res, wireprotov2peer.commandresponse):
3018 if isinstance(res, wireprotov2peer.commandresponse):
3018 val = list(res.cborobjects())
3019 val = list(res.cborobjects())
3019 ui.status(_('response: %s\n') %
3020 ui.status(_('response: %s\n') %
3020 stringutil.pprint(val, bprefix=True))
3021 stringutil.pprint(val, bprefix=True))
3021
3022
3022 else:
3023 else:
3023 ui.status(_('response: %s\n') %
3024 ui.status(_('response: %s\n') %
3024 stringutil.pprint(res, bprefix=True))
3025 stringutil.pprint(res, bprefix=True))
3025
3026
3026 elif action == 'batchbegin':
3027 elif action == 'batchbegin':
3027 if batchedcommands is not None:
3028 if batchedcommands is not None:
3028 raise error.Abort(_('nested batchbegin not allowed'))
3029 raise error.Abort(_('nested batchbegin not allowed'))
3029
3030
3030 batchedcommands = []
3031 batchedcommands = []
3031 elif action == 'batchsubmit':
3032 elif action == 'batchsubmit':
3032 # There is a batching API we could go through. But it would be
3033 # There is a batching API we could go through. But it would be
3033 # difficult to normalize requests into function calls. It is easier
3034 # difficult to normalize requests into function calls. It is easier
3034 # to bypass this layer and normalize to commands + args.
3035 # to bypass this layer and normalize to commands + args.
3035 ui.status(_('sending batch with %d sub-commands\n') %
3036 ui.status(_('sending batch with %d sub-commands\n') %
3036 len(batchedcommands))
3037 len(batchedcommands))
3037 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
3038 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
3038 ui.status(_('response #%d: %s\n') %
3039 ui.status(_('response #%d: %s\n') %
3039 (i, stringutil.escapestr(chunk)))
3040 (i, stringutil.escapestr(chunk)))
3040
3041
3041 batchedcommands = None
3042 batchedcommands = None
3042
3043
3043 elif action.startswith('httprequest '):
3044 elif action.startswith('httprequest '):
3044 if not opener:
3045 if not opener:
3045 raise error.Abort(_('cannot use httprequest without an HTTP '
3046 raise error.Abort(_('cannot use httprequest without an HTTP '
3046 'peer'))
3047 'peer'))
3047
3048
3048 request = action.split(' ', 2)
3049 request = action.split(' ', 2)
3049 if len(request) != 3:
3050 if len(request) != 3:
3050 raise error.Abort(_('invalid httprequest: expected format is '
3051 raise error.Abort(_('invalid httprequest: expected format is '
3051 '"httprequest <method> <path>'))
3052 '"httprequest <method> <path>'))
3052
3053
3053 method, httppath = request[1:]
3054 method, httppath = request[1:]
3054 headers = {}
3055 headers = {}
3055 body = None
3056 body = None
3056 frames = []
3057 frames = []
3057 for line in lines:
3058 for line in lines:
3058 line = line.lstrip()
3059 line = line.lstrip()
3059 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
3060 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
3060 if m:
3061 if m:
3061 headers[m.group(1)] = m.group(2)
3062 headers[m.group(1)] = m.group(2)
3062 continue
3063 continue
3063
3064
3064 if line.startswith(b'BODYFILE '):
3065 if line.startswith(b'BODYFILE '):
3065 with open(line.split(b' ', 1), 'rb') as fh:
3066 with open(line.split(b' ', 1), 'rb') as fh:
3066 body = fh.read()
3067 body = fh.read()
3067 elif line.startswith(b'frame '):
3068 elif line.startswith(b'frame '):
3068 frame = wireprotoframing.makeframefromhumanstring(
3069 frame = wireprotoframing.makeframefromhumanstring(
3069 line[len(b'frame '):])
3070 line[len(b'frame '):])
3070
3071
3071 frames.append(frame)
3072 frames.append(frame)
3072 else:
3073 else:
3073 raise error.Abort(_('unknown argument to httprequest: %s') %
3074 raise error.Abort(_('unknown argument to httprequest: %s') %
3074 line)
3075 line)
3075
3076
3076 url = path + httppath
3077 url = path + httppath
3077
3078
3078 if frames:
3079 if frames:
3079 body = b''.join(bytes(f) for f in frames)
3080 body = b''.join(bytes(f) for f in frames)
3080
3081
3081 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
3082 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
3082
3083
3083 # urllib.Request insists on using has_data() as a proxy for
3084 # urllib.Request insists on using has_data() as a proxy for
3084 # determining the request method. Override that to use our
3085 # determining the request method. Override that to use our
3085 # explicitly requested method.
3086 # explicitly requested method.
3086 req.get_method = lambda: method
3087 req.get_method = lambda: method
3087
3088
3088 try:
3089 try:
3089 res = opener.open(req)
3090 res = opener.open(req)
3090 body = res.read()
3091 body = res.read()
3091 except util.urlerr.urlerror as e:
3092 except util.urlerr.urlerror as e:
3092 e.read()
3093 e.read()
3093 continue
3094 continue
3094
3095
3095 if res.headers.get('Content-Type') == 'application/mercurial-cbor':
3096 if res.headers.get('Content-Type') == 'application/mercurial-cbor':
3096 ui.write(_('cbor> %s\n') %
3097 ui.write(_('cbor> %s\n') %
3097 stringutil.pprint(cbor.loads(body), bprefix=True))
3098 stringutil.pprint(cbor.loads(body), bprefix=True))
3098
3099
3099 elif action == 'close':
3100 elif action == 'close':
3100 peer.close()
3101 peer.close()
3101 elif action == 'readavailable':
3102 elif action == 'readavailable':
3102 if not stdout or not stderr:
3103 if not stdout or not stderr:
3103 raise error.Abort(_('readavailable not available on this peer'))
3104 raise error.Abort(_('readavailable not available on this peer'))
3104
3105
3105 stdin.close()
3106 stdin.close()
3106 stdout.read()
3107 stdout.read()
3107 stderr.read()
3108 stderr.read()
3108
3109
3109 elif action == 'readline':
3110 elif action == 'readline':
3110 if not stdout:
3111 if not stdout:
3111 raise error.Abort(_('readline not available on this peer'))
3112 raise error.Abort(_('readline not available on this peer'))
3112 stdout.readline()
3113 stdout.readline()
3113 elif action == 'ereadline':
3114 elif action == 'ereadline':
3114 if not stderr:
3115 if not stderr:
3115 raise error.Abort(_('ereadline not available on this peer'))
3116 raise error.Abort(_('ereadline not available on this peer'))
3116 stderr.readline()
3117 stderr.readline()
3117 elif action.startswith('read '):
3118 elif action.startswith('read '):
3118 count = int(action.split(' ', 1)[1])
3119 count = int(action.split(' ', 1)[1])
3119 if not stdout:
3120 if not stdout:
3120 raise error.Abort(_('read not available on this peer'))
3121 raise error.Abort(_('read not available on this peer'))
3121 stdout.read(count)
3122 stdout.read(count)
3122 elif action.startswith('eread '):
3123 elif action.startswith('eread '):
3123 count = int(action.split(' ', 1)[1])
3124 count = int(action.split(' ', 1)[1])
3124 if not stderr:
3125 if not stderr:
3125 raise error.Abort(_('eread not available on this peer'))
3126 raise error.Abort(_('eread not available on this peer'))
3126 stderr.read(count)
3127 stderr.read(count)
3127 else:
3128 else:
3128 raise error.Abort(_('unknown action: %s') % action)
3129 raise error.Abort(_('unknown action: %s') % action)
3129
3130
3130 if batchedcommands is not None:
3131 if batchedcommands is not None:
3131 raise error.Abort(_('unclosed "batchbegin" request'))
3132 raise error.Abort(_('unclosed "batchbegin" request'))
3132
3133
3133 if peer:
3134 if peer:
3134 peer.close()
3135 peer.close()
3135
3136
3136 if proc:
3137 if proc:
3137 proc.kill()
3138 proc.kill()
@@ -1,79 +1,79 b''
1 #require eol-in-paths
1 #require eol-in-paths
2
2
3 https://bz.mercurial-scm.org/352
3 https://bz.mercurial-scm.org/352
4
4
5 test issue352
5 test issue352
6
6
7 $ hg init foo
7 $ hg init foo
8 $ cd foo
8 $ cd foo
9 $ A=`printf 'he\rllo'`
9 $ A=`printf 'he\rllo'`
10 $ echo foo > "$A"
10 $ echo foo > "$A"
11 $ hg add
11 $ hg add
12 adding he\r (no-eol) (esc)
12 adding he\r (no-eol) (esc)
13 llo
13 llo
14 abort: '\n' and '\r' disallowed in filenames: 'he\rllo'
14 abort: '\n' and '\r' disallowed in filenames: 'he\rllo'
15 [255]
15 [255]
16 $ hg ci -A -m m
16 $ hg ci -A -m m
17 adding he\r (no-eol) (esc)
17 adding he\r (no-eol) (esc)
18 llo
18 llo
19 abort: '\n' and '\r' disallowed in filenames: 'he\rllo'
19 abort: '\n' and '\r' disallowed in filenames: 'he\rllo'
20 [255]
20 [255]
21 $ rm "$A"
21 $ rm "$A"
22 $ echo foo > "hell
22 $ echo foo > "hell
23 > o"
23 > o"
24 $ hg add
24 $ hg add
25 adding hell
25 adding hell
26 o
26 o
27 abort: '\n' and '\r' disallowed in filenames: 'hell\no'
27 abort: '\n' and '\r' disallowed in filenames: 'hell\no'
28 [255]
28 [255]
29 $ hg ci -A -m m
29 $ hg ci -A -m m
30 adding hell
30 adding hell
31 o
31 o
32 abort: '\n' and '\r' disallowed in filenames: 'hell\no'
32 abort: '\n' and '\r' disallowed in filenames: 'hell\no'
33 [255]
33 [255]
34 $ echo foo > "$A"
34 $ echo foo > "$A"
35 $ hg debugwalk
35 $ hg debugwalk -v
36 matcher: <alwaysmatcher>
36 matcher: <alwaysmatcher>
37 f he\r (no-eol) (esc)
37 f he\r (no-eol) (esc)
38 llo he\r (no-eol) (esc)
38 llo he\r (no-eol) (esc)
39 llo
39 llo
40 f hell
40 f hell
41 o hell
41 o hell
42 o
42 o
43
43
44 $ echo bla > quickfox
44 $ echo bla > quickfox
45 $ hg add quickfox
45 $ hg add quickfox
46 $ hg ci -m 2
46 $ hg ci -m 2
47 $ A=`printf 'quick\rfox'`
47 $ A=`printf 'quick\rfox'`
48 $ hg cp quickfox "$A"
48 $ hg cp quickfox "$A"
49 abort: '\n' and '\r' disallowed in filenames: 'quick\rfox'
49 abort: '\n' and '\r' disallowed in filenames: 'quick\rfox'
50 [255]
50 [255]
51 $ hg mv quickfox "$A"
51 $ hg mv quickfox "$A"
52 abort: '\n' and '\r' disallowed in filenames: 'quick\rfox'
52 abort: '\n' and '\r' disallowed in filenames: 'quick\rfox'
53 [255]
53 [255]
54
54
55 https://bz.mercurial-scm.org/2036
55 https://bz.mercurial-scm.org/2036
56
56
57 $ cd ..
57 $ cd ..
58
58
59 test issue2039
59 test issue2039
60
60
61 $ hg init bar
61 $ hg init bar
62 $ cd bar
62 $ cd bar
63 $ cat <<EOF >> $HGRCPATH
63 $ cat <<EOF >> $HGRCPATH
64 > [extensions]
64 > [extensions]
65 > color =
65 > color =
66 > [color]
66 > [color]
67 > mode = ansi
67 > mode = ansi
68 > EOF
68 > EOF
69 $ A=`printf 'foo\nbar'`
69 $ A=`printf 'foo\nbar'`
70 $ B=`printf 'foo\nbar.baz'`
70 $ B=`printf 'foo\nbar.baz'`
71 $ touch "$A"
71 $ touch "$A"
72 $ touch "$B"
72 $ touch "$B"
73 $ hg status --color=always
73 $ hg status --color=always
74 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc)
74 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc)
75 \x1b[0;35;1;4mbar\x1b[0m (esc)
75 \x1b[0;35;1;4mbar\x1b[0m (esc)
76 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc)
76 \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mfoo\x1b[0m (esc)
77 \x1b[0;35;1;4mbar.baz\x1b[0m (esc)
77 \x1b[0;35;1;4mbar.baz\x1b[0m (esc)
78
78
79 $ cd ..
79 $ cd ..
@@ -1,106 +1,106 b''
1 #testcases flat tree
1 #testcases flat tree
2
2
3 $ . "$TESTDIR/narrow-library.sh"
3 $ . "$TESTDIR/narrow-library.sh"
4
4
5 #if tree
5 #if tree
6 $ cat << EOF >> $HGRCPATH
6 $ cat << EOF >> $HGRCPATH
7 > [experimental]
7 > [experimental]
8 > treemanifest = 1
8 > treemanifest = 1
9 > EOF
9 > EOF
10 #endif
10 #endif
11
11
12 create full repo
12 create full repo
13
13
14 $ hg init master
14 $ hg init master
15 $ cd master
15 $ cd master
16
16
17 $ mkdir inside
17 $ mkdir inside
18 $ echo inside > inside/f1
18 $ echo inside > inside/f1
19 $ mkdir outside
19 $ mkdir outside
20 $ echo outside > outside/f1
20 $ echo outside > outside/f1
21 $ hg ci -Aqm 'initial'
21 $ hg ci -Aqm 'initial'
22
22
23 $ echo modified > inside/f1
23 $ echo modified > inside/f1
24 $ hg ci -qm 'modify inside'
24 $ hg ci -qm 'modify inside'
25
25
26 $ echo modified > outside/f1
26 $ echo modified > outside/f1
27 $ hg ci -qm 'modify outside'
27 $ hg ci -qm 'modify outside'
28
28
29 $ cd ..
29 $ cd ..
30
30
31 (The lfs extension does nothing here, but this test ensures that its hook that
31 (The lfs extension does nothing here, but this test ensures that its hook that
32 determines whether to add the lfs requirement, respects the narrow boundaries.)
32 determines whether to add the lfs requirement, respects the narrow boundaries.)
33
33
34 $ hg --config extensions.lfs= clone --narrow ssh://user@dummy/master narrow \
34 $ hg --config extensions.lfs= clone --narrow ssh://user@dummy/master narrow \
35 > --include inside
35 > --include inside
36 requesting all changes
36 requesting all changes
37 adding changesets
37 adding changesets
38 adding manifests
38 adding manifests
39 adding file changes
39 adding file changes
40 added 3 changesets with 2 changes to 1 files
40 added 3 changesets with 2 changes to 1 files
41 new changesets *:* (glob)
41 new changesets *:* (glob)
42 updating to branch default
42 updating to branch default
43 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 $ cd narrow
44 $ cd narrow
45
45
46 $ hg update -q 0
46 $ hg update -q 0
47
47
48 Can not modify dirstate outside
48 Can not modify dirstate outside
49
49
50 $ mkdir outside
50 $ mkdir outside
51 $ touch outside/f1
51 $ touch outside/f1
52 $ hg debugwalk -I 'relglob:f1'
52 $ hg debugwalk -v -I 'relglob:f1'
53 matcher: <includematcher includes='(?:(?:|.*/)f1(?:/|$))'>
53 matcher: <includematcher includes='(?:(?:|.*/)f1(?:/|$))'>
54 f inside/f1 inside/f1
54 f inside/f1 inside/f1
55 $ hg add outside/f1
55 $ hg add outside/f1
56 abort: cannot track 'outside/f1' - it is outside the narrow clone
56 abort: cannot track 'outside/f1' - it is outside the narrow clone
57 [255]
57 [255]
58 $ touch outside/f3
58 $ touch outside/f3
59 $ hg add outside/f3
59 $ hg add outside/f3
60 abort: cannot track 'outside/f3' - it is outside the narrow clone
60 abort: cannot track 'outside/f3' - it is outside the narrow clone
61 [255]
61 [255]
62
62
63 But adding a truly excluded file shouldn't count
63 But adding a truly excluded file shouldn't count
64
64
65 $ hg add outside/f3 -X outside/f3
65 $ hg add outside/f3 -X outside/f3
66
66
67 $ rm -r outside
67 $ rm -r outside
68
68
69 Can modify dirstate inside
69 Can modify dirstate inside
70
70
71 $ echo modified > inside/f1
71 $ echo modified > inside/f1
72 $ touch inside/f3
72 $ touch inside/f3
73 $ hg add inside/f3
73 $ hg add inside/f3
74 $ hg status
74 $ hg status
75 M inside/f1
75 M inside/f1
76 A inside/f3
76 A inside/f3
77 $ hg revert -qC .
77 $ hg revert -qC .
78 $ rm inside/f3
78 $ rm inside/f3
79
79
80 Can commit changes inside. Leaves outside unchanged.
80 Can commit changes inside. Leaves outside unchanged.
81
81
82 $ hg update -q 'desc("initial")'
82 $ hg update -q 'desc("initial")'
83 $ echo modified2 > inside/f1
83 $ echo modified2 > inside/f1
84 $ hg manifest --debug
84 $ hg manifest --debug
85 4d6a634d5ba06331a60c29ee0db8412490a54fcd 644 inside/f1
85 4d6a634d5ba06331a60c29ee0db8412490a54fcd 644 inside/f1
86 7fb3bb6356d28d4dc352c5ba52d7350a81b6bd46 644 outside/f1 (flat !)
86 7fb3bb6356d28d4dc352c5ba52d7350a81b6bd46 644 outside/f1 (flat !)
87 d0f2f706468ab0e8bec7af87446835fb1b13511b 755 d outside/ (tree !)
87 d0f2f706468ab0e8bec7af87446835fb1b13511b 755 d outside/ (tree !)
88 $ hg commit -m 'modify inside/f1'
88 $ hg commit -m 'modify inside/f1'
89 created new head
89 created new head
90 $ hg files -r .
90 $ hg files -r .
91 inside/f1
91 inside/f1
92 outside/f1 (flat !)
92 outside/f1 (flat !)
93 outside/ (tree !)
93 outside/ (tree !)
94 $ hg manifest --debug
94 $ hg manifest --debug
95 3f4197b4a11b9016e77ebc47fe566944885fd11b 644 inside/f1
95 3f4197b4a11b9016e77ebc47fe566944885fd11b 644 inside/f1
96 7fb3bb6356d28d4dc352c5ba52d7350a81b6bd46 644 outside/f1 (flat !)
96 7fb3bb6356d28d4dc352c5ba52d7350a81b6bd46 644 outside/f1 (flat !)
97 d0f2f706468ab0e8bec7af87446835fb1b13511b 755 d outside/ (tree !)
97 d0f2f706468ab0e8bec7af87446835fb1b13511b 755 d outside/ (tree !)
98 Some filesystems (notably FAT/exFAT only store timestamps with 2
98 Some filesystems (notably FAT/exFAT only store timestamps with 2
99 seconds of precision, so by sleeping for 3 seconds, we can ensure that
99 seconds of precision, so by sleeping for 3 seconds, we can ensure that
100 the timestamps of files stored by dirstate will appear older than the
100 the timestamps of files stored by dirstate will appear older than the
101 dirstate file, and therefore we'll be able to get stable output from
101 dirstate file, and therefore we'll be able to get stable output from
102 debugdirstate. If we don't do this, the test can be slightly flaky.
102 debugdirstate. If we don't do this, the test can be slightly flaky.
103 $ sleep 3
103 $ sleep 3
104 $ hg status
104 $ hg status
105 $ hg debugdirstate --nodates
105 $ hg debugdirstate --nodates
106 n 644 10 set inside/f1
106 n 644 10 set inside/f1
@@ -1,532 +1,532 b''
1 $ hg init t
1 $ hg init t
2 $ cd t
2 $ cd t
3 $ mkdir -p beans
3 $ mkdir -p beans
4 $ for b in kidney navy turtle borlotti black pinto; do
4 $ for b in kidney navy turtle borlotti black pinto; do
5 > echo $b > beans/$b
5 > echo $b > beans/$b
6 > done
6 > done
7 $ mkdir -p mammals/Procyonidae
7 $ mkdir -p mammals/Procyonidae
8 $ for m in cacomistle coatimundi raccoon; do
8 $ for m in cacomistle coatimundi raccoon; do
9 > echo $m > mammals/Procyonidae/$m
9 > echo $m > mammals/Procyonidae/$m
10 > done
10 > done
11 $ echo skunk > mammals/skunk
11 $ echo skunk > mammals/skunk
12 $ echo fennel > fennel
12 $ echo fennel > fennel
13 $ echo fenugreek > fenugreek
13 $ echo fenugreek > fenugreek
14 $ echo fiddlehead > fiddlehead
14 $ echo fiddlehead > fiddlehead
15 $ hg addremove
15 $ hg addremove
16 adding beans/black
16 adding beans/black
17 adding beans/borlotti
17 adding beans/borlotti
18 adding beans/kidney
18 adding beans/kidney
19 adding beans/navy
19 adding beans/navy
20 adding beans/pinto
20 adding beans/pinto
21 adding beans/turtle
21 adding beans/turtle
22 adding fennel
22 adding fennel
23 adding fenugreek
23 adding fenugreek
24 adding fiddlehead
24 adding fiddlehead
25 adding mammals/Procyonidae/cacomistle
25 adding mammals/Procyonidae/cacomistle
26 adding mammals/Procyonidae/coatimundi
26 adding mammals/Procyonidae/coatimundi
27 adding mammals/Procyonidae/raccoon
27 adding mammals/Procyonidae/raccoon
28 adding mammals/skunk
28 adding mammals/skunk
29 $ hg commit -m "commit #0"
29 $ hg commit -m "commit #0"
30
30
31 $ hg debugwalk
31 $ hg debugwalk -v
32 matcher: <alwaysmatcher>
32 matcher: <alwaysmatcher>
33 f beans/black beans/black
33 f beans/black beans/black
34 f beans/borlotti beans/borlotti
34 f beans/borlotti beans/borlotti
35 f beans/kidney beans/kidney
35 f beans/kidney beans/kidney
36 f beans/navy beans/navy
36 f beans/navy beans/navy
37 f beans/pinto beans/pinto
37 f beans/pinto beans/pinto
38 f beans/turtle beans/turtle
38 f beans/turtle beans/turtle
39 f fennel fennel
39 f fennel fennel
40 f fenugreek fenugreek
40 f fenugreek fenugreek
41 f fiddlehead fiddlehead
41 f fiddlehead fiddlehead
42 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
42 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
43 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
43 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
44 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
44 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
45 f mammals/skunk mammals/skunk
45 f mammals/skunk mammals/skunk
46 $ hg debugwalk -I.
46 $ hg debugwalk -v -I.
47 matcher: <includematcher includes='(?:)'>
47 matcher: <includematcher includes='(?:)'>
48 f beans/black beans/black
48 f beans/black beans/black
49 f beans/borlotti beans/borlotti
49 f beans/borlotti beans/borlotti
50 f beans/kidney beans/kidney
50 f beans/kidney beans/kidney
51 f beans/navy beans/navy
51 f beans/navy beans/navy
52 f beans/pinto beans/pinto
52 f beans/pinto beans/pinto
53 f beans/turtle beans/turtle
53 f beans/turtle beans/turtle
54 f fennel fennel
54 f fennel fennel
55 f fenugreek fenugreek
55 f fenugreek fenugreek
56 f fiddlehead fiddlehead
56 f fiddlehead fiddlehead
57 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
57 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
58 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
58 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
59 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
59 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
60 f mammals/skunk mammals/skunk
60 f mammals/skunk mammals/skunk
61
61
62 $ cd mammals
62 $ cd mammals
63 $ hg debugwalk
63 $ hg debugwalk -v
64 matcher: <alwaysmatcher>
64 matcher: <alwaysmatcher>
65 f beans/black ../beans/black
65 f beans/black ../beans/black
66 f beans/borlotti ../beans/borlotti
66 f beans/borlotti ../beans/borlotti
67 f beans/kidney ../beans/kidney
67 f beans/kidney ../beans/kidney
68 f beans/navy ../beans/navy
68 f beans/navy ../beans/navy
69 f beans/pinto ../beans/pinto
69 f beans/pinto ../beans/pinto
70 f beans/turtle ../beans/turtle
70 f beans/turtle ../beans/turtle
71 f fennel ../fennel
71 f fennel ../fennel
72 f fenugreek ../fenugreek
72 f fenugreek ../fenugreek
73 f fiddlehead ../fiddlehead
73 f fiddlehead ../fiddlehead
74 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
74 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
75 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
75 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
76 f mammals/Procyonidae/raccoon Procyonidae/raccoon
76 f mammals/Procyonidae/raccoon Procyonidae/raccoon
77 f mammals/skunk skunk
77 f mammals/skunk skunk
78 $ hg debugwalk -X ../beans
78 $ hg debugwalk -v -X ../beans
79 matcher: <differencematcher m1=<alwaysmatcher>, m2=<includematcher includes='(?:beans(?:/|$))'>>
79 matcher: <differencematcher m1=<alwaysmatcher>, m2=<includematcher includes='(?:beans(?:/|$))'>>
80 f fennel ../fennel
80 f fennel ../fennel
81 f fenugreek ../fenugreek
81 f fenugreek ../fenugreek
82 f fiddlehead ../fiddlehead
82 f fiddlehead ../fiddlehead
83 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
83 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
84 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
84 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
85 f mammals/Procyonidae/raccoon Procyonidae/raccoon
85 f mammals/Procyonidae/raccoon Procyonidae/raccoon
86 f mammals/skunk skunk
86 f mammals/skunk skunk
87 $ hg debugwalk -I '*k'
87 $ hg debugwalk -v -I '*k'
88 matcher: <includematcher includes='(?:mammals\\/[^/]*k(?:/|$))'>
88 matcher: <includematcher includes='(?:mammals\\/[^/]*k(?:/|$))'>
89 f mammals/skunk skunk
89 f mammals/skunk skunk
90 $ hg debugwalk -I 'glob:*k'
90 $ hg debugwalk -v -I 'glob:*k'
91 matcher: <includematcher includes='(?:mammals\\/[^/]*k(?:/|$))'>
91 matcher: <includematcher includes='(?:mammals\\/[^/]*k(?:/|$))'>
92 f mammals/skunk skunk
92 f mammals/skunk skunk
93 $ hg debugwalk -I 'relglob:*k'
93 $ hg debugwalk -v -I 'relglob:*k'
94 matcher: <includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>
94 matcher: <includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>
95 f beans/black ../beans/black
95 f beans/black ../beans/black
96 f fenugreek ../fenugreek
96 f fenugreek ../fenugreek
97 f mammals/skunk skunk
97 f mammals/skunk skunk
98 $ hg debugwalk -I 'relglob:*k' .
98 $ hg debugwalk -v -I 'relglob:*k' .
99 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:mammals(?:/|$))'>, m2=<includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>>
99 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:mammals(?:/|$))'>, m2=<includematcher includes='(?:(?:|.*/)[^/]*k(?:/|$))'>>
100 f mammals/skunk skunk
100 f mammals/skunk skunk
101 $ hg debugwalk -I 're:.*k$'
101 $ hg debugwalk -v -I 're:.*k$'
102 matcher: <includematcher includes='(?:.*k$)'>
102 matcher: <includematcher includes='(?:.*k$)'>
103 f beans/black ../beans/black
103 f beans/black ../beans/black
104 f fenugreek ../fenugreek
104 f fenugreek ../fenugreek
105 f mammals/skunk skunk
105 f mammals/skunk skunk
106 $ hg debugwalk -I 'relre:.*k$'
106 $ hg debugwalk -v -I 'relre:.*k$'
107 matcher: <includematcher includes='(?:.*.*k$)'>
107 matcher: <includematcher includes='(?:.*.*k$)'>
108 f beans/black ../beans/black
108 f beans/black ../beans/black
109 f fenugreek ../fenugreek
109 f fenugreek ../fenugreek
110 f mammals/skunk skunk
110 f mammals/skunk skunk
111 $ hg debugwalk -I 'path:beans'
111 $ hg debugwalk -v -I 'path:beans'
112 matcher: <includematcher includes='(?:beans(?:/|$))'>
112 matcher: <includematcher includes='(?:beans(?:/|$))'>
113 f beans/black ../beans/black
113 f beans/black ../beans/black
114 f beans/borlotti ../beans/borlotti
114 f beans/borlotti ../beans/borlotti
115 f beans/kidney ../beans/kidney
115 f beans/kidney ../beans/kidney
116 f beans/navy ../beans/navy
116 f beans/navy ../beans/navy
117 f beans/pinto ../beans/pinto
117 f beans/pinto ../beans/pinto
118 f beans/turtle ../beans/turtle
118 f beans/turtle ../beans/turtle
119 $ hg debugwalk -I 'relpath:detour/../../beans'
119 $ hg debugwalk -v -I 'relpath:detour/../../beans'
120 matcher: <includematcher includes='(?:beans(?:/|$))'>
120 matcher: <includematcher includes='(?:beans(?:/|$))'>
121 f beans/black ../beans/black
121 f beans/black ../beans/black
122 f beans/borlotti ../beans/borlotti
122 f beans/borlotti ../beans/borlotti
123 f beans/kidney ../beans/kidney
123 f beans/kidney ../beans/kidney
124 f beans/navy ../beans/navy
124 f beans/navy ../beans/navy
125 f beans/pinto ../beans/pinto
125 f beans/pinto ../beans/pinto
126 f beans/turtle ../beans/turtle
126 f beans/turtle ../beans/turtle
127
127
128 $ hg debugwalk 'rootfilesin:'
128 $ hg debugwalk -v 'rootfilesin:'
129 matcher: <patternmatcher patterns='(?:[^/]+$)'>
129 matcher: <patternmatcher patterns='(?:[^/]+$)'>
130 f fennel ../fennel
130 f fennel ../fennel
131 f fenugreek ../fenugreek
131 f fenugreek ../fenugreek
132 f fiddlehead ../fiddlehead
132 f fiddlehead ../fiddlehead
133 $ hg debugwalk -I 'rootfilesin:'
133 $ hg debugwalk -v -I 'rootfilesin:'
134 matcher: <includematcher includes='(?:[^/]+$)'>
134 matcher: <includematcher includes='(?:[^/]+$)'>
135 f fennel ../fennel
135 f fennel ../fennel
136 f fenugreek ../fenugreek
136 f fenugreek ../fenugreek
137 f fiddlehead ../fiddlehead
137 f fiddlehead ../fiddlehead
138 $ hg debugwalk 'rootfilesin:.'
138 $ hg debugwalk -v 'rootfilesin:.'
139 matcher: <patternmatcher patterns='(?:[^/]+$)'>
139 matcher: <patternmatcher patterns='(?:[^/]+$)'>
140 f fennel ../fennel
140 f fennel ../fennel
141 f fenugreek ../fenugreek
141 f fenugreek ../fenugreek
142 f fiddlehead ../fiddlehead
142 f fiddlehead ../fiddlehead
143 $ hg debugwalk -I 'rootfilesin:.'
143 $ hg debugwalk -v -I 'rootfilesin:.'
144 matcher: <includematcher includes='(?:[^/]+$)'>
144 matcher: <includematcher includes='(?:[^/]+$)'>
145 f fennel ../fennel
145 f fennel ../fennel
146 f fenugreek ../fenugreek
146 f fenugreek ../fenugreek
147 f fiddlehead ../fiddlehead
147 f fiddlehead ../fiddlehead
148 $ hg debugwalk -X 'rootfilesin:'
148 $ hg debugwalk -v -X 'rootfilesin:'
149 matcher: <differencematcher m1=<alwaysmatcher>, m2=<includematcher includes='(?:[^/]+$)'>>
149 matcher: <differencematcher m1=<alwaysmatcher>, m2=<includematcher includes='(?:[^/]+$)'>>
150 f beans/black ../beans/black
150 f beans/black ../beans/black
151 f beans/borlotti ../beans/borlotti
151 f beans/borlotti ../beans/borlotti
152 f beans/kidney ../beans/kidney
152 f beans/kidney ../beans/kidney
153 f beans/navy ../beans/navy
153 f beans/navy ../beans/navy
154 f beans/pinto ../beans/pinto
154 f beans/pinto ../beans/pinto
155 f beans/turtle ../beans/turtle
155 f beans/turtle ../beans/turtle
156 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
156 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
157 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
157 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
158 f mammals/Procyonidae/raccoon Procyonidae/raccoon
158 f mammals/Procyonidae/raccoon Procyonidae/raccoon
159 f mammals/skunk skunk
159 f mammals/skunk skunk
160 $ hg debugwalk 'rootfilesin:fennel'
160 $ hg debugwalk -v 'rootfilesin:fennel'
161 matcher: <patternmatcher patterns='(?:fennel/[^/]+$)'>
161 matcher: <patternmatcher patterns='(?:fennel/[^/]+$)'>
162 $ hg debugwalk -I 'rootfilesin:fennel'
162 $ hg debugwalk -v -I 'rootfilesin:fennel'
163 matcher: <includematcher includes='(?:fennel/[^/]+$)'>
163 matcher: <includematcher includes='(?:fennel/[^/]+$)'>
164 $ hg debugwalk 'rootfilesin:skunk'
164 $ hg debugwalk -v 'rootfilesin:skunk'
165 matcher: <patternmatcher patterns='(?:skunk/[^/]+$)'>
165 matcher: <patternmatcher patterns='(?:skunk/[^/]+$)'>
166 $ hg debugwalk -I 'rootfilesin:skunk'
166 $ hg debugwalk -v -I 'rootfilesin:skunk'
167 matcher: <includematcher includes='(?:skunk/[^/]+$)'>
167 matcher: <includematcher includes='(?:skunk/[^/]+$)'>
168 $ hg debugwalk 'rootfilesin:beans'
168 $ hg debugwalk -v 'rootfilesin:beans'
169 matcher: <patternmatcher patterns='(?:beans/[^/]+$)'>
169 matcher: <patternmatcher patterns='(?:beans/[^/]+$)'>
170 f beans/black ../beans/black
170 f beans/black ../beans/black
171 f beans/borlotti ../beans/borlotti
171 f beans/borlotti ../beans/borlotti
172 f beans/kidney ../beans/kidney
172 f beans/kidney ../beans/kidney
173 f beans/navy ../beans/navy
173 f beans/navy ../beans/navy
174 f beans/pinto ../beans/pinto
174 f beans/pinto ../beans/pinto
175 f beans/turtle ../beans/turtle
175 f beans/turtle ../beans/turtle
176 $ hg debugwalk -I 'rootfilesin:beans'
176 $ hg debugwalk -v -I 'rootfilesin:beans'
177 matcher: <includematcher includes='(?:beans/[^/]+$)'>
177 matcher: <includematcher includes='(?:beans/[^/]+$)'>
178 f beans/black ../beans/black
178 f beans/black ../beans/black
179 f beans/borlotti ../beans/borlotti
179 f beans/borlotti ../beans/borlotti
180 f beans/kidney ../beans/kidney
180 f beans/kidney ../beans/kidney
181 f beans/navy ../beans/navy
181 f beans/navy ../beans/navy
182 f beans/pinto ../beans/pinto
182 f beans/pinto ../beans/pinto
183 f beans/turtle ../beans/turtle
183 f beans/turtle ../beans/turtle
184 $ hg debugwalk 'rootfilesin:mammals'
184 $ hg debugwalk -v 'rootfilesin:mammals'
185 matcher: <patternmatcher patterns='(?:mammals/[^/]+$)'>
185 matcher: <patternmatcher patterns='(?:mammals/[^/]+$)'>
186 f mammals/skunk skunk
186 f mammals/skunk skunk
187 $ hg debugwalk -I 'rootfilesin:mammals'
187 $ hg debugwalk -v -I 'rootfilesin:mammals'
188 matcher: <includematcher includes='(?:mammals/[^/]+$)'>
188 matcher: <includematcher includes='(?:mammals/[^/]+$)'>
189 f mammals/skunk skunk
189 f mammals/skunk skunk
190 $ hg debugwalk 'rootfilesin:mammals/'
190 $ hg debugwalk -v 'rootfilesin:mammals/'
191 matcher: <patternmatcher patterns='(?:mammals/[^/]+$)'>
191 matcher: <patternmatcher patterns='(?:mammals/[^/]+$)'>
192 f mammals/skunk skunk
192 f mammals/skunk skunk
193 $ hg debugwalk -I 'rootfilesin:mammals/'
193 $ hg debugwalk -v -I 'rootfilesin:mammals/'
194 matcher: <includematcher includes='(?:mammals/[^/]+$)'>
194 matcher: <includematcher includes='(?:mammals/[^/]+$)'>
195 f mammals/skunk skunk
195 f mammals/skunk skunk
196 $ hg debugwalk -X 'rootfilesin:mammals'
196 $ hg debugwalk -v -X 'rootfilesin:mammals'
197 matcher: <differencematcher m1=<alwaysmatcher>, m2=<includematcher includes='(?:mammals/[^/]+$)'>>
197 matcher: <differencematcher m1=<alwaysmatcher>, m2=<includematcher includes='(?:mammals/[^/]+$)'>>
198 f beans/black ../beans/black
198 f beans/black ../beans/black
199 f beans/borlotti ../beans/borlotti
199 f beans/borlotti ../beans/borlotti
200 f beans/kidney ../beans/kidney
200 f beans/kidney ../beans/kidney
201 f beans/navy ../beans/navy
201 f beans/navy ../beans/navy
202 f beans/pinto ../beans/pinto
202 f beans/pinto ../beans/pinto
203 f beans/turtle ../beans/turtle
203 f beans/turtle ../beans/turtle
204 f fennel ../fennel
204 f fennel ../fennel
205 f fenugreek ../fenugreek
205 f fenugreek ../fenugreek
206 f fiddlehead ../fiddlehead
206 f fiddlehead ../fiddlehead
207 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
207 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
208 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
208 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
209 f mammals/Procyonidae/raccoon Procyonidae/raccoon
209 f mammals/Procyonidae/raccoon Procyonidae/raccoon
210
210
211 $ hg debugwalk .
211 $ hg debugwalk -v .
212 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
212 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
213 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
213 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
214 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
214 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
215 f mammals/Procyonidae/raccoon Procyonidae/raccoon
215 f mammals/Procyonidae/raccoon Procyonidae/raccoon
216 f mammals/skunk skunk
216 f mammals/skunk skunk
217 $ hg debugwalk -I.
217 $ hg debugwalk -v -I.
218 matcher: <includematcher includes='(?:mammals(?:/|$))'>
218 matcher: <includematcher includes='(?:mammals(?:/|$))'>
219 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
219 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
220 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
220 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
221 f mammals/Procyonidae/raccoon Procyonidae/raccoon
221 f mammals/Procyonidae/raccoon Procyonidae/raccoon
222 f mammals/skunk skunk
222 f mammals/skunk skunk
223 $ hg debugwalk Procyonidae
223 $ hg debugwalk -v Procyonidae
224 matcher: <patternmatcher patterns='(?:mammals\\/Procyonidae(?:/|$))'>
224 matcher: <patternmatcher patterns='(?:mammals\\/Procyonidae(?:/|$))'>
225 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
225 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
226 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
226 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
227 f mammals/Procyonidae/raccoon Procyonidae/raccoon
227 f mammals/Procyonidae/raccoon Procyonidae/raccoon
228
228
229 $ cd Procyonidae
229 $ cd Procyonidae
230 $ hg debugwalk .
230 $ hg debugwalk -v .
231 matcher: <patternmatcher patterns='(?:mammals\\/Procyonidae(?:/|$))'>
231 matcher: <patternmatcher patterns='(?:mammals\\/Procyonidae(?:/|$))'>
232 f mammals/Procyonidae/cacomistle cacomistle
232 f mammals/Procyonidae/cacomistle cacomistle
233 f mammals/Procyonidae/coatimundi coatimundi
233 f mammals/Procyonidae/coatimundi coatimundi
234 f mammals/Procyonidae/raccoon raccoon
234 f mammals/Procyonidae/raccoon raccoon
235 $ hg debugwalk ..
235 $ hg debugwalk -v ..
236 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
236 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
237 f mammals/Procyonidae/cacomistle cacomistle
237 f mammals/Procyonidae/cacomistle cacomistle
238 f mammals/Procyonidae/coatimundi coatimundi
238 f mammals/Procyonidae/coatimundi coatimundi
239 f mammals/Procyonidae/raccoon raccoon
239 f mammals/Procyonidae/raccoon raccoon
240 f mammals/skunk ../skunk
240 f mammals/skunk ../skunk
241 $ cd ..
241 $ cd ..
242
242
243 $ hg debugwalk ../beans
243 $ hg debugwalk -v ../beans
244 matcher: <patternmatcher patterns='(?:beans(?:/|$))'>
244 matcher: <patternmatcher patterns='(?:beans(?:/|$))'>
245 f beans/black ../beans/black
245 f beans/black ../beans/black
246 f beans/borlotti ../beans/borlotti
246 f beans/borlotti ../beans/borlotti
247 f beans/kidney ../beans/kidney
247 f beans/kidney ../beans/kidney
248 f beans/navy ../beans/navy
248 f beans/navy ../beans/navy
249 f beans/pinto ../beans/pinto
249 f beans/pinto ../beans/pinto
250 f beans/turtle ../beans/turtle
250 f beans/turtle ../beans/turtle
251 $ hg debugwalk .
251 $ hg debugwalk -v .
252 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
252 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
253 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
253 f mammals/Procyonidae/cacomistle Procyonidae/cacomistle
254 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
254 f mammals/Procyonidae/coatimundi Procyonidae/coatimundi
255 f mammals/Procyonidae/raccoon Procyonidae/raccoon
255 f mammals/Procyonidae/raccoon Procyonidae/raccoon
256 f mammals/skunk skunk
256 f mammals/skunk skunk
257 $ hg debugwalk .hg
257 $ hg debugwalk -v .hg
258 abort: path 'mammals/.hg' is inside nested repo 'mammals'
258 abort: path 'mammals/.hg' is inside nested repo 'mammals'
259 [255]
259 [255]
260 $ hg debugwalk ../.hg
260 $ hg debugwalk -v ../.hg
261 abort: path contains illegal component: .hg
261 abort: path contains illegal component: .hg
262 [255]
262 [255]
263 $ cd ..
263 $ cd ..
264
264
265 $ hg debugwalk -Ibeans
265 $ hg debugwalk -v -Ibeans
266 matcher: <includematcher includes='(?:beans(?:/|$))'>
266 matcher: <includematcher includes='(?:beans(?:/|$))'>
267 f beans/black beans/black
267 f beans/black beans/black
268 f beans/borlotti beans/borlotti
268 f beans/borlotti beans/borlotti
269 f beans/kidney beans/kidney
269 f beans/kidney beans/kidney
270 f beans/navy beans/navy
270 f beans/navy beans/navy
271 f beans/pinto beans/pinto
271 f beans/pinto beans/pinto
272 f beans/turtle beans/turtle
272 f beans/turtle beans/turtle
273 $ hg debugwalk -I '{*,{b,m}*/*}k'
273 $ hg debugwalk -v -I '{*,{b,m}*/*}k'
274 matcher: <includematcher includes='(?:(?:[^/]*|(?:b|m)[^/]*\\/[^/]*)k(?:/|$))'>
274 matcher: <includematcher includes='(?:(?:[^/]*|(?:b|m)[^/]*\\/[^/]*)k(?:/|$))'>
275 f beans/black beans/black
275 f beans/black beans/black
276 f fenugreek fenugreek
276 f fenugreek fenugreek
277 f mammals/skunk mammals/skunk
277 f mammals/skunk mammals/skunk
278 $ hg debugwalk -Ibeans mammals
278 $ hg debugwalk -v -Ibeans mammals
279 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:mammals(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
279 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:mammals(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
280 $ hg debugwalk -Inon-existent
280 $ hg debugwalk -v -Inon-existent
281 matcher: <includematcher includes='(?:non\\-existent(?:/|$))'>
281 matcher: <includematcher includes='(?:non\\-existent(?:/|$))'>
282 $ hg debugwalk -Inon-existent -Ibeans/black
282 $ hg debugwalk -v -Inon-existent -Ibeans/black
283 matcher: <includematcher includes='(?:non\\-existent(?:/|$)|beans\\/black(?:/|$))'>
283 matcher: <includematcher includes='(?:non\\-existent(?:/|$)|beans\\/black(?:/|$))'>
284 f beans/black beans/black
284 f beans/black beans/black
285 $ hg debugwalk -Ibeans beans/black
285 $ hg debugwalk -v -Ibeans beans/black
286 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
286 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
287 f beans/black beans/black exact
287 f beans/black beans/black exact
288 $ hg debugwalk -Ibeans/black beans
288 $ hg debugwalk -v -Ibeans/black beans
289 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:beans(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
289 matcher: <intersectionmatcher m1=<patternmatcher patterns='(?:beans(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
290 f beans/black beans/black
290 f beans/black beans/black
291 $ hg debugwalk -Xbeans/black beans
291 $ hg debugwalk -v -Xbeans/black beans
292 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
292 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
293 f beans/borlotti beans/borlotti
293 f beans/borlotti beans/borlotti
294 f beans/kidney beans/kidney
294 f beans/kidney beans/kidney
295 f beans/navy beans/navy
295 f beans/navy beans/navy
296 f beans/pinto beans/pinto
296 f beans/pinto beans/pinto
297 f beans/turtle beans/turtle
297 f beans/turtle beans/turtle
298 $ hg debugwalk -Xbeans/black -Ibeans
298 $ hg debugwalk -v -Xbeans/black -Ibeans
299 matcher: <differencematcher m1=<includematcher includes='(?:beans(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
299 matcher: <differencematcher m1=<includematcher includes='(?:beans(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
300 f beans/borlotti beans/borlotti
300 f beans/borlotti beans/borlotti
301 f beans/kidney beans/kidney
301 f beans/kidney beans/kidney
302 f beans/navy beans/navy
302 f beans/navy beans/navy
303 f beans/pinto beans/pinto
303 f beans/pinto beans/pinto
304 f beans/turtle beans/turtle
304 f beans/turtle beans/turtle
305 $ hg debugwalk -Xbeans/black beans/black
305 $ hg debugwalk -v -Xbeans/black beans/black
306 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
306 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
307 $ hg debugwalk -Xbeans/black -Ibeans/black
307 $ hg debugwalk -v -Xbeans/black -Ibeans/black
308 matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
308 matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans\\/black(?:/|$))'>>
309 $ hg debugwalk -Xbeans beans/black
309 $ hg debugwalk -v -Xbeans beans/black
310 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
310 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
311 $ hg debugwalk -Xbeans -Ibeans/black
311 $ hg debugwalk -v -Xbeans -Ibeans/black
312 matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
312 matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
313 $ hg debugwalk 'glob:mammals/../beans/b*'
313 $ hg debugwalk -v 'glob:mammals/../beans/b*'
314 matcher: <patternmatcher patterns='(?:beans\\/b[^/]*$)'>
314 matcher: <patternmatcher patterns='(?:beans\\/b[^/]*$)'>
315 f beans/black beans/black
315 f beans/black beans/black
316 f beans/borlotti beans/borlotti
316 f beans/borlotti beans/borlotti
317 $ hg debugwalk '-X*/Procyonidae' mammals
317 $ hg debugwalk -v '-X*/Procyonidae' mammals
318 matcher: <differencematcher m1=<patternmatcher patterns='(?:mammals(?:/|$))'>, m2=<includematcher includes='(?:[^/]*\\/Procyonidae(?:/|$))'>>
318 matcher: <differencematcher m1=<patternmatcher patterns='(?:mammals(?:/|$))'>, m2=<includematcher includes='(?:[^/]*\\/Procyonidae(?:/|$))'>>
319 f mammals/skunk mammals/skunk
319 f mammals/skunk mammals/skunk
320 $ hg debugwalk path:mammals
320 $ hg debugwalk -v path:mammals
321 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
321 matcher: <patternmatcher patterns='(?:mammals(?:/|$))'>
322 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
322 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
323 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
323 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
324 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
324 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
325 f mammals/skunk mammals/skunk
325 f mammals/skunk mammals/skunk
326 $ hg debugwalk ..
326 $ hg debugwalk -v ..
327 abort: .. not under root '$TESTTMP/t'
327 abort: .. not under root '$TESTTMP/t'
328 [255]
328 [255]
329 $ hg debugwalk beans/../..
329 $ hg debugwalk -v beans/../..
330 abort: beans/../.. not under root '$TESTTMP/t'
330 abort: beans/../.. not under root '$TESTTMP/t'
331 [255]
331 [255]
332 $ hg debugwalk .hg
332 $ hg debugwalk -v .hg
333 abort: path contains illegal component: .hg
333 abort: path contains illegal component: .hg
334 [255]
334 [255]
335 $ hg debugwalk beans/../.hg
335 $ hg debugwalk -v beans/../.hg
336 abort: path contains illegal component: .hg
336 abort: path contains illegal component: .hg
337 [255]
337 [255]
338 $ hg debugwalk beans/../.hg/data
338 $ hg debugwalk -v beans/../.hg/data
339 abort: path contains illegal component: .hg/data
339 abort: path contains illegal component: .hg/data
340 [255]
340 [255]
341 $ hg debugwalk beans/.hg
341 $ hg debugwalk -v beans/.hg
342 abort: path 'beans/.hg' is inside nested repo 'beans'
342 abort: path 'beans/.hg' is inside nested repo 'beans'
343 [255]
343 [255]
344
344
345 Test explicit paths and excludes:
345 Test explicit paths and excludes:
346
346
347 $ hg debugwalk fennel -X fennel
347 $ hg debugwalk -v fennel -X fennel
348 matcher: <differencematcher m1=<patternmatcher patterns='(?:fennel(?:/|$))'>, m2=<includematcher includes='(?:fennel(?:/|$))'>>
348 matcher: <differencematcher m1=<patternmatcher patterns='(?:fennel(?:/|$))'>, m2=<includematcher includes='(?:fennel(?:/|$))'>>
349 $ hg debugwalk fennel -X 'f*'
349 $ hg debugwalk -v fennel -X 'f*'
350 matcher: <differencematcher m1=<patternmatcher patterns='(?:fennel(?:/|$))'>, m2=<includematcher includes='(?:f[^/]*(?:/|$))'>>
350 matcher: <differencematcher m1=<patternmatcher patterns='(?:fennel(?:/|$))'>, m2=<includematcher includes='(?:f[^/]*(?:/|$))'>>
351 $ hg debugwalk beans/black -X 'path:beans'
351 $ hg debugwalk -v beans/black -X 'path:beans'
352 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
352 matcher: <differencematcher m1=<patternmatcher patterns='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
353 $ hg debugwalk -I 'path:beans/black' -X 'path:beans'
353 $ hg debugwalk -v -I 'path:beans/black' -X 'path:beans'
354 matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
354 matcher: <differencematcher m1=<includematcher includes='(?:beans\\/black(?:/|$))'>, m2=<includematcher includes='(?:beans(?:/|$))'>>
355
355
356 Test absolute paths:
356 Test absolute paths:
357
357
358 $ hg debugwalk `pwd`/beans
358 $ hg debugwalk -v `pwd`/beans
359 matcher: <patternmatcher patterns='(?:beans(?:/|$))'>
359 matcher: <patternmatcher patterns='(?:beans(?:/|$))'>
360 f beans/black beans/black
360 f beans/black beans/black
361 f beans/borlotti beans/borlotti
361 f beans/borlotti beans/borlotti
362 f beans/kidney beans/kidney
362 f beans/kidney beans/kidney
363 f beans/navy beans/navy
363 f beans/navy beans/navy
364 f beans/pinto beans/pinto
364 f beans/pinto beans/pinto
365 f beans/turtle beans/turtle
365 f beans/turtle beans/turtle
366 $ hg debugwalk `pwd`/..
366 $ hg debugwalk -v `pwd`/..
367 abort: $TESTTMP/t/.. not under root '$TESTTMP/t'
367 abort: $TESTTMP/t/.. not under root '$TESTTMP/t'
368 [255]
368 [255]
369
369
370 Test patterns:
370 Test patterns:
371
371
372 $ hg debugwalk glob:\*
372 $ hg debugwalk -v glob:\*
373 matcher: <patternmatcher patterns='(?:[^/]*$)'>
373 matcher: <patternmatcher patterns='(?:[^/]*$)'>
374 f fennel fennel
374 f fennel fennel
375 f fenugreek fenugreek
375 f fenugreek fenugreek
376 f fiddlehead fiddlehead
376 f fiddlehead fiddlehead
377 #if eol-in-paths
377 #if eol-in-paths
378 $ echo glob:glob > glob:glob
378 $ echo glob:glob > glob:glob
379 $ hg addremove
379 $ hg addremove
380 adding glob:glob
380 adding glob:glob
381 warning: filename contains ':', which is reserved on Windows: 'glob:glob'
381 warning: filename contains ':', which is reserved on Windows: 'glob:glob'
382 $ hg debugwalk glob:\*
382 $ hg debugwalk -v glob:\*
383 matcher: <patternmatcher patterns='(?:[^/]*$)'>
383 matcher: <patternmatcher patterns='(?:[^/]*$)'>
384 f fennel fennel
384 f fennel fennel
385 f fenugreek fenugreek
385 f fenugreek fenugreek
386 f fiddlehead fiddlehead
386 f fiddlehead fiddlehead
387 f glob:glob glob:glob
387 f glob:glob glob:glob
388 $ hg debugwalk glob:glob
388 $ hg debugwalk -v glob:glob
389 matcher: <patternmatcher patterns='(?:glob$)'>
389 matcher: <patternmatcher patterns='(?:glob$)'>
390 glob: $ENOENT$
390 glob: $ENOENT$
391 $ hg debugwalk glob:glob:glob
391 $ hg debugwalk -v glob:glob:glob
392 matcher: <patternmatcher patterns='(?:glob\\:glob$)'>
392 matcher: <patternmatcher patterns='(?:glob\\:glob$)'>
393 f glob:glob glob:glob exact
393 f glob:glob glob:glob exact
394 $ hg debugwalk path:glob:glob
394 $ hg debugwalk -v path:glob:glob
395 matcher: <patternmatcher patterns='(?:glob\\:glob(?:/|$))'>
395 matcher: <patternmatcher patterns='(?:glob\\:glob(?:/|$))'>
396 f glob:glob glob:glob exact
396 f glob:glob glob:glob exact
397 $ rm glob:glob
397 $ rm glob:glob
398 $ hg addremove
398 $ hg addremove
399 removing glob:glob
399 removing glob:glob
400 #endif
400 #endif
401
401
402 $ hg debugwalk 'glob:**e'
402 $ hg debugwalk -v 'glob:**e'
403 matcher: <patternmatcher patterns='(?:.*e$)'>
403 matcher: <patternmatcher patterns='(?:.*e$)'>
404 f beans/turtle beans/turtle
404 f beans/turtle beans/turtle
405 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
405 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
406
406
407 $ hg debugwalk 're:.*[kb]$'
407 $ hg debugwalk -v 're:.*[kb]$'
408 matcher: <patternmatcher patterns='(?:.*[kb]$)'>
408 matcher: <patternmatcher patterns='(?:.*[kb]$)'>
409 f beans/black beans/black
409 f beans/black beans/black
410 f fenugreek fenugreek
410 f fenugreek fenugreek
411 f mammals/skunk mammals/skunk
411 f mammals/skunk mammals/skunk
412
412
413 $ hg debugwalk path:beans/black
413 $ hg debugwalk -v path:beans/black
414 matcher: <patternmatcher patterns='(?:beans\\/black(?:/|$))'>
414 matcher: <patternmatcher patterns='(?:beans\\/black(?:/|$))'>
415 f beans/black beans/black exact
415 f beans/black beans/black exact
416 $ hg debugwalk path:beans//black
416 $ hg debugwalk -v path:beans//black
417 matcher: <patternmatcher patterns='(?:beans\\/black(?:/|$))'>
417 matcher: <patternmatcher patterns='(?:beans\\/black(?:/|$))'>
418 f beans/black beans/black exact
418 f beans/black beans/black exact
419
419
420 $ hg debugwalk relglob:Procyonidae
420 $ hg debugwalk -v relglob:Procyonidae
421 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae$)'>
421 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae$)'>
422 $ hg debugwalk 'relglob:Procyonidae/**'
422 $ hg debugwalk -v 'relglob:Procyonidae/**'
423 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae\\/.*$)'>
423 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae\\/.*$)'>
424 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
424 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
425 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
425 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
426 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
426 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
427 $ hg debugwalk 'relglob:Procyonidae/**' fennel
427 $ hg debugwalk -v 'relglob:Procyonidae/**' fennel
428 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae\\/.*$|fennel(?:/|$))'>
428 matcher: <patternmatcher patterns='(?:(?:|.*/)Procyonidae\\/.*$|fennel(?:/|$))'>
429 f fennel fennel exact
429 f fennel fennel exact
430 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
430 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
431 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
431 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
432 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
432 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
433 $ hg debugwalk beans 'glob:beans/*'
433 $ hg debugwalk -v beans 'glob:beans/*'
434 matcher: <patternmatcher patterns='(?:beans(?:/|$)|beans\\/[^/]*$)'>
434 matcher: <patternmatcher patterns='(?:beans(?:/|$)|beans\\/[^/]*$)'>
435 f beans/black beans/black
435 f beans/black beans/black
436 f beans/borlotti beans/borlotti
436 f beans/borlotti beans/borlotti
437 f beans/kidney beans/kidney
437 f beans/kidney beans/kidney
438 f beans/navy beans/navy
438 f beans/navy beans/navy
439 f beans/pinto beans/pinto
439 f beans/pinto beans/pinto
440 f beans/turtle beans/turtle
440 f beans/turtle beans/turtle
441 $ hg debugwalk 'glob:mamm**'
441 $ hg debugwalk -v 'glob:mamm**'
442 matcher: <patternmatcher patterns='(?:mamm.*$)'>
442 matcher: <patternmatcher patterns='(?:mamm.*$)'>
443 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
443 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
444 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
444 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
445 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
445 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
446 f mammals/skunk mammals/skunk
446 f mammals/skunk mammals/skunk
447 $ hg debugwalk 'glob:mamm**' fennel
447 $ hg debugwalk -v 'glob:mamm**' fennel
448 matcher: <patternmatcher patterns='(?:mamm.*$|fennel(?:/|$))'>
448 matcher: <patternmatcher patterns='(?:mamm.*$|fennel(?:/|$))'>
449 f fennel fennel exact
449 f fennel fennel exact
450 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
450 f mammals/Procyonidae/cacomistle mammals/Procyonidae/cacomistle
451 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
451 f mammals/Procyonidae/coatimundi mammals/Procyonidae/coatimundi
452 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
452 f mammals/Procyonidae/raccoon mammals/Procyonidae/raccoon
453 f mammals/skunk mammals/skunk
453 f mammals/skunk mammals/skunk
454 $ hg debugwalk 'glob:j*'
454 $ hg debugwalk -v 'glob:j*'
455 matcher: <patternmatcher patterns='(?:j[^/]*$)'>
455 matcher: <patternmatcher patterns='(?:j[^/]*$)'>
456 $ hg debugwalk NOEXIST
456 $ hg debugwalk -v NOEXIST
457 matcher: <patternmatcher patterns='(?:NOEXIST(?:/|$))'>
457 matcher: <patternmatcher patterns='(?:NOEXIST(?:/|$))'>
458 NOEXIST: * (glob)
458 NOEXIST: * (glob)
459
459
460 #if fifo
460 #if fifo
461 $ mkfifo fifo
461 $ mkfifo fifo
462 $ hg debugwalk fifo
462 $ hg debugwalk -v fifo
463 matcher: <patternmatcher patterns='(?:fifo(?:/|$))'>
463 matcher: <patternmatcher patterns='(?:fifo(?:/|$))'>
464 fifo: unsupported file type (type is fifo)
464 fifo: unsupported file type (type is fifo)
465 #endif
465 #endif
466
466
467 $ rm fenugreek
467 $ rm fenugreek
468 $ hg debugwalk fenugreek
468 $ hg debugwalk -v fenugreek
469 matcher: <patternmatcher patterns='(?:fenugreek(?:/|$))'>
469 matcher: <patternmatcher patterns='(?:fenugreek(?:/|$))'>
470 f fenugreek fenugreek exact
470 f fenugreek fenugreek exact
471 $ hg rm fenugreek
471 $ hg rm fenugreek
472 $ hg debugwalk fenugreek
472 $ hg debugwalk -v fenugreek
473 matcher: <patternmatcher patterns='(?:fenugreek(?:/|$))'>
473 matcher: <patternmatcher patterns='(?:fenugreek(?:/|$))'>
474 f fenugreek fenugreek exact
474 f fenugreek fenugreek exact
475 $ touch new
475 $ touch new
476 $ hg debugwalk new
476 $ hg debugwalk -v new
477 matcher: <patternmatcher patterns='(?:new(?:/|$))'>
477 matcher: <patternmatcher patterns='(?:new(?:/|$))'>
478 f new new exact
478 f new new exact
479
479
480 $ mkdir ignored
480 $ mkdir ignored
481 $ touch ignored/file
481 $ touch ignored/file
482 $ echo '^ignored$' > .hgignore
482 $ echo '^ignored$' > .hgignore
483 $ hg debugwalk ignored
483 $ hg debugwalk -v ignored
484 matcher: <patternmatcher patterns='(?:ignored(?:/|$))'>
484 matcher: <patternmatcher patterns='(?:ignored(?:/|$))'>
485 $ hg debugwalk ignored/file
485 $ hg debugwalk -v ignored/file
486 matcher: <patternmatcher patterns='(?:ignored\\/file(?:/|$))'>
486 matcher: <patternmatcher patterns='(?:ignored\\/file(?:/|$))'>
487 f ignored/file ignored/file exact
487 f ignored/file ignored/file exact
488
488
489 Test listfile and listfile0
489 Test listfile and listfile0
490
490
491 $ $PYTHON -c "open('listfile0', 'wb').write(b'fenugreek\0new\0')"
491 $ $PYTHON -c "open('listfile0', 'wb').write(b'fenugreek\0new\0')"
492 $ hg debugwalk -I 'listfile0:listfile0'
492 $ hg debugwalk -v -I 'listfile0:listfile0'
493 matcher: <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$))'>
493 matcher: <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$))'>
494 f fenugreek fenugreek
494 f fenugreek fenugreek
495 f new new
495 f new new
496 $ $PYTHON -c "open('listfile', 'wb').write(b'fenugreek\nnew\r\nmammals/skunk\n')"
496 $ $PYTHON -c "open('listfile', 'wb').write(b'fenugreek\nnew\r\nmammals/skunk\n')"
497 $ hg debugwalk -I 'listfile:listfile'
497 $ hg debugwalk -v -I 'listfile:listfile'
498 matcher: <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$)|mammals\\/skunk(?:/|$))'>
498 matcher: <includematcher includes='(?:fenugreek(?:/|$)|new(?:/|$)|mammals\\/skunk(?:/|$))'>
499 f fenugreek fenugreek
499 f fenugreek fenugreek
500 f mammals/skunk mammals/skunk
500 f mammals/skunk mammals/skunk
501 f new new
501 f new new
502
502
503 $ cd ..
503 $ cd ..
504 $ hg debugwalk -R t t/mammals/skunk
504 $ hg debugwalk -v -R t t/mammals/skunk
505 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
505 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
506 f mammals/skunk t/mammals/skunk exact
506 f mammals/skunk t/mammals/skunk exact
507 $ mkdir t2
507 $ mkdir t2
508 $ cd t2
508 $ cd t2
509 $ hg debugwalk -R ../t ../t/mammals/skunk
509 $ hg debugwalk -v -R ../t ../t/mammals/skunk
510 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
510 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
511 f mammals/skunk ../t/mammals/skunk exact
511 f mammals/skunk ../t/mammals/skunk exact
512 $ hg debugwalk --cwd ../t mammals/skunk
512 $ hg debugwalk -v --cwd ../t mammals/skunk
513 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
513 matcher: <patternmatcher patterns='(?:mammals\\/skunk(?:/|$))'>
514 f mammals/skunk mammals/skunk exact
514 f mammals/skunk mammals/skunk exact
515
515
516 $ cd ..
516 $ cd ..
517
517
518 Test split patterns on overflow
518 Test split patterns on overflow
519
519
520 $ cd t
520 $ cd t
521 $ echo fennel > overflow.list
521 $ echo fennel > overflow.list
522 $ cat >> printnum.py <<EOF
522 $ cat >> printnum.py <<EOF
523 > from __future__ import print_function
523 > from __future__ import print_function
524 > for i in range(20000 // 100):
524 > for i in range(20000 // 100):
525 > print('x' * 100)
525 > print('x' * 100)
526 > EOF
526 > EOF
527 $ $PYTHON printnum.py >> overflow.list
527 $ $PYTHON printnum.py >> overflow.list
528 $ echo fenugreek >> overflow.list
528 $ echo fenugreek >> overflow.list
529 $ hg debugwalk 'listfile:overflow.list' 2>&1 | egrep -v '(^matcher: |^xxx)'
529 $ hg debugwalk 'listfile:overflow.list' 2>&1 | egrep -v '^xxx'
530 f fennel fennel exact
530 f fennel fennel exact
531 f fenugreek fenugreek exact
531 f fenugreek fenugreek exact
532 $ cd ..
532 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now