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