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