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