##// END OF EJS Templates
debuginstall: use codecs.lookup() to detect invalid encoding...
Yuya Nishihara -
r34131:902219a9 default
parent child Browse files
Show More
@@ -1,2318 +1,2319 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 collections
11 import collections
11 import difflib
12 import difflib
12 import errno
13 import errno
13 import operator
14 import operator
14 import os
15 import os
15 import random
16 import random
16 import socket
17 import socket
17 import ssl
18 import ssl
18 import string
19 import string
19 import sys
20 import sys
20 import tempfile
21 import tempfile
21 import time
22 import time
22
23
23 from .i18n import _
24 from .i18n import _
24 from .node import (
25 from .node import (
25 bin,
26 bin,
26 hex,
27 hex,
27 nullhex,
28 nullhex,
28 nullid,
29 nullid,
29 nullrev,
30 nullrev,
30 short,
31 short,
31 )
32 )
32 from . import (
33 from . import (
33 bundle2,
34 bundle2,
34 changegroup,
35 changegroup,
35 cmdutil,
36 cmdutil,
36 color,
37 color,
37 context,
38 context,
38 dagparser,
39 dagparser,
39 dagutil,
40 dagutil,
40 encoding,
41 encoding,
41 error,
42 error,
42 exchange,
43 exchange,
43 extensions,
44 extensions,
44 filemerge,
45 filemerge,
45 fileset,
46 fileset,
46 formatter,
47 formatter,
47 hg,
48 hg,
48 localrepo,
49 localrepo,
49 lock as lockmod,
50 lock as lockmod,
50 merge as mergemod,
51 merge as mergemod,
51 obsolete,
52 obsolete,
52 obsutil,
53 obsutil,
53 phases,
54 phases,
54 policy,
55 policy,
55 pvec,
56 pvec,
56 pycompat,
57 pycompat,
57 registrar,
58 registrar,
58 repair,
59 repair,
59 revlog,
60 revlog,
60 revset,
61 revset,
61 revsetlang,
62 revsetlang,
62 scmutil,
63 scmutil,
63 setdiscovery,
64 setdiscovery,
64 simplemerge,
65 simplemerge,
65 smartset,
66 smartset,
66 sslutil,
67 sslutil,
67 streamclone,
68 streamclone,
68 templater,
69 templater,
69 treediscovery,
70 treediscovery,
70 upgrade,
71 upgrade,
71 util,
72 util,
72 vfs as vfsmod,
73 vfs as vfsmod,
73 )
74 )
74
75
75 release = lockmod.release
76 release = lockmod.release
76
77
77 command = registrar.command()
78 command = registrar.command()
78
79
79 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
80 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
80 def debugancestor(ui, repo, *args):
81 def debugancestor(ui, repo, *args):
81 """find the ancestor revision of two revisions in a given index"""
82 """find the ancestor revision of two revisions in a given index"""
82 if len(args) == 3:
83 if len(args) == 3:
83 index, rev1, rev2 = args
84 index, rev1, rev2 = args
84 r = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False), index)
85 r = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False), index)
85 lookup = r.lookup
86 lookup = r.lookup
86 elif len(args) == 2:
87 elif len(args) == 2:
87 if not repo:
88 if not repo:
88 raise error.Abort(_('there is no Mercurial repository here '
89 raise error.Abort(_('there is no Mercurial repository here '
89 '(.hg not found)'))
90 '(.hg not found)'))
90 rev1, rev2 = args
91 rev1, rev2 = args
91 r = repo.changelog
92 r = repo.changelog
92 lookup = repo.lookup
93 lookup = repo.lookup
93 else:
94 else:
94 raise error.Abort(_('either two or three arguments required'))
95 raise error.Abort(_('either two or three arguments required'))
95 a = r.ancestor(lookup(rev1), lookup(rev2))
96 a = r.ancestor(lookup(rev1), lookup(rev2))
96 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
97 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
97
98
98 @command('debugapplystreamclonebundle', [], 'FILE')
99 @command('debugapplystreamclonebundle', [], 'FILE')
99 def debugapplystreamclonebundle(ui, repo, fname):
100 def debugapplystreamclonebundle(ui, repo, fname):
100 """apply a stream clone bundle file"""
101 """apply a stream clone bundle file"""
101 f = hg.openpath(ui, fname)
102 f = hg.openpath(ui, fname)
102 gen = exchange.readbundle(ui, f, fname)
103 gen = exchange.readbundle(ui, f, fname)
103 gen.apply(repo)
104 gen.apply(repo)
104
105
105 @command('debugbuilddag',
106 @command('debugbuilddag',
106 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
107 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
107 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
108 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
108 ('n', 'new-file', None, _('add new file at each rev'))],
109 ('n', 'new-file', None, _('add new file at each rev'))],
109 _('[OPTION]... [TEXT]'))
110 _('[OPTION]... [TEXT]'))
110 def debugbuilddag(ui, repo, text=None,
111 def debugbuilddag(ui, repo, text=None,
111 mergeable_file=False,
112 mergeable_file=False,
112 overwritten_file=False,
113 overwritten_file=False,
113 new_file=False):
114 new_file=False):
114 """builds a repo with a given DAG from scratch in the current empty repo
115 """builds a repo with a given DAG from scratch in the current empty repo
115
116
116 The description of the DAG is read from stdin if not given on the
117 The description of the DAG is read from stdin if not given on the
117 command line.
118 command line.
118
119
119 Elements:
120 Elements:
120
121
121 - "+n" is a linear run of n nodes based on the current default parent
122 - "+n" is a linear run of n nodes based on the current default parent
122 - "." is a single node based on the current default parent
123 - "." is a single node based on the current default parent
123 - "$" resets the default parent to null (implied at the start);
124 - "$" resets the default parent to null (implied at the start);
124 otherwise the default parent is always the last node created
125 otherwise the default parent is always the last node created
125 - "<p" sets the default parent to the backref p
126 - "<p" sets the default parent to the backref p
126 - "*p" is a fork at parent p, which is a backref
127 - "*p" is a fork at parent p, which is a backref
127 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
128 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
128 - "/p2" is a merge of the preceding node and p2
129 - "/p2" is a merge of the preceding node and p2
129 - ":tag" defines a local tag for the preceding node
130 - ":tag" defines a local tag for the preceding node
130 - "@branch" sets the named branch for subsequent nodes
131 - "@branch" sets the named branch for subsequent nodes
131 - "#...\\n" is a comment up to the end of the line
132 - "#...\\n" is a comment up to the end of the line
132
133
133 Whitespace between the above elements is ignored.
134 Whitespace between the above elements is ignored.
134
135
135 A backref is either
136 A backref is either
136
137
137 - a number n, which references the node curr-n, where curr is the current
138 - a number n, which references the node curr-n, where curr is the current
138 node, or
139 node, or
139 - the name of a local tag you placed earlier using ":tag", or
140 - the name of a local tag you placed earlier using ":tag", or
140 - empty to denote the default parent.
141 - empty to denote the default parent.
141
142
142 All string valued-elements are either strictly alphanumeric, or must
143 All string valued-elements are either strictly alphanumeric, or must
143 be enclosed in double quotes ("..."), with "\\" as escape character.
144 be enclosed in double quotes ("..."), with "\\" as escape character.
144 """
145 """
145
146
146 if text is None:
147 if text is None:
147 ui.status(_("reading DAG from stdin\n"))
148 ui.status(_("reading DAG from stdin\n"))
148 text = ui.fin.read()
149 text = ui.fin.read()
149
150
150 cl = repo.changelog
151 cl = repo.changelog
151 if len(cl) > 0:
152 if len(cl) > 0:
152 raise error.Abort(_('repository is not empty'))
153 raise error.Abort(_('repository is not empty'))
153
154
154 # determine number of revs in DAG
155 # determine number of revs in DAG
155 total = 0
156 total = 0
156 for type, data in dagparser.parsedag(text):
157 for type, data in dagparser.parsedag(text):
157 if type == 'n':
158 if type == 'n':
158 total += 1
159 total += 1
159
160
160 if mergeable_file:
161 if mergeable_file:
161 linesperrev = 2
162 linesperrev = 2
162 # make a file with k lines per rev
163 # make a file with k lines per rev
163 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
164 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
164 initialmergedlines.append("")
165 initialmergedlines.append("")
165
166
166 tags = []
167 tags = []
167
168
168 wlock = lock = tr = None
169 wlock = lock = tr = None
169 try:
170 try:
170 wlock = repo.wlock()
171 wlock = repo.wlock()
171 lock = repo.lock()
172 lock = repo.lock()
172 tr = repo.transaction("builddag")
173 tr = repo.transaction("builddag")
173
174
174 at = -1
175 at = -1
175 atbranch = 'default'
176 atbranch = 'default'
176 nodeids = []
177 nodeids = []
177 id = 0
178 id = 0
178 ui.progress(_('building'), id, unit=_('revisions'), total=total)
179 ui.progress(_('building'), id, unit=_('revisions'), total=total)
179 for type, data in dagparser.parsedag(text):
180 for type, data in dagparser.parsedag(text):
180 if type == 'n':
181 if type == 'n':
181 ui.note(('node %s\n' % str(data)))
182 ui.note(('node %s\n' % str(data)))
182 id, ps = data
183 id, ps = data
183
184
184 files = []
185 files = []
185 fctxs = {}
186 fctxs = {}
186
187
187 p2 = None
188 p2 = None
188 if mergeable_file:
189 if mergeable_file:
189 fn = "mf"
190 fn = "mf"
190 p1 = repo[ps[0]]
191 p1 = repo[ps[0]]
191 if len(ps) > 1:
192 if len(ps) > 1:
192 p2 = repo[ps[1]]
193 p2 = repo[ps[1]]
193 pa = p1.ancestor(p2)
194 pa = p1.ancestor(p2)
194 base, local, other = [x[fn].data() for x in (pa, p1,
195 base, local, other = [x[fn].data() for x in (pa, p1,
195 p2)]
196 p2)]
196 m3 = simplemerge.Merge3Text(base, local, other)
197 m3 = simplemerge.Merge3Text(base, local, other)
197 ml = [l.strip() for l in m3.merge_lines()]
198 ml = [l.strip() for l in m3.merge_lines()]
198 ml.append("")
199 ml.append("")
199 elif at > 0:
200 elif at > 0:
200 ml = p1[fn].data().split("\n")
201 ml = p1[fn].data().split("\n")
201 else:
202 else:
202 ml = initialmergedlines
203 ml = initialmergedlines
203 ml[id * linesperrev] += " r%i" % id
204 ml[id * linesperrev] += " r%i" % id
204 mergedtext = "\n".join(ml)
205 mergedtext = "\n".join(ml)
205 files.append(fn)
206 files.append(fn)
206 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
207 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
207
208
208 if overwritten_file:
209 if overwritten_file:
209 fn = "of"
210 fn = "of"
210 files.append(fn)
211 files.append(fn)
211 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
212 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
212
213
213 if new_file:
214 if new_file:
214 fn = "nf%i" % id
215 fn = "nf%i" % id
215 files.append(fn)
216 files.append(fn)
216 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
217 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
217 if len(ps) > 1:
218 if len(ps) > 1:
218 if not p2:
219 if not p2:
219 p2 = repo[ps[1]]
220 p2 = repo[ps[1]]
220 for fn in p2:
221 for fn in p2:
221 if fn.startswith("nf"):
222 if fn.startswith("nf"):
222 files.append(fn)
223 files.append(fn)
223 fctxs[fn] = p2[fn]
224 fctxs[fn] = p2[fn]
224
225
225 def fctxfn(repo, cx, path):
226 def fctxfn(repo, cx, path):
226 return fctxs.get(path)
227 return fctxs.get(path)
227
228
228 if len(ps) == 0 or ps[0] < 0:
229 if len(ps) == 0 or ps[0] < 0:
229 pars = [None, None]
230 pars = [None, None]
230 elif len(ps) == 1:
231 elif len(ps) == 1:
231 pars = [nodeids[ps[0]], None]
232 pars = [nodeids[ps[0]], None]
232 else:
233 else:
233 pars = [nodeids[p] for p in ps]
234 pars = [nodeids[p] for p in ps]
234 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
235 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
235 date=(id, 0),
236 date=(id, 0),
236 user="debugbuilddag",
237 user="debugbuilddag",
237 extra={'branch': atbranch})
238 extra={'branch': atbranch})
238 nodeid = repo.commitctx(cx)
239 nodeid = repo.commitctx(cx)
239 nodeids.append(nodeid)
240 nodeids.append(nodeid)
240 at = id
241 at = id
241 elif type == 'l':
242 elif type == 'l':
242 id, name = data
243 id, name = data
243 ui.note(('tag %s\n' % name))
244 ui.note(('tag %s\n' % name))
244 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
245 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
245 elif type == 'a':
246 elif type == 'a':
246 ui.note(('branch %s\n' % data))
247 ui.note(('branch %s\n' % data))
247 atbranch = data
248 atbranch = data
248 ui.progress(_('building'), id, unit=_('revisions'), total=total)
249 ui.progress(_('building'), id, unit=_('revisions'), total=total)
249 tr.close()
250 tr.close()
250
251
251 if tags:
252 if tags:
252 repo.vfs.write("localtags", "".join(tags))
253 repo.vfs.write("localtags", "".join(tags))
253 finally:
254 finally:
254 ui.progress(_('building'), None)
255 ui.progress(_('building'), None)
255 release(tr, lock, wlock)
256 release(tr, lock, wlock)
256
257
257 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
258 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
258 indent_string = ' ' * indent
259 indent_string = ' ' * indent
259 if all:
260 if all:
260 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
261 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
261 % indent_string)
262 % indent_string)
262
263
263 def showchunks(named):
264 def showchunks(named):
264 ui.write("\n%s%s\n" % (indent_string, named))
265 ui.write("\n%s%s\n" % (indent_string, named))
265 chain = None
266 chain = None
266 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
267 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
267 node = chunkdata['node']
268 node = chunkdata['node']
268 p1 = chunkdata['p1']
269 p1 = chunkdata['p1']
269 p2 = chunkdata['p2']
270 p2 = chunkdata['p2']
270 cs = chunkdata['cs']
271 cs = chunkdata['cs']
271 deltabase = chunkdata['deltabase']
272 deltabase = chunkdata['deltabase']
272 delta = chunkdata['delta']
273 delta = chunkdata['delta']
273 ui.write("%s%s %s %s %s %s %s\n" %
274 ui.write("%s%s %s %s %s %s %s\n" %
274 (indent_string, hex(node), hex(p1), hex(p2),
275 (indent_string, hex(node), hex(p1), hex(p2),
275 hex(cs), hex(deltabase), len(delta)))
276 hex(cs), hex(deltabase), len(delta)))
276 chain = node
277 chain = node
277
278
278 chunkdata = gen.changelogheader()
279 chunkdata = gen.changelogheader()
279 showchunks("changelog")
280 showchunks("changelog")
280 chunkdata = gen.manifestheader()
281 chunkdata = gen.manifestheader()
281 showchunks("manifest")
282 showchunks("manifest")
282 for chunkdata in iter(gen.filelogheader, {}):
283 for chunkdata in iter(gen.filelogheader, {}):
283 fname = chunkdata['filename']
284 fname = chunkdata['filename']
284 showchunks(fname)
285 showchunks(fname)
285 else:
286 else:
286 if isinstance(gen, bundle2.unbundle20):
287 if isinstance(gen, bundle2.unbundle20):
287 raise error.Abort(_('use debugbundle2 for this file'))
288 raise error.Abort(_('use debugbundle2 for this file'))
288 chunkdata = gen.changelogheader()
289 chunkdata = gen.changelogheader()
289 chain = None
290 chain = None
290 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
291 for chunkdata in iter(lambda: gen.deltachunk(chain), {}):
291 node = chunkdata['node']
292 node = chunkdata['node']
292 ui.write("%s%s\n" % (indent_string, hex(node)))
293 ui.write("%s%s\n" % (indent_string, hex(node)))
293 chain = node
294 chain = node
294
295
295 def _debugobsmarkers(ui, part, indent=0, **opts):
296 def _debugobsmarkers(ui, part, indent=0, **opts):
296 """display version and markers contained in 'data'"""
297 """display version and markers contained in 'data'"""
297 opts = pycompat.byteskwargs(opts)
298 opts = pycompat.byteskwargs(opts)
298 data = part.read()
299 data = part.read()
299 indent_string = ' ' * indent
300 indent_string = ' ' * indent
300 try:
301 try:
301 version, markers = obsolete._readmarkers(data)
302 version, markers = obsolete._readmarkers(data)
302 except error.UnknownVersion as exc:
303 except error.UnknownVersion as exc:
303 msg = "%sunsupported version: %s (%d bytes)\n"
304 msg = "%sunsupported version: %s (%d bytes)\n"
304 msg %= indent_string, exc.version, len(data)
305 msg %= indent_string, exc.version, len(data)
305 ui.write(msg)
306 ui.write(msg)
306 else:
307 else:
307 msg = "%sversion: %s (%d bytes)\n"
308 msg = "%sversion: %s (%d bytes)\n"
308 msg %= indent_string, version, len(data)
309 msg %= indent_string, version, len(data)
309 ui.write(msg)
310 ui.write(msg)
310 fm = ui.formatter('debugobsolete', opts)
311 fm = ui.formatter('debugobsolete', opts)
311 for rawmarker in sorted(markers):
312 for rawmarker in sorted(markers):
312 m = obsutil.marker(None, rawmarker)
313 m = obsutil.marker(None, rawmarker)
313 fm.startitem()
314 fm.startitem()
314 fm.plain(indent_string)
315 fm.plain(indent_string)
315 cmdutil.showmarker(fm, m)
316 cmdutil.showmarker(fm, m)
316 fm.end()
317 fm.end()
317
318
318 def _debugphaseheads(ui, data, indent=0):
319 def _debugphaseheads(ui, data, indent=0):
319 """display version and markers contained in 'data'"""
320 """display version and markers contained in 'data'"""
320 indent_string = ' ' * indent
321 indent_string = ' ' * indent
321 headsbyphase = bundle2._readphaseheads(data)
322 headsbyphase = bundle2._readphaseheads(data)
322 for phase in phases.allphases:
323 for phase in phases.allphases:
323 for head in headsbyphase[phase]:
324 for head in headsbyphase[phase]:
324 ui.write(indent_string)
325 ui.write(indent_string)
325 ui.write('%s %s\n' % (hex(head), phases.phasenames[phase]))
326 ui.write('%s %s\n' % (hex(head), phases.phasenames[phase]))
326
327
327 def _quasirepr(thing):
328 def _quasirepr(thing):
328 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
329 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
329 return '{%s}' % (
330 return '{%s}' % (
330 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing)))
331 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing)))
331 return pycompat.bytestr(repr(thing))
332 return pycompat.bytestr(repr(thing))
332
333
333 def _debugbundle2(ui, gen, all=None, **opts):
334 def _debugbundle2(ui, gen, all=None, **opts):
334 """lists the contents of a bundle2"""
335 """lists the contents of a bundle2"""
335 if not isinstance(gen, bundle2.unbundle20):
336 if not isinstance(gen, bundle2.unbundle20):
336 raise error.Abort(_('not a bundle2 file'))
337 raise error.Abort(_('not a bundle2 file'))
337 ui.write(('Stream params: %s\n' % _quasirepr(gen.params)))
338 ui.write(('Stream params: %s\n' % _quasirepr(gen.params)))
338 parttypes = opts.get(r'part_type', [])
339 parttypes = opts.get(r'part_type', [])
339 for part in gen.iterparts():
340 for part in gen.iterparts():
340 if parttypes and part.type not in parttypes:
341 if parttypes and part.type not in parttypes:
341 continue
342 continue
342 ui.write('%s -- %s\n' % (part.type, _quasirepr(part.params)))
343 ui.write('%s -- %s\n' % (part.type, _quasirepr(part.params)))
343 if part.type == 'changegroup':
344 if part.type == 'changegroup':
344 version = part.params.get('version', '01')
345 version = part.params.get('version', '01')
345 cg = changegroup.getunbundler(version, part, 'UN')
346 cg = changegroup.getunbundler(version, part, 'UN')
346 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
347 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
347 if part.type == 'obsmarkers':
348 if part.type == 'obsmarkers':
348 _debugobsmarkers(ui, part, indent=4, **opts)
349 _debugobsmarkers(ui, part, indent=4, **opts)
349 if part.type == 'phase-heads':
350 if part.type == 'phase-heads':
350 _debugphaseheads(ui, part, indent=4)
351 _debugphaseheads(ui, part, indent=4)
351
352
352 @command('debugbundle',
353 @command('debugbundle',
353 [('a', 'all', None, _('show all details')),
354 [('a', 'all', None, _('show all details')),
354 ('', 'part-type', [], _('show only the named part type')),
355 ('', 'part-type', [], _('show only the named part type')),
355 ('', 'spec', None, _('print the bundlespec of the bundle'))],
356 ('', 'spec', None, _('print the bundlespec of the bundle'))],
356 _('FILE'),
357 _('FILE'),
357 norepo=True)
358 norepo=True)
358 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
359 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
359 """lists the contents of a bundle"""
360 """lists the contents of a bundle"""
360 with hg.openpath(ui, bundlepath) as f:
361 with hg.openpath(ui, bundlepath) as f:
361 if spec:
362 if spec:
362 spec = exchange.getbundlespec(ui, f)
363 spec = exchange.getbundlespec(ui, f)
363 ui.write('%s\n' % spec)
364 ui.write('%s\n' % spec)
364 return
365 return
365
366
366 gen = exchange.readbundle(ui, f, bundlepath)
367 gen = exchange.readbundle(ui, f, bundlepath)
367 if isinstance(gen, bundle2.unbundle20):
368 if isinstance(gen, bundle2.unbundle20):
368 return _debugbundle2(ui, gen, all=all, **opts)
369 return _debugbundle2(ui, gen, all=all, **opts)
369 _debugchangegroup(ui, gen, all=all, **opts)
370 _debugchangegroup(ui, gen, all=all, **opts)
370
371
371 @command('debugcheckstate', [], '')
372 @command('debugcheckstate', [], '')
372 def debugcheckstate(ui, repo):
373 def debugcheckstate(ui, repo):
373 """validate the correctness of the current dirstate"""
374 """validate the correctness of the current dirstate"""
374 parent1, parent2 = repo.dirstate.parents()
375 parent1, parent2 = repo.dirstate.parents()
375 m1 = repo[parent1].manifest()
376 m1 = repo[parent1].manifest()
376 m2 = repo[parent2].manifest()
377 m2 = repo[parent2].manifest()
377 errors = 0
378 errors = 0
378 for f in repo.dirstate:
379 for f in repo.dirstate:
379 state = repo.dirstate[f]
380 state = repo.dirstate[f]
380 if state in "nr" and f not in m1:
381 if state in "nr" and f not in m1:
381 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
382 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
382 errors += 1
383 errors += 1
383 if state in "a" and f in m1:
384 if state in "a" and f in m1:
384 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
385 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
385 errors += 1
386 errors += 1
386 if state in "m" and f not in m1 and f not in m2:
387 if state in "m" and f not in m1 and f not in m2:
387 ui.warn(_("%s in state %s, but not in either manifest\n") %
388 ui.warn(_("%s in state %s, but not in either manifest\n") %
388 (f, state))
389 (f, state))
389 errors += 1
390 errors += 1
390 for f in m1:
391 for f in m1:
391 state = repo.dirstate[f]
392 state = repo.dirstate[f]
392 if state not in "nrm":
393 if state not in "nrm":
393 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
394 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
394 errors += 1
395 errors += 1
395 if errors:
396 if errors:
396 error = _(".hg/dirstate inconsistent with current parent's manifest")
397 error = _(".hg/dirstate inconsistent with current parent's manifest")
397 raise error.Abort(error)
398 raise error.Abort(error)
398
399
399 @command('debugcolor',
400 @command('debugcolor',
400 [('', 'style', None, _('show all configured styles'))],
401 [('', 'style', None, _('show all configured styles'))],
401 'hg debugcolor')
402 'hg debugcolor')
402 def debugcolor(ui, repo, **opts):
403 def debugcolor(ui, repo, **opts):
403 """show available color, effects or style"""
404 """show available color, effects or style"""
404 ui.write(('color mode: %s\n') % ui._colormode)
405 ui.write(('color mode: %s\n') % ui._colormode)
405 if opts.get(r'style'):
406 if opts.get(r'style'):
406 return _debugdisplaystyle(ui)
407 return _debugdisplaystyle(ui)
407 else:
408 else:
408 return _debugdisplaycolor(ui)
409 return _debugdisplaycolor(ui)
409
410
410 def _debugdisplaycolor(ui):
411 def _debugdisplaycolor(ui):
411 ui = ui.copy()
412 ui = ui.copy()
412 ui._styles.clear()
413 ui._styles.clear()
413 for effect in color._activeeffects(ui).keys():
414 for effect in color._activeeffects(ui).keys():
414 ui._styles[effect] = effect
415 ui._styles[effect] = effect
415 if ui._terminfoparams:
416 if ui._terminfoparams:
416 for k, v in ui.configitems('color'):
417 for k, v in ui.configitems('color'):
417 if k.startswith('color.'):
418 if k.startswith('color.'):
418 ui._styles[k] = k[6:]
419 ui._styles[k] = k[6:]
419 elif k.startswith('terminfo.'):
420 elif k.startswith('terminfo.'):
420 ui._styles[k] = k[9:]
421 ui._styles[k] = k[9:]
421 ui.write(_('available colors:\n'))
422 ui.write(_('available colors:\n'))
422 # sort label with a '_' after the other to group '_background' entry.
423 # sort label with a '_' after the other to group '_background' entry.
423 items = sorted(ui._styles.items(),
424 items = sorted(ui._styles.items(),
424 key=lambda i: ('_' in i[0], i[0], i[1]))
425 key=lambda i: ('_' in i[0], i[0], i[1]))
425 for colorname, label in items:
426 for colorname, label in items:
426 ui.write(('%s\n') % colorname, label=label)
427 ui.write(('%s\n') % colorname, label=label)
427
428
428 def _debugdisplaystyle(ui):
429 def _debugdisplaystyle(ui):
429 ui.write(_('available style:\n'))
430 ui.write(_('available style:\n'))
430 width = max(len(s) for s in ui._styles)
431 width = max(len(s) for s in ui._styles)
431 for label, effects in sorted(ui._styles.items()):
432 for label, effects in sorted(ui._styles.items()):
432 ui.write('%s' % label, label=label)
433 ui.write('%s' % label, label=label)
433 if effects:
434 if effects:
434 # 50
435 # 50
435 ui.write(': ')
436 ui.write(': ')
436 ui.write(' ' * (max(0, width - len(label))))
437 ui.write(' ' * (max(0, width - len(label))))
437 ui.write(', '.join(ui.label(e, e) for e in effects.split()))
438 ui.write(', '.join(ui.label(e, e) for e in effects.split()))
438 ui.write('\n')
439 ui.write('\n')
439
440
440 @command('debugcreatestreamclonebundle', [], 'FILE')
441 @command('debugcreatestreamclonebundle', [], 'FILE')
441 def debugcreatestreamclonebundle(ui, repo, fname):
442 def debugcreatestreamclonebundle(ui, repo, fname):
442 """create a stream clone bundle file
443 """create a stream clone bundle file
443
444
444 Stream bundles are special bundles that are essentially archives of
445 Stream bundles are special bundles that are essentially archives of
445 revlog files. They are commonly used for cloning very quickly.
446 revlog files. They are commonly used for cloning very quickly.
446 """
447 """
447 # TODO we may want to turn this into an abort when this functionality
448 # TODO we may want to turn this into an abort when this functionality
448 # is moved into `hg bundle`.
449 # is moved into `hg bundle`.
449 if phases.hassecret(repo):
450 if phases.hassecret(repo):
450 ui.warn(_('(warning: stream clone bundle will contain secret '
451 ui.warn(_('(warning: stream clone bundle will contain secret '
451 'revisions)\n'))
452 'revisions)\n'))
452
453
453 requirements, gen = streamclone.generatebundlev1(repo)
454 requirements, gen = streamclone.generatebundlev1(repo)
454 changegroup.writechunks(ui, gen, fname)
455 changegroup.writechunks(ui, gen, fname)
455
456
456 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
457 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
457
458
458 @command('debugdag',
459 @command('debugdag',
459 [('t', 'tags', None, _('use tags as labels')),
460 [('t', 'tags', None, _('use tags as labels')),
460 ('b', 'branches', None, _('annotate with branch names')),
461 ('b', 'branches', None, _('annotate with branch names')),
461 ('', 'dots', None, _('use dots for runs')),
462 ('', 'dots', None, _('use dots for runs')),
462 ('s', 'spaces', None, _('separate elements by spaces'))],
463 ('s', 'spaces', None, _('separate elements by spaces'))],
463 _('[OPTION]... [FILE [REV]...]'),
464 _('[OPTION]... [FILE [REV]...]'),
464 optionalrepo=True)
465 optionalrepo=True)
465 def debugdag(ui, repo, file_=None, *revs, **opts):
466 def debugdag(ui, repo, file_=None, *revs, **opts):
466 """format the changelog or an index DAG as a concise textual description
467 """format the changelog or an index DAG as a concise textual description
467
468
468 If you pass a revlog index, the revlog's DAG is emitted. If you list
469 If you pass a revlog index, the revlog's DAG is emitted. If you list
469 revision numbers, they get labeled in the output as rN.
470 revision numbers, they get labeled in the output as rN.
470
471
471 Otherwise, the changelog DAG of the current repo is emitted.
472 Otherwise, the changelog DAG of the current repo is emitted.
472 """
473 """
473 spaces = opts.get(r'spaces')
474 spaces = opts.get(r'spaces')
474 dots = opts.get(r'dots')
475 dots = opts.get(r'dots')
475 if file_:
476 if file_:
476 rlog = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False),
477 rlog = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False),
477 file_)
478 file_)
478 revs = set((int(r) for r in revs))
479 revs = set((int(r) for r in revs))
479 def events():
480 def events():
480 for r in rlog:
481 for r in rlog:
481 yield 'n', (r, list(p for p in rlog.parentrevs(r)
482 yield 'n', (r, list(p for p in rlog.parentrevs(r)
482 if p != -1))
483 if p != -1))
483 if r in revs:
484 if r in revs:
484 yield 'l', (r, "r%i" % r)
485 yield 'l', (r, "r%i" % r)
485 elif repo:
486 elif repo:
486 cl = repo.changelog
487 cl = repo.changelog
487 tags = opts.get(r'tags')
488 tags = opts.get(r'tags')
488 branches = opts.get(r'branches')
489 branches = opts.get(r'branches')
489 if tags:
490 if tags:
490 labels = {}
491 labels = {}
491 for l, n in repo.tags().items():
492 for l, n in repo.tags().items():
492 labels.setdefault(cl.rev(n), []).append(l)
493 labels.setdefault(cl.rev(n), []).append(l)
493 def events():
494 def events():
494 b = "default"
495 b = "default"
495 for r in cl:
496 for r in cl:
496 if branches:
497 if branches:
497 newb = cl.read(cl.node(r))[5]['branch']
498 newb = cl.read(cl.node(r))[5]['branch']
498 if newb != b:
499 if newb != b:
499 yield 'a', newb
500 yield 'a', newb
500 b = newb
501 b = newb
501 yield 'n', (r, list(p for p in cl.parentrevs(r)
502 yield 'n', (r, list(p for p in cl.parentrevs(r)
502 if p != -1))
503 if p != -1))
503 if tags:
504 if tags:
504 ls = labels.get(r)
505 ls = labels.get(r)
505 if ls:
506 if ls:
506 for l in ls:
507 for l in ls:
507 yield 'l', (r, l)
508 yield 'l', (r, l)
508 else:
509 else:
509 raise error.Abort(_('need repo for changelog dag'))
510 raise error.Abort(_('need repo for changelog dag'))
510
511
511 for line in dagparser.dagtextlines(events(),
512 for line in dagparser.dagtextlines(events(),
512 addspaces=spaces,
513 addspaces=spaces,
513 wraplabels=True,
514 wraplabels=True,
514 wrapannotations=True,
515 wrapannotations=True,
515 wrapnonlinear=dots,
516 wrapnonlinear=dots,
516 usedots=dots,
517 usedots=dots,
517 maxlinewidth=70):
518 maxlinewidth=70):
518 ui.write(line)
519 ui.write(line)
519 ui.write("\n")
520 ui.write("\n")
520
521
521 @command('debugdata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
522 @command('debugdata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
522 def debugdata(ui, repo, file_, rev=None, **opts):
523 def debugdata(ui, repo, file_, rev=None, **opts):
523 """dump the contents of a data file revision"""
524 """dump the contents of a data file revision"""
524 opts = pycompat.byteskwargs(opts)
525 opts = pycompat.byteskwargs(opts)
525 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
526 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
526 if rev is not None:
527 if rev is not None:
527 raise error.CommandError('debugdata', _('invalid arguments'))
528 raise error.CommandError('debugdata', _('invalid arguments'))
528 file_, rev = None, file_
529 file_, rev = None, file_
529 elif rev is None:
530 elif rev is None:
530 raise error.CommandError('debugdata', _('invalid arguments'))
531 raise error.CommandError('debugdata', _('invalid arguments'))
531 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
532 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
532 try:
533 try:
533 ui.write(r.revision(r.lookup(rev), raw=True))
534 ui.write(r.revision(r.lookup(rev), raw=True))
534 except KeyError:
535 except KeyError:
535 raise error.Abort(_('invalid revision identifier %s') % rev)
536 raise error.Abort(_('invalid revision identifier %s') % rev)
536
537
537 @command('debugdate',
538 @command('debugdate',
538 [('e', 'extended', None, _('try extended date formats'))],
539 [('e', 'extended', None, _('try extended date formats'))],
539 _('[-e] DATE [RANGE]'),
540 _('[-e] DATE [RANGE]'),
540 norepo=True, optionalrepo=True)
541 norepo=True, optionalrepo=True)
541 def debugdate(ui, date, range=None, **opts):
542 def debugdate(ui, date, range=None, **opts):
542 """parse and display a date"""
543 """parse and display a date"""
543 if opts[r"extended"]:
544 if opts[r"extended"]:
544 d = util.parsedate(date, util.extendeddateformats)
545 d = util.parsedate(date, util.extendeddateformats)
545 else:
546 else:
546 d = util.parsedate(date)
547 d = util.parsedate(date)
547 ui.write(("internal: %s %s\n") % d)
548 ui.write(("internal: %s %s\n") % d)
548 ui.write(("standard: %s\n") % util.datestr(d))
549 ui.write(("standard: %s\n") % util.datestr(d))
549 if range:
550 if range:
550 m = util.matchdate(range)
551 m = util.matchdate(range)
551 ui.write(("match: %s\n") % m(d[0]))
552 ui.write(("match: %s\n") % m(d[0]))
552
553
553 @command('debugdeltachain',
554 @command('debugdeltachain',
554 cmdutil.debugrevlogopts + cmdutil.formatteropts,
555 cmdutil.debugrevlogopts + cmdutil.formatteropts,
555 _('-c|-m|FILE'),
556 _('-c|-m|FILE'),
556 optionalrepo=True)
557 optionalrepo=True)
557 def debugdeltachain(ui, repo, file_=None, **opts):
558 def debugdeltachain(ui, repo, file_=None, **opts):
558 """dump information about delta chains in a revlog
559 """dump information about delta chains in a revlog
559
560
560 Output can be templatized. Available template keywords are:
561 Output can be templatized. Available template keywords are:
561
562
562 :``rev``: revision number
563 :``rev``: revision number
563 :``chainid``: delta chain identifier (numbered by unique base)
564 :``chainid``: delta chain identifier (numbered by unique base)
564 :``chainlen``: delta chain length to this revision
565 :``chainlen``: delta chain length to this revision
565 :``prevrev``: previous revision in delta chain
566 :``prevrev``: previous revision in delta chain
566 :``deltatype``: role of delta / how it was computed
567 :``deltatype``: role of delta / how it was computed
567 :``compsize``: compressed size of revision
568 :``compsize``: compressed size of revision
568 :``uncompsize``: uncompressed size of revision
569 :``uncompsize``: uncompressed size of revision
569 :``chainsize``: total size of compressed revisions in chain
570 :``chainsize``: total size of compressed revisions in chain
570 :``chainratio``: total chain size divided by uncompressed revision size
571 :``chainratio``: total chain size divided by uncompressed revision size
571 (new delta chains typically start at ratio 2.00)
572 (new delta chains typically start at ratio 2.00)
572 :``lindist``: linear distance from base revision in delta chain to end
573 :``lindist``: linear distance from base revision in delta chain to end
573 of this revision
574 of this revision
574 :``extradist``: total size of revisions not part of this delta chain from
575 :``extradist``: total size of revisions not part of this delta chain from
575 base of delta chain to end of this revision; a measurement
576 base of delta chain to end of this revision; a measurement
576 of how much extra data we need to read/seek across to read
577 of how much extra data we need to read/seek across to read
577 the delta chain for this revision
578 the delta chain for this revision
578 :``extraratio``: extradist divided by chainsize; another representation of
579 :``extraratio``: extradist divided by chainsize; another representation of
579 how much unrelated data is needed to load this delta chain
580 how much unrelated data is needed to load this delta chain
580 """
581 """
581 opts = pycompat.byteskwargs(opts)
582 opts = pycompat.byteskwargs(opts)
582 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
583 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
583 index = r.index
584 index = r.index
584 generaldelta = r.version & revlog.FLAG_GENERALDELTA
585 generaldelta = r.version & revlog.FLAG_GENERALDELTA
585
586
586 def revinfo(rev):
587 def revinfo(rev):
587 e = index[rev]
588 e = index[rev]
588 compsize = e[1]
589 compsize = e[1]
589 uncompsize = e[2]
590 uncompsize = e[2]
590 chainsize = 0
591 chainsize = 0
591
592
592 if generaldelta:
593 if generaldelta:
593 if e[3] == e[5]:
594 if e[3] == e[5]:
594 deltatype = 'p1'
595 deltatype = 'p1'
595 elif e[3] == e[6]:
596 elif e[3] == e[6]:
596 deltatype = 'p2'
597 deltatype = 'p2'
597 elif e[3] == rev - 1:
598 elif e[3] == rev - 1:
598 deltatype = 'prev'
599 deltatype = 'prev'
599 elif e[3] == rev:
600 elif e[3] == rev:
600 deltatype = 'base'
601 deltatype = 'base'
601 else:
602 else:
602 deltatype = 'other'
603 deltatype = 'other'
603 else:
604 else:
604 if e[3] == rev:
605 if e[3] == rev:
605 deltatype = 'base'
606 deltatype = 'base'
606 else:
607 else:
607 deltatype = 'prev'
608 deltatype = 'prev'
608
609
609 chain = r._deltachain(rev)[0]
610 chain = r._deltachain(rev)[0]
610 for iterrev in chain:
611 for iterrev in chain:
611 e = index[iterrev]
612 e = index[iterrev]
612 chainsize += e[1]
613 chainsize += e[1]
613
614
614 return compsize, uncompsize, deltatype, chain, chainsize
615 return compsize, uncompsize, deltatype, chain, chainsize
615
616
616 fm = ui.formatter('debugdeltachain', opts)
617 fm = ui.formatter('debugdeltachain', opts)
617
618
618 fm.plain(' rev chain# chainlen prev delta '
619 fm.plain(' rev chain# chainlen prev delta '
619 'size rawsize chainsize ratio lindist extradist '
620 'size rawsize chainsize ratio lindist extradist '
620 'extraratio\n')
621 'extraratio\n')
621
622
622 chainbases = {}
623 chainbases = {}
623 for rev in r:
624 for rev in r:
624 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
625 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
625 chainbase = chain[0]
626 chainbase = chain[0]
626 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
627 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
627 basestart = r.start(chainbase)
628 basestart = r.start(chainbase)
628 revstart = r.start(rev)
629 revstart = r.start(rev)
629 lineardist = revstart + comp - basestart
630 lineardist = revstart + comp - basestart
630 extradist = lineardist - chainsize
631 extradist = lineardist - chainsize
631 try:
632 try:
632 prevrev = chain[-2]
633 prevrev = chain[-2]
633 except IndexError:
634 except IndexError:
634 prevrev = -1
635 prevrev = -1
635
636
636 chainratio = float(chainsize) / float(uncomp)
637 chainratio = float(chainsize) / float(uncomp)
637 extraratio = float(extradist) / float(chainsize)
638 extraratio = float(extradist) / float(chainsize)
638
639
639 fm.startitem()
640 fm.startitem()
640 fm.write('rev chainid chainlen prevrev deltatype compsize '
641 fm.write('rev chainid chainlen prevrev deltatype compsize '
641 'uncompsize chainsize chainratio lindist extradist '
642 'uncompsize chainsize chainratio lindist extradist '
642 'extraratio',
643 'extraratio',
643 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
644 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
644 rev, chainid, len(chain), prevrev, deltatype, comp,
645 rev, chainid, len(chain), prevrev, deltatype, comp,
645 uncomp, chainsize, chainratio, lineardist, extradist,
646 uncomp, chainsize, chainratio, lineardist, extradist,
646 extraratio,
647 extraratio,
647 rev=rev, chainid=chainid, chainlen=len(chain),
648 rev=rev, chainid=chainid, chainlen=len(chain),
648 prevrev=prevrev, deltatype=deltatype, compsize=comp,
649 prevrev=prevrev, deltatype=deltatype, compsize=comp,
649 uncompsize=uncomp, chainsize=chainsize,
650 uncompsize=uncomp, chainsize=chainsize,
650 chainratio=chainratio, lindist=lineardist,
651 chainratio=chainratio, lindist=lineardist,
651 extradist=extradist, extraratio=extraratio)
652 extradist=extradist, extraratio=extraratio)
652
653
653 fm.end()
654 fm.end()
654
655
655 @command('debugdirstate|debugstate',
656 @command('debugdirstate|debugstate',
656 [('', 'nodates', None, _('do not display the saved mtime')),
657 [('', 'nodates', None, _('do not display the saved mtime')),
657 ('', 'datesort', None, _('sort by saved mtime'))],
658 ('', 'datesort', None, _('sort by saved mtime'))],
658 _('[OPTION]...'))
659 _('[OPTION]...'))
659 def debugstate(ui, repo, **opts):
660 def debugstate(ui, repo, **opts):
660 """show the contents of the current dirstate"""
661 """show the contents of the current dirstate"""
661
662
662 nodates = opts.get(r'nodates')
663 nodates = opts.get(r'nodates')
663 datesort = opts.get(r'datesort')
664 datesort = opts.get(r'datesort')
664
665
665 timestr = ""
666 timestr = ""
666 if datesort:
667 if datesort:
667 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
668 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
668 else:
669 else:
669 keyfunc = None # sort by filename
670 keyfunc = None # sort by filename
670 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
671 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
671 if ent[3] == -1:
672 if ent[3] == -1:
672 timestr = 'unset '
673 timestr = 'unset '
673 elif nodates:
674 elif nodates:
674 timestr = 'set '
675 timestr = 'set '
675 else:
676 else:
676 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
677 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
677 time.localtime(ent[3]))
678 time.localtime(ent[3]))
678 if ent[1] & 0o20000:
679 if ent[1] & 0o20000:
679 mode = 'lnk'
680 mode = 'lnk'
680 else:
681 else:
681 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
682 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
682 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
683 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
683 for f in repo.dirstate.copies():
684 for f in repo.dirstate.copies():
684 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
685 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
685
686
686 @command('debugdiscovery',
687 @command('debugdiscovery',
687 [('', 'old', None, _('use old-style discovery')),
688 [('', 'old', None, _('use old-style discovery')),
688 ('', 'nonheads', None,
689 ('', 'nonheads', None,
689 _('use old-style discovery with non-heads included')),
690 _('use old-style discovery with non-heads included')),
690 ] + cmdutil.remoteopts,
691 ] + cmdutil.remoteopts,
691 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
692 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
692 def debugdiscovery(ui, repo, remoteurl="default", **opts):
693 def debugdiscovery(ui, repo, remoteurl="default", **opts):
693 """runs the changeset discovery protocol in isolation"""
694 """runs the changeset discovery protocol in isolation"""
694 opts = pycompat.byteskwargs(opts)
695 opts = pycompat.byteskwargs(opts)
695 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
696 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
696 opts.get('branch'))
697 opts.get('branch'))
697 remote = hg.peer(repo, opts, remoteurl)
698 remote = hg.peer(repo, opts, remoteurl)
698 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
699 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
699
700
700 # make sure tests are repeatable
701 # make sure tests are repeatable
701 random.seed(12323)
702 random.seed(12323)
702
703
703 def doit(localheads, remoteheads, remote=remote):
704 def doit(localheads, remoteheads, remote=remote):
704 if opts.get('old'):
705 if opts.get('old'):
705 if localheads:
706 if localheads:
706 raise error.Abort('cannot use localheads with old style '
707 raise error.Abort('cannot use localheads with old style '
707 'discovery')
708 'discovery')
708 if not util.safehasattr(remote, 'branches'):
709 if not util.safehasattr(remote, 'branches'):
709 # enable in-client legacy support
710 # enable in-client legacy support
710 remote = localrepo.locallegacypeer(remote.local())
711 remote = localrepo.locallegacypeer(remote.local())
711 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
712 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
712 force=True)
713 force=True)
713 common = set(common)
714 common = set(common)
714 if not opts.get('nonheads'):
715 if not opts.get('nonheads'):
715 ui.write(("unpruned common: %s\n") %
716 ui.write(("unpruned common: %s\n") %
716 " ".join(sorted(short(n) for n in common)))
717 " ".join(sorted(short(n) for n in common)))
717 dag = dagutil.revlogdag(repo.changelog)
718 dag = dagutil.revlogdag(repo.changelog)
718 all = dag.ancestorset(dag.internalizeall(common))
719 all = dag.ancestorset(dag.internalizeall(common))
719 common = dag.externalizeall(dag.headsetofconnecteds(all))
720 common = dag.externalizeall(dag.headsetofconnecteds(all))
720 else:
721 else:
721 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
722 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
722 common = set(common)
723 common = set(common)
723 rheads = set(hds)
724 rheads = set(hds)
724 lheads = set(repo.heads())
725 lheads = set(repo.heads())
725 ui.write(("common heads: %s\n") %
726 ui.write(("common heads: %s\n") %
726 " ".join(sorted(short(n) for n in common)))
727 " ".join(sorted(short(n) for n in common)))
727 if lheads <= common:
728 if lheads <= common:
728 ui.write(("local is subset\n"))
729 ui.write(("local is subset\n"))
729 elif rheads <= common:
730 elif rheads <= common:
730 ui.write(("remote is subset\n"))
731 ui.write(("remote is subset\n"))
731
732
732 serverlogs = opts.get('serverlog')
733 serverlogs = opts.get('serverlog')
733 if serverlogs:
734 if serverlogs:
734 for filename in serverlogs:
735 for filename in serverlogs:
735 with open(filename, 'r') as logfile:
736 with open(filename, 'r') as logfile:
736 line = logfile.readline()
737 line = logfile.readline()
737 while line:
738 while line:
738 parts = line.strip().split(';')
739 parts = line.strip().split(';')
739 op = parts[1]
740 op = parts[1]
740 if op == 'cg':
741 if op == 'cg':
741 pass
742 pass
742 elif op == 'cgss':
743 elif op == 'cgss':
743 doit(parts[2].split(' '), parts[3].split(' '))
744 doit(parts[2].split(' '), parts[3].split(' '))
744 elif op == 'unb':
745 elif op == 'unb':
745 doit(parts[3].split(' '), parts[2].split(' '))
746 doit(parts[3].split(' '), parts[2].split(' '))
746 line = logfile.readline()
747 line = logfile.readline()
747 else:
748 else:
748 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
749 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
749 opts.get('remote_head'))
750 opts.get('remote_head'))
750 localrevs = opts.get('local_head')
751 localrevs = opts.get('local_head')
751 doit(localrevs, remoterevs)
752 doit(localrevs, remoterevs)
752
753
753 @command('debugextensions', cmdutil.formatteropts, [], norepo=True)
754 @command('debugextensions', cmdutil.formatteropts, [], norepo=True)
754 def debugextensions(ui, **opts):
755 def debugextensions(ui, **opts):
755 '''show information about active extensions'''
756 '''show information about active extensions'''
756 opts = pycompat.byteskwargs(opts)
757 opts = pycompat.byteskwargs(opts)
757 exts = extensions.extensions(ui)
758 exts = extensions.extensions(ui)
758 hgver = util.version()
759 hgver = util.version()
759 fm = ui.formatter('debugextensions', opts)
760 fm = ui.formatter('debugextensions', opts)
760 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
761 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
761 isinternal = extensions.ismoduleinternal(extmod)
762 isinternal = extensions.ismoduleinternal(extmod)
762 extsource = pycompat.fsencode(extmod.__file__)
763 extsource = pycompat.fsencode(extmod.__file__)
763 if isinternal:
764 if isinternal:
764 exttestedwith = [] # never expose magic string to users
765 exttestedwith = [] # never expose magic string to users
765 else:
766 else:
766 exttestedwith = getattr(extmod, 'testedwith', '').split()
767 exttestedwith = getattr(extmod, 'testedwith', '').split()
767 extbuglink = getattr(extmod, 'buglink', None)
768 extbuglink = getattr(extmod, 'buglink', None)
768
769
769 fm.startitem()
770 fm.startitem()
770
771
771 if ui.quiet or ui.verbose:
772 if ui.quiet or ui.verbose:
772 fm.write('name', '%s\n', extname)
773 fm.write('name', '%s\n', extname)
773 else:
774 else:
774 fm.write('name', '%s', extname)
775 fm.write('name', '%s', extname)
775 if isinternal or hgver in exttestedwith:
776 if isinternal or hgver in exttestedwith:
776 fm.plain('\n')
777 fm.plain('\n')
777 elif not exttestedwith:
778 elif not exttestedwith:
778 fm.plain(_(' (untested!)\n'))
779 fm.plain(_(' (untested!)\n'))
779 else:
780 else:
780 lasttestedversion = exttestedwith[-1]
781 lasttestedversion = exttestedwith[-1]
781 fm.plain(' (%s!)\n' % lasttestedversion)
782 fm.plain(' (%s!)\n' % lasttestedversion)
782
783
783 fm.condwrite(ui.verbose and extsource, 'source',
784 fm.condwrite(ui.verbose and extsource, 'source',
784 _(' location: %s\n'), extsource or "")
785 _(' location: %s\n'), extsource or "")
785
786
786 if ui.verbose:
787 if ui.verbose:
787 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
788 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
788 fm.data(bundled=isinternal)
789 fm.data(bundled=isinternal)
789
790
790 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
791 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
791 _(' tested with: %s\n'),
792 _(' tested with: %s\n'),
792 fm.formatlist(exttestedwith, name='ver'))
793 fm.formatlist(exttestedwith, name='ver'))
793
794
794 fm.condwrite(ui.verbose and extbuglink, 'buglink',
795 fm.condwrite(ui.verbose and extbuglink, 'buglink',
795 _(' bug reporting: %s\n'), extbuglink or "")
796 _(' bug reporting: %s\n'), extbuglink or "")
796
797
797 fm.end()
798 fm.end()
798
799
799 @command('debugfileset',
800 @command('debugfileset',
800 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
801 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
801 _('[-r REV] FILESPEC'))
802 _('[-r REV] FILESPEC'))
802 def debugfileset(ui, repo, expr, **opts):
803 def debugfileset(ui, repo, expr, **opts):
803 '''parse and apply a fileset specification'''
804 '''parse and apply a fileset specification'''
804 ctx = scmutil.revsingle(repo, opts.get(r'rev'), None)
805 ctx = scmutil.revsingle(repo, opts.get(r'rev'), None)
805 if ui.verbose:
806 if ui.verbose:
806 tree = fileset.parse(expr)
807 tree = fileset.parse(expr)
807 ui.note(fileset.prettyformat(tree), "\n")
808 ui.note(fileset.prettyformat(tree), "\n")
808
809
809 for f in ctx.getfileset(expr):
810 for f in ctx.getfileset(expr):
810 ui.write("%s\n" % f)
811 ui.write("%s\n" % f)
811
812
812 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
813 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
813 def debugfsinfo(ui, path="."):
814 def debugfsinfo(ui, path="."):
814 """show information detected about current filesystem"""
815 """show information detected about current filesystem"""
815 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
816 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
816 ui.write(('fstype: %s\n') % (util.getfstype(path) or '(unknown)'))
817 ui.write(('fstype: %s\n') % (util.getfstype(path) or '(unknown)'))
817 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
818 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
818 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
819 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
819 casesensitive = '(unknown)'
820 casesensitive = '(unknown)'
820 try:
821 try:
821 with tempfile.NamedTemporaryFile(prefix='.debugfsinfo', dir=path) as f:
822 with tempfile.NamedTemporaryFile(prefix='.debugfsinfo', dir=path) as f:
822 casesensitive = util.fscasesensitive(f.name) and 'yes' or 'no'
823 casesensitive = util.fscasesensitive(f.name) and 'yes' or 'no'
823 except OSError:
824 except OSError:
824 pass
825 pass
825 ui.write(('case-sensitive: %s\n') % casesensitive)
826 ui.write(('case-sensitive: %s\n') % casesensitive)
826
827
827 @command('debuggetbundle',
828 @command('debuggetbundle',
828 [('H', 'head', [], _('id of head node'), _('ID')),
829 [('H', 'head', [], _('id of head node'), _('ID')),
829 ('C', 'common', [], _('id of common node'), _('ID')),
830 ('C', 'common', [], _('id of common node'), _('ID')),
830 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
831 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
831 _('REPO FILE [-H|-C ID]...'),
832 _('REPO FILE [-H|-C ID]...'),
832 norepo=True)
833 norepo=True)
833 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
834 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
834 """retrieves a bundle from a repo
835 """retrieves a bundle from a repo
835
836
836 Every ID must be a full-length hex node id string. Saves the bundle to the
837 Every ID must be a full-length hex node id string. Saves the bundle to the
837 given file.
838 given file.
838 """
839 """
839 opts = pycompat.byteskwargs(opts)
840 opts = pycompat.byteskwargs(opts)
840 repo = hg.peer(ui, opts, repopath)
841 repo = hg.peer(ui, opts, repopath)
841 if not repo.capable('getbundle'):
842 if not repo.capable('getbundle'):
842 raise error.Abort("getbundle() not supported by target repository")
843 raise error.Abort("getbundle() not supported by target repository")
843 args = {}
844 args = {}
844 if common:
845 if common:
845 args[r'common'] = [bin(s) for s in common]
846 args[r'common'] = [bin(s) for s in common]
846 if head:
847 if head:
847 args[r'heads'] = [bin(s) for s in head]
848 args[r'heads'] = [bin(s) for s in head]
848 # TODO: get desired bundlecaps from command line.
849 # TODO: get desired bundlecaps from command line.
849 args[r'bundlecaps'] = None
850 args[r'bundlecaps'] = None
850 bundle = repo.getbundle('debug', **args)
851 bundle = repo.getbundle('debug', **args)
851
852
852 bundletype = opts.get('type', 'bzip2').lower()
853 bundletype = opts.get('type', 'bzip2').lower()
853 btypes = {'none': 'HG10UN',
854 btypes = {'none': 'HG10UN',
854 'bzip2': 'HG10BZ',
855 'bzip2': 'HG10BZ',
855 'gzip': 'HG10GZ',
856 'gzip': 'HG10GZ',
856 'bundle2': 'HG20'}
857 'bundle2': 'HG20'}
857 bundletype = btypes.get(bundletype)
858 bundletype = btypes.get(bundletype)
858 if bundletype not in bundle2.bundletypes:
859 if bundletype not in bundle2.bundletypes:
859 raise error.Abort(_('unknown bundle type specified with --type'))
860 raise error.Abort(_('unknown bundle type specified with --type'))
860 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
861 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
861
862
862 @command('debugignore', [], '[FILE]')
863 @command('debugignore', [], '[FILE]')
863 def debugignore(ui, repo, *files, **opts):
864 def debugignore(ui, repo, *files, **opts):
864 """display the combined ignore pattern and information about ignored files
865 """display the combined ignore pattern and information about ignored files
865
866
866 With no argument display the combined ignore pattern.
867 With no argument display the combined ignore pattern.
867
868
868 Given space separated file names, shows if the given file is ignored and
869 Given space separated file names, shows if the given file is ignored and
869 if so, show the ignore rule (file and line number) that matched it.
870 if so, show the ignore rule (file and line number) that matched it.
870 """
871 """
871 ignore = repo.dirstate._ignore
872 ignore = repo.dirstate._ignore
872 if not files:
873 if not files:
873 # Show all the patterns
874 # Show all the patterns
874 ui.write("%s\n" % repr(ignore))
875 ui.write("%s\n" % repr(ignore))
875 else:
876 else:
876 m = scmutil.match(repo[None], pats=files)
877 m = scmutil.match(repo[None], pats=files)
877 for f in m.files():
878 for f in m.files():
878 nf = util.normpath(f)
879 nf = util.normpath(f)
879 ignored = None
880 ignored = None
880 ignoredata = None
881 ignoredata = None
881 if nf != '.':
882 if nf != '.':
882 if ignore(nf):
883 if ignore(nf):
883 ignored = nf
884 ignored = nf
884 ignoredata = repo.dirstate._ignorefileandline(nf)
885 ignoredata = repo.dirstate._ignorefileandline(nf)
885 else:
886 else:
886 for p in util.finddirs(nf):
887 for p in util.finddirs(nf):
887 if ignore(p):
888 if ignore(p):
888 ignored = p
889 ignored = p
889 ignoredata = repo.dirstate._ignorefileandline(p)
890 ignoredata = repo.dirstate._ignorefileandline(p)
890 break
891 break
891 if ignored:
892 if ignored:
892 if ignored == nf:
893 if ignored == nf:
893 ui.write(_("%s is ignored\n") % m.uipath(f))
894 ui.write(_("%s is ignored\n") % m.uipath(f))
894 else:
895 else:
895 ui.write(_("%s is ignored because of "
896 ui.write(_("%s is ignored because of "
896 "containing folder %s\n")
897 "containing folder %s\n")
897 % (m.uipath(f), ignored))
898 % (m.uipath(f), ignored))
898 ignorefile, lineno, line = ignoredata
899 ignorefile, lineno, line = ignoredata
899 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
900 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
900 % (ignorefile, lineno, line))
901 % (ignorefile, lineno, line))
901 else:
902 else:
902 ui.write(_("%s is not ignored\n") % m.uipath(f))
903 ui.write(_("%s is not ignored\n") % m.uipath(f))
903
904
904 @command('debugindex', cmdutil.debugrevlogopts +
905 @command('debugindex', cmdutil.debugrevlogopts +
905 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
906 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
906 _('[-f FORMAT] -c|-m|FILE'),
907 _('[-f FORMAT] -c|-m|FILE'),
907 optionalrepo=True)
908 optionalrepo=True)
908 def debugindex(ui, repo, file_=None, **opts):
909 def debugindex(ui, repo, file_=None, **opts):
909 """dump the contents of an index file"""
910 """dump the contents of an index file"""
910 opts = pycompat.byteskwargs(opts)
911 opts = pycompat.byteskwargs(opts)
911 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
912 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
912 format = opts.get('format', 0)
913 format = opts.get('format', 0)
913 if format not in (0, 1):
914 if format not in (0, 1):
914 raise error.Abort(_("unknown format %d") % format)
915 raise error.Abort(_("unknown format %d") % format)
915
916
916 generaldelta = r.version & revlog.FLAG_GENERALDELTA
917 generaldelta = r.version & revlog.FLAG_GENERALDELTA
917 if generaldelta:
918 if generaldelta:
918 basehdr = ' delta'
919 basehdr = ' delta'
919 else:
920 else:
920 basehdr = ' base'
921 basehdr = ' base'
921
922
922 if ui.debugflag:
923 if ui.debugflag:
923 shortfn = hex
924 shortfn = hex
924 else:
925 else:
925 shortfn = short
926 shortfn = short
926
927
927 # There might not be anything in r, so have a sane default
928 # There might not be anything in r, so have a sane default
928 idlen = 12
929 idlen = 12
929 for i in r:
930 for i in r:
930 idlen = len(shortfn(r.node(i)))
931 idlen = len(shortfn(r.node(i)))
931 break
932 break
932
933
933 if format == 0:
934 if format == 0:
934 ui.write((" rev offset length " + basehdr + " linkrev"
935 ui.write((" rev offset length " + basehdr + " linkrev"
935 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
936 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
936 elif format == 1:
937 elif format == 1:
937 ui.write((" rev flag offset length"
938 ui.write((" rev flag offset length"
938 " size " + basehdr + " link p1 p2"
939 " size " + basehdr + " link p1 p2"
939 " %s\n") % "nodeid".rjust(idlen))
940 " %s\n") % "nodeid".rjust(idlen))
940
941
941 for i in r:
942 for i in r:
942 node = r.node(i)
943 node = r.node(i)
943 if generaldelta:
944 if generaldelta:
944 base = r.deltaparent(i)
945 base = r.deltaparent(i)
945 else:
946 else:
946 base = r.chainbase(i)
947 base = r.chainbase(i)
947 if format == 0:
948 if format == 0:
948 try:
949 try:
949 pp = r.parents(node)
950 pp = r.parents(node)
950 except Exception:
951 except Exception:
951 pp = [nullid, nullid]
952 pp = [nullid, nullid]
952 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
953 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
953 i, r.start(i), r.length(i), base, r.linkrev(i),
954 i, r.start(i), r.length(i), base, r.linkrev(i),
954 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
955 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
955 elif format == 1:
956 elif format == 1:
956 pr = r.parentrevs(i)
957 pr = r.parentrevs(i)
957 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
958 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
958 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
959 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
959 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
960 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
960
961
961 @command('debugindexdot', cmdutil.debugrevlogopts,
962 @command('debugindexdot', cmdutil.debugrevlogopts,
962 _('-c|-m|FILE'), optionalrepo=True)
963 _('-c|-m|FILE'), optionalrepo=True)
963 def debugindexdot(ui, repo, file_=None, **opts):
964 def debugindexdot(ui, repo, file_=None, **opts):
964 """dump an index DAG as a graphviz dot file"""
965 """dump an index DAG as a graphviz dot file"""
965 opts = pycompat.byteskwargs(opts)
966 opts = pycompat.byteskwargs(opts)
966 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
967 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
967 ui.write(("digraph G {\n"))
968 ui.write(("digraph G {\n"))
968 for i in r:
969 for i in r:
969 node = r.node(i)
970 node = r.node(i)
970 pp = r.parents(node)
971 pp = r.parents(node)
971 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
972 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
972 if pp[1] != nullid:
973 if pp[1] != nullid:
973 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
974 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
974 ui.write("}\n")
975 ui.write("}\n")
975
976
976 @command('debuginstall', [] + cmdutil.formatteropts, '', norepo=True)
977 @command('debuginstall', [] + cmdutil.formatteropts, '', norepo=True)
977 def debuginstall(ui, **opts):
978 def debuginstall(ui, **opts):
978 '''test Mercurial installation
979 '''test Mercurial installation
979
980
980 Returns 0 on success.
981 Returns 0 on success.
981 '''
982 '''
982 opts = pycompat.byteskwargs(opts)
983 opts = pycompat.byteskwargs(opts)
983
984
984 def writetemp(contents):
985 def writetemp(contents):
985 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
986 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
986 f = os.fdopen(fd, pycompat.sysstr("wb"))
987 f = os.fdopen(fd, pycompat.sysstr("wb"))
987 f.write(contents)
988 f.write(contents)
988 f.close()
989 f.close()
989 return name
990 return name
990
991
991 problems = 0
992 problems = 0
992
993
993 fm = ui.formatter('debuginstall', opts)
994 fm = ui.formatter('debuginstall', opts)
994 fm.startitem()
995 fm.startitem()
995
996
996 # encoding
997 # encoding
997 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
998 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
998 err = None
999 err = None
999 try:
1000 try:
1000 encoding.fromlocal("test")
1001 codecs.lookup(pycompat.sysstr(encoding.encoding))
1001 except error.Abort as inst:
1002 except LookupError as inst:
1002 err = inst
1003 err = inst
1003 problems += 1
1004 problems += 1
1004 fm.condwrite(err, 'encodingerror', _(" %s\n"
1005 fm.condwrite(err, 'encodingerror', _(" %s\n"
1005 " (check that your locale is properly set)\n"), err)
1006 " (check that your locale is properly set)\n"), err)
1006
1007
1007 # Python
1008 # Python
1008 fm.write('pythonexe', _("checking Python executable (%s)\n"),
1009 fm.write('pythonexe', _("checking Python executable (%s)\n"),
1009 pycompat.sysexecutable)
1010 pycompat.sysexecutable)
1010 fm.write('pythonver', _("checking Python version (%s)\n"),
1011 fm.write('pythonver', _("checking Python version (%s)\n"),
1011 ("%d.%d.%d" % sys.version_info[:3]))
1012 ("%d.%d.%d" % sys.version_info[:3]))
1012 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
1013 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
1013 os.path.dirname(pycompat.fsencode(os.__file__)))
1014 os.path.dirname(pycompat.fsencode(os.__file__)))
1014
1015
1015 security = set(sslutil.supportedprotocols)
1016 security = set(sslutil.supportedprotocols)
1016 if sslutil.hassni:
1017 if sslutil.hassni:
1017 security.add('sni')
1018 security.add('sni')
1018
1019
1019 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
1020 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
1020 fm.formatlist(sorted(security), name='protocol',
1021 fm.formatlist(sorted(security), name='protocol',
1021 fmt='%s', sep=','))
1022 fmt='%s', sep=','))
1022
1023
1023 # These are warnings, not errors. So don't increment problem count. This
1024 # These are warnings, not errors. So don't increment problem count. This
1024 # may change in the future.
1025 # may change in the future.
1025 if 'tls1.2' not in security:
1026 if 'tls1.2' not in security:
1026 fm.plain(_(' TLS 1.2 not supported by Python install; '
1027 fm.plain(_(' TLS 1.2 not supported by Python install; '
1027 'network connections lack modern security\n'))
1028 'network connections lack modern security\n'))
1028 if 'sni' not in security:
1029 if 'sni' not in security:
1029 fm.plain(_(' SNI not supported by Python install; may have '
1030 fm.plain(_(' SNI not supported by Python install; may have '
1030 'connectivity issues with some servers\n'))
1031 'connectivity issues with some servers\n'))
1031
1032
1032 # TODO print CA cert info
1033 # TODO print CA cert info
1033
1034
1034 # hg version
1035 # hg version
1035 hgver = util.version()
1036 hgver = util.version()
1036 fm.write('hgver', _("checking Mercurial version (%s)\n"),
1037 fm.write('hgver', _("checking Mercurial version (%s)\n"),
1037 hgver.split('+')[0])
1038 hgver.split('+')[0])
1038 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
1039 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
1039 '+'.join(hgver.split('+')[1:]))
1040 '+'.join(hgver.split('+')[1:]))
1040
1041
1041 # compiled modules
1042 # compiled modules
1042 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
1043 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
1043 policy.policy)
1044 policy.policy)
1044 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
1045 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
1045 os.path.dirname(pycompat.fsencode(__file__)))
1046 os.path.dirname(pycompat.fsencode(__file__)))
1046
1047
1047 if policy.policy in ('c', 'allow'):
1048 if policy.policy in ('c', 'allow'):
1048 err = None
1049 err = None
1049 try:
1050 try:
1050 from .cext import (
1051 from .cext import (
1051 base85,
1052 base85,
1052 bdiff,
1053 bdiff,
1053 mpatch,
1054 mpatch,
1054 osutil,
1055 osutil,
1055 )
1056 )
1056 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1057 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1057 except Exception as inst:
1058 except Exception as inst:
1058 err = inst
1059 err = inst
1059 problems += 1
1060 problems += 1
1060 fm.condwrite(err, 'extensionserror', " %s\n", err)
1061 fm.condwrite(err, 'extensionserror', " %s\n", err)
1061
1062
1062 compengines = util.compengines._engines.values()
1063 compengines = util.compengines._engines.values()
1063 fm.write('compengines', _('checking registered compression engines (%s)\n'),
1064 fm.write('compengines', _('checking registered compression engines (%s)\n'),
1064 fm.formatlist(sorted(e.name() for e in compengines),
1065 fm.formatlist(sorted(e.name() for e in compengines),
1065 name='compengine', fmt='%s', sep=', '))
1066 name='compengine', fmt='%s', sep=', '))
1066 fm.write('compenginesavail', _('checking available compression engines '
1067 fm.write('compenginesavail', _('checking available compression engines '
1067 '(%s)\n'),
1068 '(%s)\n'),
1068 fm.formatlist(sorted(e.name() for e in compengines
1069 fm.formatlist(sorted(e.name() for e in compengines
1069 if e.available()),
1070 if e.available()),
1070 name='compengine', fmt='%s', sep=', '))
1071 name='compengine', fmt='%s', sep=', '))
1071 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
1072 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
1072 fm.write('compenginesserver', _('checking available compression engines '
1073 fm.write('compenginesserver', _('checking available compression engines '
1073 'for wire protocol (%s)\n'),
1074 'for wire protocol (%s)\n'),
1074 fm.formatlist([e.name() for e in wirecompengines
1075 fm.formatlist([e.name() for e in wirecompengines
1075 if e.wireprotosupport()],
1076 if e.wireprotosupport()],
1076 name='compengine', fmt='%s', sep=', '))
1077 name='compengine', fmt='%s', sep=', '))
1077
1078
1078 # templates
1079 # templates
1079 p = templater.templatepaths()
1080 p = templater.templatepaths()
1080 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1081 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1081 fm.condwrite(not p, '', _(" no template directories found\n"))
1082 fm.condwrite(not p, '', _(" no template directories found\n"))
1082 if p:
1083 if p:
1083 m = templater.templatepath("map-cmdline.default")
1084 m = templater.templatepath("map-cmdline.default")
1084 if m:
1085 if m:
1085 # template found, check if it is working
1086 # template found, check if it is working
1086 err = None
1087 err = None
1087 try:
1088 try:
1088 templater.templater.frommapfile(m)
1089 templater.templater.frommapfile(m)
1089 except Exception as inst:
1090 except Exception as inst:
1090 err = inst
1091 err = inst
1091 p = None
1092 p = None
1092 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1093 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1093 else:
1094 else:
1094 p = None
1095 p = None
1095 fm.condwrite(p, 'defaulttemplate',
1096 fm.condwrite(p, 'defaulttemplate',
1096 _("checking default template (%s)\n"), m)
1097 _("checking default template (%s)\n"), m)
1097 fm.condwrite(not m, 'defaulttemplatenotfound',
1098 fm.condwrite(not m, 'defaulttemplatenotfound',
1098 _(" template '%s' not found\n"), "default")
1099 _(" template '%s' not found\n"), "default")
1099 if not p:
1100 if not p:
1100 problems += 1
1101 problems += 1
1101 fm.condwrite(not p, '',
1102 fm.condwrite(not p, '',
1102 _(" (templates seem to have been installed incorrectly)\n"))
1103 _(" (templates seem to have been installed incorrectly)\n"))
1103
1104
1104 # editor
1105 # editor
1105 editor = ui.geteditor()
1106 editor = ui.geteditor()
1106 editor = util.expandpath(editor)
1107 editor = util.expandpath(editor)
1107 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
1108 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
1108 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
1109 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
1109 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1110 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1110 _(" No commit editor set and can't find %s in PATH\n"
1111 _(" No commit editor set and can't find %s in PATH\n"
1111 " (specify a commit editor in your configuration"
1112 " (specify a commit editor in your configuration"
1112 " file)\n"), not cmdpath and editor == 'vi' and editor)
1113 " file)\n"), not cmdpath and editor == 'vi' and editor)
1113 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1114 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1114 _(" Can't find editor '%s' in PATH\n"
1115 _(" Can't find editor '%s' in PATH\n"
1115 " (specify a commit editor in your configuration"
1116 " (specify a commit editor in your configuration"
1116 " file)\n"), not cmdpath and editor)
1117 " file)\n"), not cmdpath and editor)
1117 if not cmdpath and editor != 'vi':
1118 if not cmdpath and editor != 'vi':
1118 problems += 1
1119 problems += 1
1119
1120
1120 # check username
1121 # check username
1121 username = None
1122 username = None
1122 err = None
1123 err = None
1123 try:
1124 try:
1124 username = ui.username()
1125 username = ui.username()
1125 except error.Abort as e:
1126 except error.Abort as e:
1126 err = e
1127 err = e
1127 problems += 1
1128 problems += 1
1128
1129
1129 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1130 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1130 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1131 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1131 " (specify a username in your configuration file)\n"), err)
1132 " (specify a username in your configuration file)\n"), err)
1132
1133
1133 fm.condwrite(not problems, '',
1134 fm.condwrite(not problems, '',
1134 _("no problems detected\n"))
1135 _("no problems detected\n"))
1135 if not problems:
1136 if not problems:
1136 fm.data(problems=problems)
1137 fm.data(problems=problems)
1137 fm.condwrite(problems, 'problems',
1138 fm.condwrite(problems, 'problems',
1138 _("%d problems detected,"
1139 _("%d problems detected,"
1139 " please check your install!\n"), problems)
1140 " please check your install!\n"), problems)
1140 fm.end()
1141 fm.end()
1141
1142
1142 return problems
1143 return problems
1143
1144
1144 @command('debugknown', [], _('REPO ID...'), norepo=True)
1145 @command('debugknown', [], _('REPO ID...'), norepo=True)
1145 def debugknown(ui, repopath, *ids, **opts):
1146 def debugknown(ui, repopath, *ids, **opts):
1146 """test whether node ids are known to a repo
1147 """test whether node ids are known to a repo
1147
1148
1148 Every ID must be a full-length hex node id string. Returns a list of 0s
1149 Every ID must be a full-length hex node id string. Returns a list of 0s
1149 and 1s indicating unknown/known.
1150 and 1s indicating unknown/known.
1150 """
1151 """
1151 opts = pycompat.byteskwargs(opts)
1152 opts = pycompat.byteskwargs(opts)
1152 repo = hg.peer(ui, opts, repopath)
1153 repo = hg.peer(ui, opts, repopath)
1153 if not repo.capable('known'):
1154 if not repo.capable('known'):
1154 raise error.Abort("known() not supported by target repository")
1155 raise error.Abort("known() not supported by target repository")
1155 flags = repo.known([bin(s) for s in ids])
1156 flags = repo.known([bin(s) for s in ids])
1156 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1157 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1157
1158
1158 @command('debuglabelcomplete', [], _('LABEL...'))
1159 @command('debuglabelcomplete', [], _('LABEL...'))
1159 def debuglabelcomplete(ui, repo, *args):
1160 def debuglabelcomplete(ui, repo, *args):
1160 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1161 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1161 debugnamecomplete(ui, repo, *args)
1162 debugnamecomplete(ui, repo, *args)
1162
1163
1163 @command('debuglocks',
1164 @command('debuglocks',
1164 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1165 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1165 ('W', 'force-wlock', None,
1166 ('W', 'force-wlock', None,
1166 _('free the working state lock (DANGEROUS)'))],
1167 _('free the working state lock (DANGEROUS)'))],
1167 _('[OPTION]...'))
1168 _('[OPTION]...'))
1168 def debuglocks(ui, repo, **opts):
1169 def debuglocks(ui, repo, **opts):
1169 """show or modify state of locks
1170 """show or modify state of locks
1170
1171
1171 By default, this command will show which locks are held. This
1172 By default, this command will show which locks are held. This
1172 includes the user and process holding the lock, the amount of time
1173 includes the user and process holding the lock, the amount of time
1173 the lock has been held, and the machine name where the process is
1174 the lock has been held, and the machine name where the process is
1174 running if it's not local.
1175 running if it's not local.
1175
1176
1176 Locks protect the integrity of Mercurial's data, so should be
1177 Locks protect the integrity of Mercurial's data, so should be
1177 treated with care. System crashes or other interruptions may cause
1178 treated with care. System crashes or other interruptions may cause
1178 locks to not be properly released, though Mercurial will usually
1179 locks to not be properly released, though Mercurial will usually
1179 detect and remove such stale locks automatically.
1180 detect and remove such stale locks automatically.
1180
1181
1181 However, detecting stale locks may not always be possible (for
1182 However, detecting stale locks may not always be possible (for
1182 instance, on a shared filesystem). Removing locks may also be
1183 instance, on a shared filesystem). Removing locks may also be
1183 blocked by filesystem permissions.
1184 blocked by filesystem permissions.
1184
1185
1185 Returns 0 if no locks are held.
1186 Returns 0 if no locks are held.
1186
1187
1187 """
1188 """
1188
1189
1189 if opts.get(r'force_lock'):
1190 if opts.get(r'force_lock'):
1190 repo.svfs.unlink('lock')
1191 repo.svfs.unlink('lock')
1191 if opts.get(r'force_wlock'):
1192 if opts.get(r'force_wlock'):
1192 repo.vfs.unlink('wlock')
1193 repo.vfs.unlink('wlock')
1193 if opts.get(r'force_lock') or opts.get(r'force_lock'):
1194 if opts.get(r'force_lock') or opts.get(r'force_lock'):
1194 return 0
1195 return 0
1195
1196
1196 now = time.time()
1197 now = time.time()
1197 held = 0
1198 held = 0
1198
1199
1199 def report(vfs, name, method):
1200 def report(vfs, name, method):
1200 # this causes stale locks to get reaped for more accurate reporting
1201 # this causes stale locks to get reaped for more accurate reporting
1201 try:
1202 try:
1202 l = method(False)
1203 l = method(False)
1203 except error.LockHeld:
1204 except error.LockHeld:
1204 l = None
1205 l = None
1205
1206
1206 if l:
1207 if l:
1207 l.release()
1208 l.release()
1208 else:
1209 else:
1209 try:
1210 try:
1210 stat = vfs.lstat(name)
1211 stat = vfs.lstat(name)
1211 age = now - stat.st_mtime
1212 age = now - stat.st_mtime
1212 user = util.username(stat.st_uid)
1213 user = util.username(stat.st_uid)
1213 locker = vfs.readlock(name)
1214 locker = vfs.readlock(name)
1214 if ":" in locker:
1215 if ":" in locker:
1215 host, pid = locker.split(':')
1216 host, pid = locker.split(':')
1216 if host == socket.gethostname():
1217 if host == socket.gethostname():
1217 locker = 'user %s, process %s' % (user, pid)
1218 locker = 'user %s, process %s' % (user, pid)
1218 else:
1219 else:
1219 locker = 'user %s, process %s, host %s' \
1220 locker = 'user %s, process %s, host %s' \
1220 % (user, pid, host)
1221 % (user, pid, host)
1221 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1222 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1222 return 1
1223 return 1
1223 except OSError as e:
1224 except OSError as e:
1224 if e.errno != errno.ENOENT:
1225 if e.errno != errno.ENOENT:
1225 raise
1226 raise
1226
1227
1227 ui.write(("%-6s free\n") % (name + ":"))
1228 ui.write(("%-6s free\n") % (name + ":"))
1228 return 0
1229 return 0
1229
1230
1230 held += report(repo.svfs, "lock", repo.lock)
1231 held += report(repo.svfs, "lock", repo.lock)
1231 held += report(repo.vfs, "wlock", repo.wlock)
1232 held += report(repo.vfs, "wlock", repo.wlock)
1232
1233
1233 return held
1234 return held
1234
1235
1235 @command('debugmergestate', [], '')
1236 @command('debugmergestate', [], '')
1236 def debugmergestate(ui, repo, *args):
1237 def debugmergestate(ui, repo, *args):
1237 """print merge state
1238 """print merge state
1238
1239
1239 Use --verbose to print out information about whether v1 or v2 merge state
1240 Use --verbose to print out information about whether v1 or v2 merge state
1240 was chosen."""
1241 was chosen."""
1241 def _hashornull(h):
1242 def _hashornull(h):
1242 if h == nullhex:
1243 if h == nullhex:
1243 return 'null'
1244 return 'null'
1244 else:
1245 else:
1245 return h
1246 return h
1246
1247
1247 def printrecords(version):
1248 def printrecords(version):
1248 ui.write(('* version %s records\n') % version)
1249 ui.write(('* version %s records\n') % version)
1249 if version == 1:
1250 if version == 1:
1250 records = v1records
1251 records = v1records
1251 else:
1252 else:
1252 records = v2records
1253 records = v2records
1253
1254
1254 for rtype, record in records:
1255 for rtype, record in records:
1255 # pretty print some record types
1256 # pretty print some record types
1256 if rtype == 'L':
1257 if rtype == 'L':
1257 ui.write(('local: %s\n') % record)
1258 ui.write(('local: %s\n') % record)
1258 elif rtype == 'O':
1259 elif rtype == 'O':
1259 ui.write(('other: %s\n') % record)
1260 ui.write(('other: %s\n') % record)
1260 elif rtype == 'm':
1261 elif rtype == 'm':
1261 driver, mdstate = record.split('\0', 1)
1262 driver, mdstate = record.split('\0', 1)
1262 ui.write(('merge driver: %s (state "%s")\n')
1263 ui.write(('merge driver: %s (state "%s")\n')
1263 % (driver, mdstate))
1264 % (driver, mdstate))
1264 elif rtype in 'FDC':
1265 elif rtype in 'FDC':
1265 r = record.split('\0')
1266 r = record.split('\0')
1266 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1267 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1267 if version == 1:
1268 if version == 1:
1268 onode = 'not stored in v1 format'
1269 onode = 'not stored in v1 format'
1269 flags = r[7]
1270 flags = r[7]
1270 else:
1271 else:
1271 onode, flags = r[7:9]
1272 onode, flags = r[7:9]
1272 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1273 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1273 % (f, rtype, state, _hashornull(hash)))
1274 % (f, rtype, state, _hashornull(hash)))
1274 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1275 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1275 ui.write((' ancestor path: %s (node %s)\n')
1276 ui.write((' ancestor path: %s (node %s)\n')
1276 % (afile, _hashornull(anode)))
1277 % (afile, _hashornull(anode)))
1277 ui.write((' other path: %s (node %s)\n')
1278 ui.write((' other path: %s (node %s)\n')
1278 % (ofile, _hashornull(onode)))
1279 % (ofile, _hashornull(onode)))
1279 elif rtype == 'f':
1280 elif rtype == 'f':
1280 filename, rawextras = record.split('\0', 1)
1281 filename, rawextras = record.split('\0', 1)
1281 extras = rawextras.split('\0')
1282 extras = rawextras.split('\0')
1282 i = 0
1283 i = 0
1283 extrastrings = []
1284 extrastrings = []
1284 while i < len(extras):
1285 while i < len(extras):
1285 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1286 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1286 i += 2
1287 i += 2
1287
1288
1288 ui.write(('file extras: %s (%s)\n')
1289 ui.write(('file extras: %s (%s)\n')
1289 % (filename, ', '.join(extrastrings)))
1290 % (filename, ', '.join(extrastrings)))
1290 elif rtype == 'l':
1291 elif rtype == 'l':
1291 labels = record.split('\0', 2)
1292 labels = record.split('\0', 2)
1292 labels = [l for l in labels if len(l) > 0]
1293 labels = [l for l in labels if len(l) > 0]
1293 ui.write(('labels:\n'))
1294 ui.write(('labels:\n'))
1294 ui.write((' local: %s\n' % labels[0]))
1295 ui.write((' local: %s\n' % labels[0]))
1295 ui.write((' other: %s\n' % labels[1]))
1296 ui.write((' other: %s\n' % labels[1]))
1296 if len(labels) > 2:
1297 if len(labels) > 2:
1297 ui.write((' base: %s\n' % labels[2]))
1298 ui.write((' base: %s\n' % labels[2]))
1298 else:
1299 else:
1299 ui.write(('unrecognized entry: %s\t%s\n')
1300 ui.write(('unrecognized entry: %s\t%s\n')
1300 % (rtype, record.replace('\0', '\t')))
1301 % (rtype, record.replace('\0', '\t')))
1301
1302
1302 # Avoid mergestate.read() since it may raise an exception for unsupported
1303 # Avoid mergestate.read() since it may raise an exception for unsupported
1303 # merge state records. We shouldn't be doing this, but this is OK since this
1304 # merge state records. We shouldn't be doing this, but this is OK since this
1304 # command is pretty low-level.
1305 # command is pretty low-level.
1305 ms = mergemod.mergestate(repo)
1306 ms = mergemod.mergestate(repo)
1306
1307
1307 # sort so that reasonable information is on top
1308 # sort so that reasonable information is on top
1308 v1records = ms._readrecordsv1()
1309 v1records = ms._readrecordsv1()
1309 v2records = ms._readrecordsv2()
1310 v2records = ms._readrecordsv2()
1310 order = 'LOml'
1311 order = 'LOml'
1311 def key(r):
1312 def key(r):
1312 idx = order.find(r[0])
1313 idx = order.find(r[0])
1313 if idx == -1:
1314 if idx == -1:
1314 return (1, r[1])
1315 return (1, r[1])
1315 else:
1316 else:
1316 return (0, idx)
1317 return (0, idx)
1317 v1records.sort(key=key)
1318 v1records.sort(key=key)
1318 v2records.sort(key=key)
1319 v2records.sort(key=key)
1319
1320
1320 if not v1records and not v2records:
1321 if not v1records and not v2records:
1321 ui.write(('no merge state found\n'))
1322 ui.write(('no merge state found\n'))
1322 elif not v2records:
1323 elif not v2records:
1323 ui.note(('no version 2 merge state\n'))
1324 ui.note(('no version 2 merge state\n'))
1324 printrecords(1)
1325 printrecords(1)
1325 elif ms._v1v2match(v1records, v2records):
1326 elif ms._v1v2match(v1records, v2records):
1326 ui.note(('v1 and v2 states match: using v2\n'))
1327 ui.note(('v1 and v2 states match: using v2\n'))
1327 printrecords(2)
1328 printrecords(2)
1328 else:
1329 else:
1329 ui.note(('v1 and v2 states mismatch: using v1\n'))
1330 ui.note(('v1 and v2 states mismatch: using v1\n'))
1330 printrecords(1)
1331 printrecords(1)
1331 if ui.verbose:
1332 if ui.verbose:
1332 printrecords(2)
1333 printrecords(2)
1333
1334
1334 @command('debugnamecomplete', [], _('NAME...'))
1335 @command('debugnamecomplete', [], _('NAME...'))
1335 def debugnamecomplete(ui, repo, *args):
1336 def debugnamecomplete(ui, repo, *args):
1336 '''complete "names" - tags, open branch names, bookmark names'''
1337 '''complete "names" - tags, open branch names, bookmark names'''
1337
1338
1338 names = set()
1339 names = set()
1339 # since we previously only listed open branches, we will handle that
1340 # since we previously only listed open branches, we will handle that
1340 # specially (after this for loop)
1341 # specially (after this for loop)
1341 for name, ns in repo.names.iteritems():
1342 for name, ns in repo.names.iteritems():
1342 if name != 'branches':
1343 if name != 'branches':
1343 names.update(ns.listnames(repo))
1344 names.update(ns.listnames(repo))
1344 names.update(tag for (tag, heads, tip, closed)
1345 names.update(tag for (tag, heads, tip, closed)
1345 in repo.branchmap().iterbranches() if not closed)
1346 in repo.branchmap().iterbranches() if not closed)
1346 completions = set()
1347 completions = set()
1347 if not args:
1348 if not args:
1348 args = ['']
1349 args = ['']
1349 for a in args:
1350 for a in args:
1350 completions.update(n for n in names if n.startswith(a))
1351 completions.update(n for n in names if n.startswith(a))
1351 ui.write('\n'.join(sorted(completions)))
1352 ui.write('\n'.join(sorted(completions)))
1352 ui.write('\n')
1353 ui.write('\n')
1353
1354
1354 @command('debugobsolete',
1355 @command('debugobsolete',
1355 [('', 'flags', 0, _('markers flag')),
1356 [('', 'flags', 0, _('markers flag')),
1356 ('', 'record-parents', False,
1357 ('', 'record-parents', False,
1357 _('record parent information for the precursor')),
1358 _('record parent information for the precursor')),
1358 ('r', 'rev', [], _('display markers relevant to REV')),
1359 ('r', 'rev', [], _('display markers relevant to REV')),
1359 ('', 'exclusive', False, _('restrict display to markers only '
1360 ('', 'exclusive', False, _('restrict display to markers only '
1360 'relevant to REV')),
1361 'relevant to REV')),
1361 ('', 'index', False, _('display index of the marker')),
1362 ('', 'index', False, _('display index of the marker')),
1362 ('', 'delete', [], _('delete markers specified by indices')),
1363 ('', 'delete', [], _('delete markers specified by indices')),
1363 ] + cmdutil.commitopts2 + cmdutil.formatteropts,
1364 ] + cmdutil.commitopts2 + cmdutil.formatteropts,
1364 _('[OBSOLETED [REPLACEMENT ...]]'))
1365 _('[OBSOLETED [REPLACEMENT ...]]'))
1365 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1366 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1366 """create arbitrary obsolete marker
1367 """create arbitrary obsolete marker
1367
1368
1368 With no arguments, displays the list of obsolescence markers."""
1369 With no arguments, displays the list of obsolescence markers."""
1369
1370
1370 opts = pycompat.byteskwargs(opts)
1371 opts = pycompat.byteskwargs(opts)
1371
1372
1372 def parsenodeid(s):
1373 def parsenodeid(s):
1373 try:
1374 try:
1374 # We do not use revsingle/revrange functions here to accept
1375 # We do not use revsingle/revrange functions here to accept
1375 # arbitrary node identifiers, possibly not present in the
1376 # arbitrary node identifiers, possibly not present in the
1376 # local repository.
1377 # local repository.
1377 n = bin(s)
1378 n = bin(s)
1378 if len(n) != len(nullid):
1379 if len(n) != len(nullid):
1379 raise TypeError()
1380 raise TypeError()
1380 return n
1381 return n
1381 except TypeError:
1382 except TypeError:
1382 raise error.Abort('changeset references must be full hexadecimal '
1383 raise error.Abort('changeset references must be full hexadecimal '
1383 'node identifiers')
1384 'node identifiers')
1384
1385
1385 if opts.get('delete'):
1386 if opts.get('delete'):
1386 indices = []
1387 indices = []
1387 for v in opts.get('delete'):
1388 for v in opts.get('delete'):
1388 try:
1389 try:
1389 indices.append(int(v))
1390 indices.append(int(v))
1390 except ValueError:
1391 except ValueError:
1391 raise error.Abort(_('invalid index value: %r') % v,
1392 raise error.Abort(_('invalid index value: %r') % v,
1392 hint=_('use integers for indices'))
1393 hint=_('use integers for indices'))
1393
1394
1394 if repo.currenttransaction():
1395 if repo.currenttransaction():
1395 raise error.Abort(_('cannot delete obsmarkers in the middle '
1396 raise error.Abort(_('cannot delete obsmarkers in the middle '
1396 'of transaction.'))
1397 'of transaction.'))
1397
1398
1398 with repo.lock():
1399 with repo.lock():
1399 n = repair.deleteobsmarkers(repo.obsstore, indices)
1400 n = repair.deleteobsmarkers(repo.obsstore, indices)
1400 ui.write(_('deleted %i obsolescence markers\n') % n)
1401 ui.write(_('deleted %i obsolescence markers\n') % n)
1401
1402
1402 return
1403 return
1403
1404
1404 if precursor is not None:
1405 if precursor is not None:
1405 if opts['rev']:
1406 if opts['rev']:
1406 raise error.Abort('cannot select revision when creating marker')
1407 raise error.Abort('cannot select revision when creating marker')
1407 metadata = {}
1408 metadata = {}
1408 metadata['user'] = opts['user'] or ui.username()
1409 metadata['user'] = opts['user'] or ui.username()
1409 succs = tuple(parsenodeid(succ) for succ in successors)
1410 succs = tuple(parsenodeid(succ) for succ in successors)
1410 l = repo.lock()
1411 l = repo.lock()
1411 try:
1412 try:
1412 tr = repo.transaction('debugobsolete')
1413 tr = repo.transaction('debugobsolete')
1413 try:
1414 try:
1414 date = opts.get('date')
1415 date = opts.get('date')
1415 if date:
1416 if date:
1416 date = util.parsedate(date)
1417 date = util.parsedate(date)
1417 else:
1418 else:
1418 date = None
1419 date = None
1419 prec = parsenodeid(precursor)
1420 prec = parsenodeid(precursor)
1420 parents = None
1421 parents = None
1421 if opts['record_parents']:
1422 if opts['record_parents']:
1422 if prec not in repo.unfiltered():
1423 if prec not in repo.unfiltered():
1423 raise error.Abort('cannot used --record-parents on '
1424 raise error.Abort('cannot used --record-parents on '
1424 'unknown changesets')
1425 'unknown changesets')
1425 parents = repo.unfiltered()[prec].parents()
1426 parents = repo.unfiltered()[prec].parents()
1426 parents = tuple(p.node() for p in parents)
1427 parents = tuple(p.node() for p in parents)
1427 repo.obsstore.create(tr, prec, succs, opts['flags'],
1428 repo.obsstore.create(tr, prec, succs, opts['flags'],
1428 parents=parents, date=date,
1429 parents=parents, date=date,
1429 metadata=metadata, ui=ui)
1430 metadata=metadata, ui=ui)
1430 tr.close()
1431 tr.close()
1431 except ValueError as exc:
1432 except ValueError as exc:
1432 raise error.Abort(_('bad obsmarker input: %s') % exc)
1433 raise error.Abort(_('bad obsmarker input: %s') % exc)
1433 finally:
1434 finally:
1434 tr.release()
1435 tr.release()
1435 finally:
1436 finally:
1436 l.release()
1437 l.release()
1437 else:
1438 else:
1438 if opts['rev']:
1439 if opts['rev']:
1439 revs = scmutil.revrange(repo, opts['rev'])
1440 revs = scmutil.revrange(repo, opts['rev'])
1440 nodes = [repo[r].node() for r in revs]
1441 nodes = [repo[r].node() for r in revs]
1441 markers = list(obsutil.getmarkers(repo, nodes=nodes,
1442 markers = list(obsutil.getmarkers(repo, nodes=nodes,
1442 exclusive=opts['exclusive']))
1443 exclusive=opts['exclusive']))
1443 markers.sort(key=lambda x: x._data)
1444 markers.sort(key=lambda x: x._data)
1444 else:
1445 else:
1445 markers = obsutil.getmarkers(repo)
1446 markers = obsutil.getmarkers(repo)
1446
1447
1447 markerstoiter = markers
1448 markerstoiter = markers
1448 isrelevant = lambda m: True
1449 isrelevant = lambda m: True
1449 if opts.get('rev') and opts.get('index'):
1450 if opts.get('rev') and opts.get('index'):
1450 markerstoiter = obsutil.getmarkers(repo)
1451 markerstoiter = obsutil.getmarkers(repo)
1451 markerset = set(markers)
1452 markerset = set(markers)
1452 isrelevant = lambda m: m in markerset
1453 isrelevant = lambda m: m in markerset
1453
1454
1454 fm = ui.formatter('debugobsolete', opts)
1455 fm = ui.formatter('debugobsolete', opts)
1455 for i, m in enumerate(markerstoiter):
1456 for i, m in enumerate(markerstoiter):
1456 if not isrelevant(m):
1457 if not isrelevant(m):
1457 # marker can be irrelevant when we're iterating over a set
1458 # marker can be irrelevant when we're iterating over a set
1458 # of markers (markerstoiter) which is bigger than the set
1459 # of markers (markerstoiter) which is bigger than the set
1459 # of markers we want to display (markers)
1460 # of markers we want to display (markers)
1460 # this can happen if both --index and --rev options are
1461 # this can happen if both --index and --rev options are
1461 # provided and thus we need to iterate over all of the markers
1462 # provided and thus we need to iterate over all of the markers
1462 # to get the correct indices, but only display the ones that
1463 # to get the correct indices, but only display the ones that
1463 # are relevant to --rev value
1464 # are relevant to --rev value
1464 continue
1465 continue
1465 fm.startitem()
1466 fm.startitem()
1466 ind = i if opts.get('index') else None
1467 ind = i if opts.get('index') else None
1467 cmdutil.showmarker(fm, m, index=ind)
1468 cmdutil.showmarker(fm, m, index=ind)
1468 fm.end()
1469 fm.end()
1469
1470
1470 @command('debugpathcomplete',
1471 @command('debugpathcomplete',
1471 [('f', 'full', None, _('complete an entire path')),
1472 [('f', 'full', None, _('complete an entire path')),
1472 ('n', 'normal', None, _('show only normal files')),
1473 ('n', 'normal', None, _('show only normal files')),
1473 ('a', 'added', None, _('show only added files')),
1474 ('a', 'added', None, _('show only added files')),
1474 ('r', 'removed', None, _('show only removed files'))],
1475 ('r', 'removed', None, _('show only removed files'))],
1475 _('FILESPEC...'))
1476 _('FILESPEC...'))
1476 def debugpathcomplete(ui, repo, *specs, **opts):
1477 def debugpathcomplete(ui, repo, *specs, **opts):
1477 '''complete part or all of a tracked path
1478 '''complete part or all of a tracked path
1478
1479
1479 This command supports shells that offer path name completion. It
1480 This command supports shells that offer path name completion. It
1480 currently completes only files already known to the dirstate.
1481 currently completes only files already known to the dirstate.
1481
1482
1482 Completion extends only to the next path segment unless
1483 Completion extends only to the next path segment unless
1483 --full is specified, in which case entire paths are used.'''
1484 --full is specified, in which case entire paths are used.'''
1484
1485
1485 def complete(path, acceptable):
1486 def complete(path, acceptable):
1486 dirstate = repo.dirstate
1487 dirstate = repo.dirstate
1487 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1488 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1488 rootdir = repo.root + pycompat.ossep
1489 rootdir = repo.root + pycompat.ossep
1489 if spec != repo.root and not spec.startswith(rootdir):
1490 if spec != repo.root and not spec.startswith(rootdir):
1490 return [], []
1491 return [], []
1491 if os.path.isdir(spec):
1492 if os.path.isdir(spec):
1492 spec += '/'
1493 spec += '/'
1493 spec = spec[len(rootdir):]
1494 spec = spec[len(rootdir):]
1494 fixpaths = pycompat.ossep != '/'
1495 fixpaths = pycompat.ossep != '/'
1495 if fixpaths:
1496 if fixpaths:
1496 spec = spec.replace(pycompat.ossep, '/')
1497 spec = spec.replace(pycompat.ossep, '/')
1497 speclen = len(spec)
1498 speclen = len(spec)
1498 fullpaths = opts[r'full']
1499 fullpaths = opts[r'full']
1499 files, dirs = set(), set()
1500 files, dirs = set(), set()
1500 adddir, addfile = dirs.add, files.add
1501 adddir, addfile = dirs.add, files.add
1501 for f, st in dirstate.iteritems():
1502 for f, st in dirstate.iteritems():
1502 if f.startswith(spec) and st[0] in acceptable:
1503 if f.startswith(spec) and st[0] in acceptable:
1503 if fixpaths:
1504 if fixpaths:
1504 f = f.replace('/', pycompat.ossep)
1505 f = f.replace('/', pycompat.ossep)
1505 if fullpaths:
1506 if fullpaths:
1506 addfile(f)
1507 addfile(f)
1507 continue
1508 continue
1508 s = f.find(pycompat.ossep, speclen)
1509 s = f.find(pycompat.ossep, speclen)
1509 if s >= 0:
1510 if s >= 0:
1510 adddir(f[:s])
1511 adddir(f[:s])
1511 else:
1512 else:
1512 addfile(f)
1513 addfile(f)
1513 return files, dirs
1514 return files, dirs
1514
1515
1515 acceptable = ''
1516 acceptable = ''
1516 if opts[r'normal']:
1517 if opts[r'normal']:
1517 acceptable += 'nm'
1518 acceptable += 'nm'
1518 if opts[r'added']:
1519 if opts[r'added']:
1519 acceptable += 'a'
1520 acceptable += 'a'
1520 if opts[r'removed']:
1521 if opts[r'removed']:
1521 acceptable += 'r'
1522 acceptable += 'r'
1522 cwd = repo.getcwd()
1523 cwd = repo.getcwd()
1523 if not specs:
1524 if not specs:
1524 specs = ['.']
1525 specs = ['.']
1525
1526
1526 files, dirs = set(), set()
1527 files, dirs = set(), set()
1527 for spec in specs:
1528 for spec in specs:
1528 f, d = complete(spec, acceptable or 'nmar')
1529 f, d = complete(spec, acceptable or 'nmar')
1529 files.update(f)
1530 files.update(f)
1530 dirs.update(d)
1531 dirs.update(d)
1531 files.update(dirs)
1532 files.update(dirs)
1532 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1533 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1533 ui.write('\n')
1534 ui.write('\n')
1534
1535
1535 @command('debugpickmergetool',
1536 @command('debugpickmergetool',
1536 [('r', 'rev', '', _('check for files in this revision'), _('REV')),
1537 [('r', 'rev', '', _('check for files in this revision'), _('REV')),
1537 ('', 'changedelete', None, _('emulate merging change and delete')),
1538 ('', 'changedelete', None, _('emulate merging change and delete')),
1538 ] + cmdutil.walkopts + cmdutil.mergetoolopts,
1539 ] + cmdutil.walkopts + cmdutil.mergetoolopts,
1539 _('[PATTERN]...'),
1540 _('[PATTERN]...'),
1540 inferrepo=True)
1541 inferrepo=True)
1541 def debugpickmergetool(ui, repo, *pats, **opts):
1542 def debugpickmergetool(ui, repo, *pats, **opts):
1542 """examine which merge tool is chosen for specified file
1543 """examine which merge tool is chosen for specified file
1543
1544
1544 As described in :hg:`help merge-tools`, Mercurial examines
1545 As described in :hg:`help merge-tools`, Mercurial examines
1545 configurations below in this order to decide which merge tool is
1546 configurations below in this order to decide which merge tool is
1546 chosen for specified file.
1547 chosen for specified file.
1547
1548
1548 1. ``--tool`` option
1549 1. ``--tool`` option
1549 2. ``HGMERGE`` environment variable
1550 2. ``HGMERGE`` environment variable
1550 3. configurations in ``merge-patterns`` section
1551 3. configurations in ``merge-patterns`` section
1551 4. configuration of ``ui.merge``
1552 4. configuration of ``ui.merge``
1552 5. configurations in ``merge-tools`` section
1553 5. configurations in ``merge-tools`` section
1553 6. ``hgmerge`` tool (for historical reason only)
1554 6. ``hgmerge`` tool (for historical reason only)
1554 7. default tool for fallback (``:merge`` or ``:prompt``)
1555 7. default tool for fallback (``:merge`` or ``:prompt``)
1555
1556
1556 This command writes out examination result in the style below::
1557 This command writes out examination result in the style below::
1557
1558
1558 FILE = MERGETOOL
1559 FILE = MERGETOOL
1559
1560
1560 By default, all files known in the first parent context of the
1561 By default, all files known in the first parent context of the
1561 working directory are examined. Use file patterns and/or -I/-X
1562 working directory are examined. Use file patterns and/or -I/-X
1562 options to limit target files. -r/--rev is also useful to examine
1563 options to limit target files. -r/--rev is also useful to examine
1563 files in another context without actual updating to it.
1564 files in another context without actual updating to it.
1564
1565
1565 With --debug, this command shows warning messages while matching
1566 With --debug, this command shows warning messages while matching
1566 against ``merge-patterns`` and so on, too. It is recommended to
1567 against ``merge-patterns`` and so on, too. It is recommended to
1567 use this option with explicit file patterns and/or -I/-X options,
1568 use this option with explicit file patterns and/or -I/-X options,
1568 because this option increases amount of output per file according
1569 because this option increases amount of output per file according
1569 to configurations in hgrc.
1570 to configurations in hgrc.
1570
1571
1571 With -v/--verbose, this command shows configurations below at
1572 With -v/--verbose, this command shows configurations below at
1572 first (only if specified).
1573 first (only if specified).
1573
1574
1574 - ``--tool`` option
1575 - ``--tool`` option
1575 - ``HGMERGE`` environment variable
1576 - ``HGMERGE`` environment variable
1576 - configuration of ``ui.merge``
1577 - configuration of ``ui.merge``
1577
1578
1578 If merge tool is chosen before matching against
1579 If merge tool is chosen before matching against
1579 ``merge-patterns``, this command can't show any helpful
1580 ``merge-patterns``, this command can't show any helpful
1580 information, even with --debug. In such case, information above is
1581 information, even with --debug. In such case, information above is
1581 useful to know why a merge tool is chosen.
1582 useful to know why a merge tool is chosen.
1582 """
1583 """
1583 opts = pycompat.byteskwargs(opts)
1584 opts = pycompat.byteskwargs(opts)
1584 overrides = {}
1585 overrides = {}
1585 if opts['tool']:
1586 if opts['tool']:
1586 overrides[('ui', 'forcemerge')] = opts['tool']
1587 overrides[('ui', 'forcemerge')] = opts['tool']
1587 ui.note(('with --tool %r\n') % (opts['tool']))
1588 ui.note(('with --tool %r\n') % (opts['tool']))
1588
1589
1589 with ui.configoverride(overrides, 'debugmergepatterns'):
1590 with ui.configoverride(overrides, 'debugmergepatterns'):
1590 hgmerge = encoding.environ.get("HGMERGE")
1591 hgmerge = encoding.environ.get("HGMERGE")
1591 if hgmerge is not None:
1592 if hgmerge is not None:
1592 ui.note(('with HGMERGE=%r\n') % (hgmerge))
1593 ui.note(('with HGMERGE=%r\n') % (hgmerge))
1593 uimerge = ui.config("ui", "merge")
1594 uimerge = ui.config("ui", "merge")
1594 if uimerge:
1595 if uimerge:
1595 ui.note(('with ui.merge=%r\n') % (uimerge))
1596 ui.note(('with ui.merge=%r\n') % (uimerge))
1596
1597
1597 ctx = scmutil.revsingle(repo, opts.get('rev'))
1598 ctx = scmutil.revsingle(repo, opts.get('rev'))
1598 m = scmutil.match(ctx, pats, opts)
1599 m = scmutil.match(ctx, pats, opts)
1599 changedelete = opts['changedelete']
1600 changedelete = opts['changedelete']
1600 for path in ctx.walk(m):
1601 for path in ctx.walk(m):
1601 fctx = ctx[path]
1602 fctx = ctx[path]
1602 try:
1603 try:
1603 if not ui.debugflag:
1604 if not ui.debugflag:
1604 ui.pushbuffer(error=True)
1605 ui.pushbuffer(error=True)
1605 tool, toolpath = filemerge._picktool(repo, ui, path,
1606 tool, toolpath = filemerge._picktool(repo, ui, path,
1606 fctx.isbinary(),
1607 fctx.isbinary(),
1607 'l' in fctx.flags(),
1608 'l' in fctx.flags(),
1608 changedelete)
1609 changedelete)
1609 finally:
1610 finally:
1610 if not ui.debugflag:
1611 if not ui.debugflag:
1611 ui.popbuffer()
1612 ui.popbuffer()
1612 ui.write(('%s = %s\n') % (path, tool))
1613 ui.write(('%s = %s\n') % (path, tool))
1613
1614
1614 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1615 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1615 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1616 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1616 '''access the pushkey key/value protocol
1617 '''access the pushkey key/value protocol
1617
1618
1618 With two args, list the keys in the given namespace.
1619 With two args, list the keys in the given namespace.
1619
1620
1620 With five args, set a key to new if it currently is set to old.
1621 With five args, set a key to new if it currently is set to old.
1621 Reports success or failure.
1622 Reports success or failure.
1622 '''
1623 '''
1623
1624
1624 target = hg.peer(ui, {}, repopath)
1625 target = hg.peer(ui, {}, repopath)
1625 if keyinfo:
1626 if keyinfo:
1626 key, old, new = keyinfo
1627 key, old, new = keyinfo
1627 r = target.pushkey(namespace, key, old, new)
1628 r = target.pushkey(namespace, key, old, new)
1628 ui.status(str(r) + '\n')
1629 ui.status(str(r) + '\n')
1629 return not r
1630 return not r
1630 else:
1631 else:
1631 for k, v in sorted(target.listkeys(namespace).iteritems()):
1632 for k, v in sorted(target.listkeys(namespace).iteritems()):
1632 ui.write("%s\t%s\n" % (util.escapestr(k),
1633 ui.write("%s\t%s\n" % (util.escapestr(k),
1633 util.escapestr(v)))
1634 util.escapestr(v)))
1634
1635
1635 @command('debugpvec', [], _('A B'))
1636 @command('debugpvec', [], _('A B'))
1636 def debugpvec(ui, repo, a, b=None):
1637 def debugpvec(ui, repo, a, b=None):
1637 ca = scmutil.revsingle(repo, a)
1638 ca = scmutil.revsingle(repo, a)
1638 cb = scmutil.revsingle(repo, b)
1639 cb = scmutil.revsingle(repo, b)
1639 pa = pvec.ctxpvec(ca)
1640 pa = pvec.ctxpvec(ca)
1640 pb = pvec.ctxpvec(cb)
1641 pb = pvec.ctxpvec(cb)
1641 if pa == pb:
1642 if pa == pb:
1642 rel = "="
1643 rel = "="
1643 elif pa > pb:
1644 elif pa > pb:
1644 rel = ">"
1645 rel = ">"
1645 elif pa < pb:
1646 elif pa < pb:
1646 rel = "<"
1647 rel = "<"
1647 elif pa | pb:
1648 elif pa | pb:
1648 rel = "|"
1649 rel = "|"
1649 ui.write(_("a: %s\n") % pa)
1650 ui.write(_("a: %s\n") % pa)
1650 ui.write(_("b: %s\n") % pb)
1651 ui.write(_("b: %s\n") % pb)
1651 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1652 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1652 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1653 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1653 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1654 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1654 pa.distance(pb), rel))
1655 pa.distance(pb), rel))
1655
1656
1656 @command('debugrebuilddirstate|debugrebuildstate',
1657 @command('debugrebuilddirstate|debugrebuildstate',
1657 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1658 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1658 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1659 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1659 'the working copy parent')),
1660 'the working copy parent')),
1660 ],
1661 ],
1661 _('[-r REV]'))
1662 _('[-r REV]'))
1662 def debugrebuilddirstate(ui, repo, rev, **opts):
1663 def debugrebuilddirstate(ui, repo, rev, **opts):
1663 """rebuild the dirstate as it would look like for the given revision
1664 """rebuild the dirstate as it would look like for the given revision
1664
1665
1665 If no revision is specified the first current parent will be used.
1666 If no revision is specified the first current parent will be used.
1666
1667
1667 The dirstate will be set to the files of the given revision.
1668 The dirstate will be set to the files of the given revision.
1668 The actual working directory content or existing dirstate
1669 The actual working directory content or existing dirstate
1669 information such as adds or removes is not considered.
1670 information such as adds or removes is not considered.
1670
1671
1671 ``minimal`` will only rebuild the dirstate status for files that claim to be
1672 ``minimal`` will only rebuild the dirstate status for files that claim to be
1672 tracked but are not in the parent manifest, or that exist in the parent
1673 tracked but are not in the parent manifest, or that exist in the parent
1673 manifest but are not in the dirstate. It will not change adds, removes, or
1674 manifest but are not in the dirstate. It will not change adds, removes, or
1674 modified files that are in the working copy parent.
1675 modified files that are in the working copy parent.
1675
1676
1676 One use of this command is to make the next :hg:`status` invocation
1677 One use of this command is to make the next :hg:`status` invocation
1677 check the actual file content.
1678 check the actual file content.
1678 """
1679 """
1679 ctx = scmutil.revsingle(repo, rev)
1680 ctx = scmutil.revsingle(repo, rev)
1680 with repo.wlock():
1681 with repo.wlock():
1681 dirstate = repo.dirstate
1682 dirstate = repo.dirstate
1682 changedfiles = None
1683 changedfiles = None
1683 # See command doc for what minimal does.
1684 # See command doc for what minimal does.
1684 if opts.get(r'minimal'):
1685 if opts.get(r'minimal'):
1685 manifestfiles = set(ctx.manifest().keys())
1686 manifestfiles = set(ctx.manifest().keys())
1686 dirstatefiles = set(dirstate)
1687 dirstatefiles = set(dirstate)
1687 manifestonly = manifestfiles - dirstatefiles
1688 manifestonly = manifestfiles - dirstatefiles
1688 dsonly = dirstatefiles - manifestfiles
1689 dsonly = dirstatefiles - manifestfiles
1689 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1690 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1690 changedfiles = manifestonly | dsnotadded
1691 changedfiles = manifestonly | dsnotadded
1691
1692
1692 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1693 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1693
1694
1694 @command('debugrebuildfncache', [], '')
1695 @command('debugrebuildfncache', [], '')
1695 def debugrebuildfncache(ui, repo):
1696 def debugrebuildfncache(ui, repo):
1696 """rebuild the fncache file"""
1697 """rebuild the fncache file"""
1697 repair.rebuildfncache(ui, repo)
1698 repair.rebuildfncache(ui, repo)
1698
1699
1699 @command('debugrename',
1700 @command('debugrename',
1700 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1701 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1701 _('[-r REV] FILE'))
1702 _('[-r REV] FILE'))
1702 def debugrename(ui, repo, file1, *pats, **opts):
1703 def debugrename(ui, repo, file1, *pats, **opts):
1703 """dump rename information"""
1704 """dump rename information"""
1704
1705
1705 opts = pycompat.byteskwargs(opts)
1706 opts = pycompat.byteskwargs(opts)
1706 ctx = scmutil.revsingle(repo, opts.get('rev'))
1707 ctx = scmutil.revsingle(repo, opts.get('rev'))
1707 m = scmutil.match(ctx, (file1,) + pats, opts)
1708 m = scmutil.match(ctx, (file1,) + pats, opts)
1708 for abs in ctx.walk(m):
1709 for abs in ctx.walk(m):
1709 fctx = ctx[abs]
1710 fctx = ctx[abs]
1710 o = fctx.filelog().renamed(fctx.filenode())
1711 o = fctx.filelog().renamed(fctx.filenode())
1711 rel = m.rel(abs)
1712 rel = m.rel(abs)
1712 if o:
1713 if o:
1713 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1714 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1714 else:
1715 else:
1715 ui.write(_("%s not renamed\n") % rel)
1716 ui.write(_("%s not renamed\n") % rel)
1716
1717
1717 @command('debugrevlog', cmdutil.debugrevlogopts +
1718 @command('debugrevlog', cmdutil.debugrevlogopts +
1718 [('d', 'dump', False, _('dump index data'))],
1719 [('d', 'dump', False, _('dump index data'))],
1719 _('-c|-m|FILE'),
1720 _('-c|-m|FILE'),
1720 optionalrepo=True)
1721 optionalrepo=True)
1721 def debugrevlog(ui, repo, file_=None, **opts):
1722 def debugrevlog(ui, repo, file_=None, **opts):
1722 """show data and statistics about a revlog"""
1723 """show data and statistics about a revlog"""
1723 opts = pycompat.byteskwargs(opts)
1724 opts = pycompat.byteskwargs(opts)
1724 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1725 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1725
1726
1726 if opts.get("dump"):
1727 if opts.get("dump"):
1727 numrevs = len(r)
1728 numrevs = len(r)
1728 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1729 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1729 " rawsize totalsize compression heads chainlen\n"))
1730 " rawsize totalsize compression heads chainlen\n"))
1730 ts = 0
1731 ts = 0
1731 heads = set()
1732 heads = set()
1732
1733
1733 for rev in xrange(numrevs):
1734 for rev in xrange(numrevs):
1734 dbase = r.deltaparent(rev)
1735 dbase = r.deltaparent(rev)
1735 if dbase == -1:
1736 if dbase == -1:
1736 dbase = rev
1737 dbase = rev
1737 cbase = r.chainbase(rev)
1738 cbase = r.chainbase(rev)
1738 clen = r.chainlen(rev)
1739 clen = r.chainlen(rev)
1739 p1, p2 = r.parentrevs(rev)
1740 p1, p2 = r.parentrevs(rev)
1740 rs = r.rawsize(rev)
1741 rs = r.rawsize(rev)
1741 ts = ts + rs
1742 ts = ts + rs
1742 heads -= set(r.parentrevs(rev))
1743 heads -= set(r.parentrevs(rev))
1743 heads.add(rev)
1744 heads.add(rev)
1744 try:
1745 try:
1745 compression = ts / r.end(rev)
1746 compression = ts / r.end(rev)
1746 except ZeroDivisionError:
1747 except ZeroDivisionError:
1747 compression = 0
1748 compression = 0
1748 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1749 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1749 "%11d %5d %8d\n" %
1750 "%11d %5d %8d\n" %
1750 (rev, p1, p2, r.start(rev), r.end(rev),
1751 (rev, p1, p2, r.start(rev), r.end(rev),
1751 r.start(dbase), r.start(cbase),
1752 r.start(dbase), r.start(cbase),
1752 r.start(p1), r.start(p2),
1753 r.start(p1), r.start(p2),
1753 rs, ts, compression, len(heads), clen))
1754 rs, ts, compression, len(heads), clen))
1754 return 0
1755 return 0
1755
1756
1756 v = r.version
1757 v = r.version
1757 format = v & 0xFFFF
1758 format = v & 0xFFFF
1758 flags = []
1759 flags = []
1759 gdelta = False
1760 gdelta = False
1760 if v & revlog.FLAG_INLINE_DATA:
1761 if v & revlog.FLAG_INLINE_DATA:
1761 flags.append('inline')
1762 flags.append('inline')
1762 if v & revlog.FLAG_GENERALDELTA:
1763 if v & revlog.FLAG_GENERALDELTA:
1763 gdelta = True
1764 gdelta = True
1764 flags.append('generaldelta')
1765 flags.append('generaldelta')
1765 if not flags:
1766 if not flags:
1766 flags = ['(none)']
1767 flags = ['(none)']
1767
1768
1768 nummerges = 0
1769 nummerges = 0
1769 numfull = 0
1770 numfull = 0
1770 numprev = 0
1771 numprev = 0
1771 nump1 = 0
1772 nump1 = 0
1772 nump2 = 0
1773 nump2 = 0
1773 numother = 0
1774 numother = 0
1774 nump1prev = 0
1775 nump1prev = 0
1775 nump2prev = 0
1776 nump2prev = 0
1776 chainlengths = []
1777 chainlengths = []
1777 chainbases = []
1778 chainbases = []
1778 chainspans = []
1779 chainspans = []
1779
1780
1780 datasize = [None, 0, 0]
1781 datasize = [None, 0, 0]
1781 fullsize = [None, 0, 0]
1782 fullsize = [None, 0, 0]
1782 deltasize = [None, 0, 0]
1783 deltasize = [None, 0, 0]
1783 chunktypecounts = {}
1784 chunktypecounts = {}
1784 chunktypesizes = {}
1785 chunktypesizes = {}
1785
1786
1786 def addsize(size, l):
1787 def addsize(size, l):
1787 if l[0] is None or size < l[0]:
1788 if l[0] is None or size < l[0]:
1788 l[0] = size
1789 l[0] = size
1789 if size > l[1]:
1790 if size > l[1]:
1790 l[1] = size
1791 l[1] = size
1791 l[2] += size
1792 l[2] += size
1792
1793
1793 numrevs = len(r)
1794 numrevs = len(r)
1794 for rev in xrange(numrevs):
1795 for rev in xrange(numrevs):
1795 p1, p2 = r.parentrevs(rev)
1796 p1, p2 = r.parentrevs(rev)
1796 delta = r.deltaparent(rev)
1797 delta = r.deltaparent(rev)
1797 if format > 0:
1798 if format > 0:
1798 addsize(r.rawsize(rev), datasize)
1799 addsize(r.rawsize(rev), datasize)
1799 if p2 != nullrev:
1800 if p2 != nullrev:
1800 nummerges += 1
1801 nummerges += 1
1801 size = r.length(rev)
1802 size = r.length(rev)
1802 if delta == nullrev:
1803 if delta == nullrev:
1803 chainlengths.append(0)
1804 chainlengths.append(0)
1804 chainbases.append(r.start(rev))
1805 chainbases.append(r.start(rev))
1805 chainspans.append(size)
1806 chainspans.append(size)
1806 numfull += 1
1807 numfull += 1
1807 addsize(size, fullsize)
1808 addsize(size, fullsize)
1808 else:
1809 else:
1809 chainlengths.append(chainlengths[delta] + 1)
1810 chainlengths.append(chainlengths[delta] + 1)
1810 baseaddr = chainbases[delta]
1811 baseaddr = chainbases[delta]
1811 revaddr = r.start(rev)
1812 revaddr = r.start(rev)
1812 chainbases.append(baseaddr)
1813 chainbases.append(baseaddr)
1813 chainspans.append((revaddr - baseaddr) + size)
1814 chainspans.append((revaddr - baseaddr) + size)
1814 addsize(size, deltasize)
1815 addsize(size, deltasize)
1815 if delta == rev - 1:
1816 if delta == rev - 1:
1816 numprev += 1
1817 numprev += 1
1817 if delta == p1:
1818 if delta == p1:
1818 nump1prev += 1
1819 nump1prev += 1
1819 elif delta == p2:
1820 elif delta == p2:
1820 nump2prev += 1
1821 nump2prev += 1
1821 elif delta == p1:
1822 elif delta == p1:
1822 nump1 += 1
1823 nump1 += 1
1823 elif delta == p2:
1824 elif delta == p2:
1824 nump2 += 1
1825 nump2 += 1
1825 elif delta != nullrev:
1826 elif delta != nullrev:
1826 numother += 1
1827 numother += 1
1827
1828
1828 # Obtain data on the raw chunks in the revlog.
1829 # Obtain data on the raw chunks in the revlog.
1829 segment = r._getsegmentforrevs(rev, rev)[1]
1830 segment = r._getsegmentforrevs(rev, rev)[1]
1830 if segment:
1831 if segment:
1831 chunktype = bytes(segment[0:1])
1832 chunktype = bytes(segment[0:1])
1832 else:
1833 else:
1833 chunktype = 'empty'
1834 chunktype = 'empty'
1834
1835
1835 if chunktype not in chunktypecounts:
1836 if chunktype not in chunktypecounts:
1836 chunktypecounts[chunktype] = 0
1837 chunktypecounts[chunktype] = 0
1837 chunktypesizes[chunktype] = 0
1838 chunktypesizes[chunktype] = 0
1838
1839
1839 chunktypecounts[chunktype] += 1
1840 chunktypecounts[chunktype] += 1
1840 chunktypesizes[chunktype] += size
1841 chunktypesizes[chunktype] += size
1841
1842
1842 # Adjust size min value for empty cases
1843 # Adjust size min value for empty cases
1843 for size in (datasize, fullsize, deltasize):
1844 for size in (datasize, fullsize, deltasize):
1844 if size[0] is None:
1845 if size[0] is None:
1845 size[0] = 0
1846 size[0] = 0
1846
1847
1847 numdeltas = numrevs - numfull
1848 numdeltas = numrevs - numfull
1848 numoprev = numprev - nump1prev - nump2prev
1849 numoprev = numprev - nump1prev - nump2prev
1849 totalrawsize = datasize[2]
1850 totalrawsize = datasize[2]
1850 datasize[2] /= numrevs
1851 datasize[2] /= numrevs
1851 fulltotal = fullsize[2]
1852 fulltotal = fullsize[2]
1852 fullsize[2] /= numfull
1853 fullsize[2] /= numfull
1853 deltatotal = deltasize[2]
1854 deltatotal = deltasize[2]
1854 if numrevs - numfull > 0:
1855 if numrevs - numfull > 0:
1855 deltasize[2] /= numrevs - numfull
1856 deltasize[2] /= numrevs - numfull
1856 totalsize = fulltotal + deltatotal
1857 totalsize = fulltotal + deltatotal
1857 avgchainlen = sum(chainlengths) / numrevs
1858 avgchainlen = sum(chainlengths) / numrevs
1858 maxchainlen = max(chainlengths)
1859 maxchainlen = max(chainlengths)
1859 maxchainspan = max(chainspans)
1860 maxchainspan = max(chainspans)
1860 compratio = 1
1861 compratio = 1
1861 if totalsize:
1862 if totalsize:
1862 compratio = totalrawsize / totalsize
1863 compratio = totalrawsize / totalsize
1863
1864
1864 basedfmtstr = '%%%dd\n'
1865 basedfmtstr = '%%%dd\n'
1865 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1866 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
1866
1867
1867 def dfmtstr(max):
1868 def dfmtstr(max):
1868 return basedfmtstr % len(str(max))
1869 return basedfmtstr % len(str(max))
1869 def pcfmtstr(max, padding=0):
1870 def pcfmtstr(max, padding=0):
1870 return basepcfmtstr % (len(str(max)), ' ' * padding)
1871 return basepcfmtstr % (len(str(max)), ' ' * padding)
1871
1872
1872 def pcfmt(value, total):
1873 def pcfmt(value, total):
1873 if total:
1874 if total:
1874 return (value, 100 * float(value) / total)
1875 return (value, 100 * float(value) / total)
1875 else:
1876 else:
1876 return value, 100.0
1877 return value, 100.0
1877
1878
1878 ui.write(('format : %d\n') % format)
1879 ui.write(('format : %d\n') % format)
1879 ui.write(('flags : %s\n') % ', '.join(flags))
1880 ui.write(('flags : %s\n') % ', '.join(flags))
1880
1881
1881 ui.write('\n')
1882 ui.write('\n')
1882 fmt = pcfmtstr(totalsize)
1883 fmt = pcfmtstr(totalsize)
1883 fmt2 = dfmtstr(totalsize)
1884 fmt2 = dfmtstr(totalsize)
1884 ui.write(('revisions : ') + fmt2 % numrevs)
1885 ui.write(('revisions : ') + fmt2 % numrevs)
1885 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
1886 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
1886 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
1887 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
1887 ui.write(('revisions : ') + fmt2 % numrevs)
1888 ui.write(('revisions : ') + fmt2 % numrevs)
1888 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
1889 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
1889 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
1890 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
1890 ui.write(('revision size : ') + fmt2 % totalsize)
1891 ui.write(('revision size : ') + fmt2 % totalsize)
1891 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
1892 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
1892 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
1893 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
1893
1894
1894 def fmtchunktype(chunktype):
1895 def fmtchunktype(chunktype):
1895 if chunktype == 'empty':
1896 if chunktype == 'empty':
1896 return ' %s : ' % chunktype
1897 return ' %s : ' % chunktype
1897 elif chunktype in pycompat.bytestr(string.ascii_letters):
1898 elif chunktype in pycompat.bytestr(string.ascii_letters):
1898 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
1899 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
1899 else:
1900 else:
1900 return ' 0x%s : ' % hex(chunktype)
1901 return ' 0x%s : ' % hex(chunktype)
1901
1902
1902 ui.write('\n')
1903 ui.write('\n')
1903 ui.write(('chunks : ') + fmt2 % numrevs)
1904 ui.write(('chunks : ') + fmt2 % numrevs)
1904 for chunktype in sorted(chunktypecounts):
1905 for chunktype in sorted(chunktypecounts):
1905 ui.write(fmtchunktype(chunktype))
1906 ui.write(fmtchunktype(chunktype))
1906 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
1907 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
1907 ui.write(('chunks size : ') + fmt2 % totalsize)
1908 ui.write(('chunks size : ') + fmt2 % totalsize)
1908 for chunktype in sorted(chunktypecounts):
1909 for chunktype in sorted(chunktypecounts):
1909 ui.write(fmtchunktype(chunktype))
1910 ui.write(fmtchunktype(chunktype))
1910 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
1911 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
1911
1912
1912 ui.write('\n')
1913 ui.write('\n')
1913 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
1914 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
1914 ui.write(('avg chain length : ') + fmt % avgchainlen)
1915 ui.write(('avg chain length : ') + fmt % avgchainlen)
1915 ui.write(('max chain length : ') + fmt % maxchainlen)
1916 ui.write(('max chain length : ') + fmt % maxchainlen)
1916 ui.write(('max chain reach : ') + fmt % maxchainspan)
1917 ui.write(('max chain reach : ') + fmt % maxchainspan)
1917 ui.write(('compression ratio : ') + fmt % compratio)
1918 ui.write(('compression ratio : ') + fmt % compratio)
1918
1919
1919 if format > 0:
1920 if format > 0:
1920 ui.write('\n')
1921 ui.write('\n')
1921 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
1922 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
1922 % tuple(datasize))
1923 % tuple(datasize))
1923 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
1924 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
1924 % tuple(fullsize))
1925 % tuple(fullsize))
1925 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
1926 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
1926 % tuple(deltasize))
1927 % tuple(deltasize))
1927
1928
1928 if numdeltas > 0:
1929 if numdeltas > 0:
1929 ui.write('\n')
1930 ui.write('\n')
1930 fmt = pcfmtstr(numdeltas)
1931 fmt = pcfmtstr(numdeltas)
1931 fmt2 = pcfmtstr(numdeltas, 4)
1932 fmt2 = pcfmtstr(numdeltas, 4)
1932 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
1933 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
1933 if numprev > 0:
1934 if numprev > 0:
1934 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
1935 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
1935 numprev))
1936 numprev))
1936 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
1937 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
1937 numprev))
1938 numprev))
1938 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
1939 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
1939 numprev))
1940 numprev))
1940 if gdelta:
1941 if gdelta:
1941 ui.write(('deltas against p1 : ')
1942 ui.write(('deltas against p1 : ')
1942 + fmt % pcfmt(nump1, numdeltas))
1943 + fmt % pcfmt(nump1, numdeltas))
1943 ui.write(('deltas against p2 : ')
1944 ui.write(('deltas against p2 : ')
1944 + fmt % pcfmt(nump2, numdeltas))
1945 + fmt % pcfmt(nump2, numdeltas))
1945 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
1946 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
1946 numdeltas))
1947 numdeltas))
1947
1948
1948 @command('debugrevspec',
1949 @command('debugrevspec',
1949 [('', 'optimize', None,
1950 [('', 'optimize', None,
1950 _('print parsed tree after optimizing (DEPRECATED)')),
1951 _('print parsed tree after optimizing (DEPRECATED)')),
1951 ('', 'show-revs', True, _('print list of result revisions (default)')),
1952 ('', 'show-revs', True, _('print list of result revisions (default)')),
1952 ('s', 'show-set', None, _('print internal representation of result set')),
1953 ('s', 'show-set', None, _('print internal representation of result set')),
1953 ('p', 'show-stage', [],
1954 ('p', 'show-stage', [],
1954 _('print parsed tree at the given stage'), _('NAME')),
1955 _('print parsed tree at the given stage'), _('NAME')),
1955 ('', 'no-optimized', False, _('evaluate tree without optimization')),
1956 ('', 'no-optimized', False, _('evaluate tree without optimization')),
1956 ('', 'verify-optimized', False, _('verify optimized result')),
1957 ('', 'verify-optimized', False, _('verify optimized result')),
1957 ],
1958 ],
1958 ('REVSPEC'))
1959 ('REVSPEC'))
1959 def debugrevspec(ui, repo, expr, **opts):
1960 def debugrevspec(ui, repo, expr, **opts):
1960 """parse and apply a revision specification
1961 """parse and apply a revision specification
1961
1962
1962 Use -p/--show-stage option to print the parsed tree at the given stages.
1963 Use -p/--show-stage option to print the parsed tree at the given stages.
1963 Use -p all to print tree at every stage.
1964 Use -p all to print tree at every stage.
1964
1965
1965 Use --no-show-revs option with -s or -p to print only the set
1966 Use --no-show-revs option with -s or -p to print only the set
1966 representation or the parsed tree respectively.
1967 representation or the parsed tree respectively.
1967
1968
1968 Use --verify-optimized to compare the optimized result with the unoptimized
1969 Use --verify-optimized to compare the optimized result with the unoptimized
1969 one. Returns 1 if the optimized result differs.
1970 one. Returns 1 if the optimized result differs.
1970 """
1971 """
1971 opts = pycompat.byteskwargs(opts)
1972 opts = pycompat.byteskwargs(opts)
1972 aliases = ui.configitems('revsetalias')
1973 aliases = ui.configitems('revsetalias')
1973 stages = [
1974 stages = [
1974 ('parsed', lambda tree: tree),
1975 ('parsed', lambda tree: tree),
1975 ('expanded', lambda tree: revsetlang.expandaliases(tree, aliases,
1976 ('expanded', lambda tree: revsetlang.expandaliases(tree, aliases,
1976 ui.warn)),
1977 ui.warn)),
1977 ('concatenated', revsetlang.foldconcat),
1978 ('concatenated', revsetlang.foldconcat),
1978 ('analyzed', revsetlang.analyze),
1979 ('analyzed', revsetlang.analyze),
1979 ('optimized', revsetlang.optimize),
1980 ('optimized', revsetlang.optimize),
1980 ]
1981 ]
1981 if opts['no_optimized']:
1982 if opts['no_optimized']:
1982 stages = stages[:-1]
1983 stages = stages[:-1]
1983 if opts['verify_optimized'] and opts['no_optimized']:
1984 if opts['verify_optimized'] and opts['no_optimized']:
1984 raise error.Abort(_('cannot use --verify-optimized with '
1985 raise error.Abort(_('cannot use --verify-optimized with '
1985 '--no-optimized'))
1986 '--no-optimized'))
1986 stagenames = set(n for n, f in stages)
1987 stagenames = set(n for n, f in stages)
1987
1988
1988 showalways = set()
1989 showalways = set()
1989 showchanged = set()
1990 showchanged = set()
1990 if ui.verbose and not opts['show_stage']:
1991 if ui.verbose and not opts['show_stage']:
1991 # show parsed tree by --verbose (deprecated)
1992 # show parsed tree by --verbose (deprecated)
1992 showalways.add('parsed')
1993 showalways.add('parsed')
1993 showchanged.update(['expanded', 'concatenated'])
1994 showchanged.update(['expanded', 'concatenated'])
1994 if opts['optimize']:
1995 if opts['optimize']:
1995 showalways.add('optimized')
1996 showalways.add('optimized')
1996 if opts['show_stage'] and opts['optimize']:
1997 if opts['show_stage'] and opts['optimize']:
1997 raise error.Abort(_('cannot use --optimize with --show-stage'))
1998 raise error.Abort(_('cannot use --optimize with --show-stage'))
1998 if opts['show_stage'] == ['all']:
1999 if opts['show_stage'] == ['all']:
1999 showalways.update(stagenames)
2000 showalways.update(stagenames)
2000 else:
2001 else:
2001 for n in opts['show_stage']:
2002 for n in opts['show_stage']:
2002 if n not in stagenames:
2003 if n not in stagenames:
2003 raise error.Abort(_('invalid stage name: %s') % n)
2004 raise error.Abort(_('invalid stage name: %s') % n)
2004 showalways.update(opts['show_stage'])
2005 showalways.update(opts['show_stage'])
2005
2006
2006 treebystage = {}
2007 treebystage = {}
2007 printedtree = None
2008 printedtree = None
2008 tree = revsetlang.parse(expr, lookup=repo.__contains__)
2009 tree = revsetlang.parse(expr, lookup=repo.__contains__)
2009 for n, f in stages:
2010 for n, f in stages:
2010 treebystage[n] = tree = f(tree)
2011 treebystage[n] = tree = f(tree)
2011 if n in showalways or (n in showchanged and tree != printedtree):
2012 if n in showalways or (n in showchanged and tree != printedtree):
2012 if opts['show_stage'] or n != 'parsed':
2013 if opts['show_stage'] or n != 'parsed':
2013 ui.write(("* %s:\n") % n)
2014 ui.write(("* %s:\n") % n)
2014 ui.write(revsetlang.prettyformat(tree), "\n")
2015 ui.write(revsetlang.prettyformat(tree), "\n")
2015 printedtree = tree
2016 printedtree = tree
2016
2017
2017 if opts['verify_optimized']:
2018 if opts['verify_optimized']:
2018 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2019 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2019 brevs = revset.makematcher(treebystage['optimized'])(repo)
2020 brevs = revset.makematcher(treebystage['optimized'])(repo)
2020 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2021 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2021 ui.write(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
2022 ui.write(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
2022 ui.write(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
2023 ui.write(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
2023 arevs = list(arevs)
2024 arevs = list(arevs)
2024 brevs = list(brevs)
2025 brevs = list(brevs)
2025 if arevs == brevs:
2026 if arevs == brevs:
2026 return 0
2027 return 0
2027 ui.write(('--- analyzed\n'), label='diff.file_a')
2028 ui.write(('--- analyzed\n'), label='diff.file_a')
2028 ui.write(('+++ optimized\n'), label='diff.file_b')
2029 ui.write(('+++ optimized\n'), label='diff.file_b')
2029 sm = difflib.SequenceMatcher(None, arevs, brevs)
2030 sm = difflib.SequenceMatcher(None, arevs, brevs)
2030 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2031 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2031 if tag in ('delete', 'replace'):
2032 if tag in ('delete', 'replace'):
2032 for c in arevs[alo:ahi]:
2033 for c in arevs[alo:ahi]:
2033 ui.write('-%s\n' % c, label='diff.deleted')
2034 ui.write('-%s\n' % c, label='diff.deleted')
2034 if tag in ('insert', 'replace'):
2035 if tag in ('insert', 'replace'):
2035 for c in brevs[blo:bhi]:
2036 for c in brevs[blo:bhi]:
2036 ui.write('+%s\n' % c, label='diff.inserted')
2037 ui.write('+%s\n' % c, label='diff.inserted')
2037 if tag == 'equal':
2038 if tag == 'equal':
2038 for c in arevs[alo:ahi]:
2039 for c in arevs[alo:ahi]:
2039 ui.write(' %s\n' % c)
2040 ui.write(' %s\n' % c)
2040 return 1
2041 return 1
2041
2042
2042 func = revset.makematcher(tree)
2043 func = revset.makematcher(tree)
2043 revs = func(repo)
2044 revs = func(repo)
2044 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2045 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2045 ui.write(("* set:\n"), smartset.prettyformat(revs), "\n")
2046 ui.write(("* set:\n"), smartset.prettyformat(revs), "\n")
2046 if not opts['show_revs']:
2047 if not opts['show_revs']:
2047 return
2048 return
2048 for c in revs:
2049 for c in revs:
2049 ui.write("%s\n" % c)
2050 ui.write("%s\n" % c)
2050
2051
2051 @command('debugsetparents', [], _('REV1 [REV2]'))
2052 @command('debugsetparents', [], _('REV1 [REV2]'))
2052 def debugsetparents(ui, repo, rev1, rev2=None):
2053 def debugsetparents(ui, repo, rev1, rev2=None):
2053 """manually set the parents of the current working directory
2054 """manually set the parents of the current working directory
2054
2055
2055 This is useful for writing repository conversion tools, but should
2056 This is useful for writing repository conversion tools, but should
2056 be used with care. For example, neither the working directory nor the
2057 be used with care. For example, neither the working directory nor the
2057 dirstate is updated, so file status may be incorrect after running this
2058 dirstate is updated, so file status may be incorrect after running this
2058 command.
2059 command.
2059
2060
2060 Returns 0 on success.
2061 Returns 0 on success.
2061 """
2062 """
2062
2063
2063 r1 = scmutil.revsingle(repo, rev1).node()
2064 r1 = scmutil.revsingle(repo, rev1).node()
2064 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2065 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2065
2066
2066 with repo.wlock():
2067 with repo.wlock():
2067 repo.setparents(r1, r2)
2068 repo.setparents(r1, r2)
2068
2069
2069 @command('debugssl', [], '[SOURCE]', optionalrepo=True)
2070 @command('debugssl', [], '[SOURCE]', optionalrepo=True)
2070 def debugssl(ui, repo, source=None, **opts):
2071 def debugssl(ui, repo, source=None, **opts):
2071 '''test a secure connection to a server
2072 '''test a secure connection to a server
2072
2073
2073 This builds the certificate chain for the server on Windows, installing the
2074 This builds the certificate chain for the server on Windows, installing the
2074 missing intermediates and trusted root via Windows Update if necessary. It
2075 missing intermediates and trusted root via Windows Update if necessary. It
2075 does nothing on other platforms.
2076 does nothing on other platforms.
2076
2077
2077 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
2078 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
2078 that server is used. See :hg:`help urls` for more information.
2079 that server is used. See :hg:`help urls` for more information.
2079
2080
2080 If the update succeeds, retry the original operation. Otherwise, the cause
2081 If the update succeeds, retry the original operation. Otherwise, the cause
2081 of the SSL error is likely another issue.
2082 of the SSL error is likely another issue.
2082 '''
2083 '''
2083 if pycompat.osname != 'nt':
2084 if pycompat.osname != 'nt':
2084 raise error.Abort(_('certificate chain building is only possible on '
2085 raise error.Abort(_('certificate chain building is only possible on '
2085 'Windows'))
2086 'Windows'))
2086
2087
2087 if not source:
2088 if not source:
2088 if not repo:
2089 if not repo:
2089 raise error.Abort(_("there is no Mercurial repository here, and no "
2090 raise error.Abort(_("there is no Mercurial repository here, and no "
2090 "server specified"))
2091 "server specified"))
2091 source = "default"
2092 source = "default"
2092
2093
2093 source, branches = hg.parseurl(ui.expandpath(source))
2094 source, branches = hg.parseurl(ui.expandpath(source))
2094 url = util.url(source)
2095 url = util.url(source)
2095 addr = None
2096 addr = None
2096
2097
2097 if url.scheme == 'https':
2098 if url.scheme == 'https':
2098 addr = (url.host, url.port or 443)
2099 addr = (url.host, url.port or 443)
2099 elif url.scheme == 'ssh':
2100 elif url.scheme == 'ssh':
2100 addr = (url.host, url.port or 22)
2101 addr = (url.host, url.port or 22)
2101 else:
2102 else:
2102 raise error.Abort(_("only https and ssh connections are supported"))
2103 raise error.Abort(_("only https and ssh connections are supported"))
2103
2104
2104 from . import win32
2105 from . import win32
2105
2106
2106 s = ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_TLS,
2107 s = ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_TLS,
2107 cert_reqs=ssl.CERT_NONE, ca_certs=None)
2108 cert_reqs=ssl.CERT_NONE, ca_certs=None)
2108
2109
2109 try:
2110 try:
2110 s.connect(addr)
2111 s.connect(addr)
2111 cert = s.getpeercert(True)
2112 cert = s.getpeercert(True)
2112
2113
2113 ui.status(_('checking the certificate chain for %s\n') % url.host)
2114 ui.status(_('checking the certificate chain for %s\n') % url.host)
2114
2115
2115 complete = win32.checkcertificatechain(cert, build=False)
2116 complete = win32.checkcertificatechain(cert, build=False)
2116
2117
2117 if not complete:
2118 if not complete:
2118 ui.status(_('certificate chain is incomplete, updating... '))
2119 ui.status(_('certificate chain is incomplete, updating... '))
2119
2120
2120 if not win32.checkcertificatechain(cert):
2121 if not win32.checkcertificatechain(cert):
2121 ui.status(_('failed.\n'))
2122 ui.status(_('failed.\n'))
2122 else:
2123 else:
2123 ui.status(_('done.\n'))
2124 ui.status(_('done.\n'))
2124 else:
2125 else:
2125 ui.status(_('full certificate chain is available\n'))
2126 ui.status(_('full certificate chain is available\n'))
2126 finally:
2127 finally:
2127 s.close()
2128 s.close()
2128
2129
2129 @command('debugsub',
2130 @command('debugsub',
2130 [('r', 'rev', '',
2131 [('r', 'rev', '',
2131 _('revision to check'), _('REV'))],
2132 _('revision to check'), _('REV'))],
2132 _('[-r REV] [REV]'))
2133 _('[-r REV] [REV]'))
2133 def debugsub(ui, repo, rev=None):
2134 def debugsub(ui, repo, rev=None):
2134 ctx = scmutil.revsingle(repo, rev, None)
2135 ctx = scmutil.revsingle(repo, rev, None)
2135 for k, v in sorted(ctx.substate.items()):
2136 for k, v in sorted(ctx.substate.items()):
2136 ui.write(('path %s\n') % k)
2137 ui.write(('path %s\n') % k)
2137 ui.write((' source %s\n') % v[0])
2138 ui.write((' source %s\n') % v[0])
2138 ui.write((' revision %s\n') % v[1])
2139 ui.write((' revision %s\n') % v[1])
2139
2140
2140 @command('debugsuccessorssets',
2141 @command('debugsuccessorssets',
2141 [('', 'closest', False, _('return closest successors sets only'))],
2142 [('', 'closest', False, _('return closest successors sets only'))],
2142 _('[REV]'))
2143 _('[REV]'))
2143 def debugsuccessorssets(ui, repo, *revs, **opts):
2144 def debugsuccessorssets(ui, repo, *revs, **opts):
2144 """show set of successors for revision
2145 """show set of successors for revision
2145
2146
2146 A successors set of changeset A is a consistent group of revisions that
2147 A successors set of changeset A is a consistent group of revisions that
2147 succeed A. It contains non-obsolete changesets only unless closests
2148 succeed A. It contains non-obsolete changesets only unless closests
2148 successors set is set.
2149 successors set is set.
2149
2150
2150 In most cases a changeset A has a single successors set containing a single
2151 In most cases a changeset A has a single successors set containing a single
2151 successor (changeset A replaced by A').
2152 successor (changeset A replaced by A').
2152
2153
2153 A changeset that is made obsolete with no successors are called "pruned".
2154 A changeset that is made obsolete with no successors are called "pruned".
2154 Such changesets have no successors sets at all.
2155 Such changesets have no successors sets at all.
2155
2156
2156 A changeset that has been "split" will have a successors set containing
2157 A changeset that has been "split" will have a successors set containing
2157 more than one successor.
2158 more than one successor.
2158
2159
2159 A changeset that has been rewritten in multiple different ways is called
2160 A changeset that has been rewritten in multiple different ways is called
2160 "divergent". Such changesets have multiple successor sets (each of which
2161 "divergent". Such changesets have multiple successor sets (each of which
2161 may also be split, i.e. have multiple successors).
2162 may also be split, i.e. have multiple successors).
2162
2163
2163 Results are displayed as follows::
2164 Results are displayed as follows::
2164
2165
2165 <rev1>
2166 <rev1>
2166 <successors-1A>
2167 <successors-1A>
2167 <rev2>
2168 <rev2>
2168 <successors-2A>
2169 <successors-2A>
2169 <successors-2B1> <successors-2B2> <successors-2B3>
2170 <successors-2B1> <successors-2B2> <successors-2B3>
2170
2171
2171 Here rev2 has two possible (i.e. divergent) successors sets. The first
2172 Here rev2 has two possible (i.e. divergent) successors sets. The first
2172 holds one element, whereas the second holds three (i.e. the changeset has
2173 holds one element, whereas the second holds three (i.e. the changeset has
2173 been split).
2174 been split).
2174 """
2175 """
2175 # passed to successorssets caching computation from one call to another
2176 # passed to successorssets caching computation from one call to another
2176 cache = {}
2177 cache = {}
2177 ctx2str = str
2178 ctx2str = str
2178 node2str = short
2179 node2str = short
2179 if ui.debug():
2180 if ui.debug():
2180 def ctx2str(ctx):
2181 def ctx2str(ctx):
2181 return ctx.hex()
2182 return ctx.hex()
2182 node2str = hex
2183 node2str = hex
2183 for rev in scmutil.revrange(repo, revs):
2184 for rev in scmutil.revrange(repo, revs):
2184 ctx = repo[rev]
2185 ctx = repo[rev]
2185 ui.write('%s\n'% ctx2str(ctx))
2186 ui.write('%s\n'% ctx2str(ctx))
2186 for succsset in obsutil.successorssets(repo, ctx.node(),
2187 for succsset in obsutil.successorssets(repo, ctx.node(),
2187 closest=opts['closest'],
2188 closest=opts['closest'],
2188 cache=cache):
2189 cache=cache):
2189 if succsset:
2190 if succsset:
2190 ui.write(' ')
2191 ui.write(' ')
2191 ui.write(node2str(succsset[0]))
2192 ui.write(node2str(succsset[0]))
2192 for node in succsset[1:]:
2193 for node in succsset[1:]:
2193 ui.write(' ')
2194 ui.write(' ')
2194 ui.write(node2str(node))
2195 ui.write(node2str(node))
2195 ui.write('\n')
2196 ui.write('\n')
2196
2197
2197 @command('debugtemplate',
2198 @command('debugtemplate',
2198 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2199 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2199 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2200 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2200 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2201 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2201 optionalrepo=True)
2202 optionalrepo=True)
2202 def debugtemplate(ui, repo, tmpl, **opts):
2203 def debugtemplate(ui, repo, tmpl, **opts):
2203 """parse and apply a template
2204 """parse and apply a template
2204
2205
2205 If -r/--rev is given, the template is processed as a log template and
2206 If -r/--rev is given, the template is processed as a log template and
2206 applied to the given changesets. Otherwise, it is processed as a generic
2207 applied to the given changesets. Otherwise, it is processed as a generic
2207 template.
2208 template.
2208
2209
2209 Use --verbose to print the parsed tree.
2210 Use --verbose to print the parsed tree.
2210 """
2211 """
2211 revs = None
2212 revs = None
2212 if opts[r'rev']:
2213 if opts[r'rev']:
2213 if repo is None:
2214 if repo is None:
2214 raise error.RepoError(_('there is no Mercurial repository here '
2215 raise error.RepoError(_('there is no Mercurial repository here '
2215 '(.hg not found)'))
2216 '(.hg not found)'))
2216 revs = scmutil.revrange(repo, opts[r'rev'])
2217 revs = scmutil.revrange(repo, opts[r'rev'])
2217
2218
2218 props = {}
2219 props = {}
2219 for d in opts[r'define']:
2220 for d in opts[r'define']:
2220 try:
2221 try:
2221 k, v = (e.strip() for e in d.split('=', 1))
2222 k, v = (e.strip() for e in d.split('=', 1))
2222 if not k or k == 'ui':
2223 if not k or k == 'ui':
2223 raise ValueError
2224 raise ValueError
2224 props[k] = v
2225 props[k] = v
2225 except ValueError:
2226 except ValueError:
2226 raise error.Abort(_('malformed keyword definition: %s') % d)
2227 raise error.Abort(_('malformed keyword definition: %s') % d)
2227
2228
2228 if ui.verbose:
2229 if ui.verbose:
2229 aliases = ui.configitems('templatealias')
2230 aliases = ui.configitems('templatealias')
2230 tree = templater.parse(tmpl)
2231 tree = templater.parse(tmpl)
2231 ui.note(templater.prettyformat(tree), '\n')
2232 ui.note(templater.prettyformat(tree), '\n')
2232 newtree = templater.expandaliases(tree, aliases)
2233 newtree = templater.expandaliases(tree, aliases)
2233 if newtree != tree:
2234 if newtree != tree:
2234 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2235 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2235
2236
2236 if revs is None:
2237 if revs is None:
2237 t = formatter.maketemplater(ui, tmpl)
2238 t = formatter.maketemplater(ui, tmpl)
2238 props['ui'] = ui
2239 props['ui'] = ui
2239 ui.write(t.render(props))
2240 ui.write(t.render(props))
2240 else:
2241 else:
2241 displayer = cmdutil.makelogtemplater(ui, repo, tmpl)
2242 displayer = cmdutil.makelogtemplater(ui, repo, tmpl)
2242 for r in revs:
2243 for r in revs:
2243 displayer.show(repo[r], **pycompat.strkwargs(props))
2244 displayer.show(repo[r], **pycompat.strkwargs(props))
2244 displayer.close()
2245 displayer.close()
2245
2246
2246 @command('debugupdatecaches', [])
2247 @command('debugupdatecaches', [])
2247 def debugupdatecaches(ui, repo, *pats, **opts):
2248 def debugupdatecaches(ui, repo, *pats, **opts):
2248 """warm all known caches in the repository"""
2249 """warm all known caches in the repository"""
2249 with repo.wlock(), repo.lock():
2250 with repo.wlock(), repo.lock():
2250 repo.updatecaches()
2251 repo.updatecaches()
2251
2252
2252 @command('debugupgraderepo', [
2253 @command('debugupgraderepo', [
2253 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
2254 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
2254 ('', 'run', False, _('performs an upgrade')),
2255 ('', 'run', False, _('performs an upgrade')),
2255 ])
2256 ])
2256 def debugupgraderepo(ui, repo, run=False, optimize=None):
2257 def debugupgraderepo(ui, repo, run=False, optimize=None):
2257 """upgrade a repository to use different features
2258 """upgrade a repository to use different features
2258
2259
2259 If no arguments are specified, the repository is evaluated for upgrade
2260 If no arguments are specified, the repository is evaluated for upgrade
2260 and a list of problems and potential optimizations is printed.
2261 and a list of problems and potential optimizations is printed.
2261
2262
2262 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
2263 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
2263 can be influenced via additional arguments. More details will be provided
2264 can be influenced via additional arguments. More details will be provided
2264 by the command output when run without ``--run``.
2265 by the command output when run without ``--run``.
2265
2266
2266 During the upgrade, the repository will be locked and no writes will be
2267 During the upgrade, the repository will be locked and no writes will be
2267 allowed.
2268 allowed.
2268
2269
2269 At the end of the upgrade, the repository may not be readable while new
2270 At the end of the upgrade, the repository may not be readable while new
2270 repository data is swapped in. This window will be as long as it takes to
2271 repository data is swapped in. This window will be as long as it takes to
2271 rename some directories inside the ``.hg`` directory. On most machines, this
2272 rename some directories inside the ``.hg`` directory. On most machines, this
2272 should complete almost instantaneously and the chances of a consumer being
2273 should complete almost instantaneously and the chances of a consumer being
2273 unable to access the repository should be low.
2274 unable to access the repository should be low.
2274 """
2275 """
2275 return upgrade.upgraderepo(ui, repo, run=run, optimize=optimize)
2276 return upgrade.upgraderepo(ui, repo, run=run, optimize=optimize)
2276
2277
2277 @command('debugwalk', cmdutil.walkopts, _('[OPTION]... [FILE]...'),
2278 @command('debugwalk', cmdutil.walkopts, _('[OPTION]... [FILE]...'),
2278 inferrepo=True)
2279 inferrepo=True)
2279 def debugwalk(ui, repo, *pats, **opts):
2280 def debugwalk(ui, repo, *pats, **opts):
2280 """show how files match on given patterns"""
2281 """show how files match on given patterns"""
2281 opts = pycompat.byteskwargs(opts)
2282 opts = pycompat.byteskwargs(opts)
2282 m = scmutil.match(repo[None], pats, opts)
2283 m = scmutil.match(repo[None], pats, opts)
2283 ui.write(('matcher: %r\n' % m))
2284 ui.write(('matcher: %r\n' % m))
2284 items = list(repo[None].walk(m))
2285 items = list(repo[None].walk(m))
2285 if not items:
2286 if not items:
2286 return
2287 return
2287 f = lambda fn: fn
2288 f = lambda fn: fn
2288 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2289 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2289 f = lambda fn: util.normpath(fn)
2290 f = lambda fn: util.normpath(fn)
2290 fmt = 'f %%-%ds %%-%ds %%s' % (
2291 fmt = 'f %%-%ds %%-%ds %%s' % (
2291 max([len(abs) for abs in items]),
2292 max([len(abs) for abs in items]),
2292 max([len(m.rel(abs)) for abs in items]))
2293 max([len(m.rel(abs)) for abs in items]))
2293 for abs in items:
2294 for abs in items:
2294 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2295 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2295 ui.write("%s\n" % line.rstrip())
2296 ui.write("%s\n" % line.rstrip())
2296
2297
2297 @command('debugwireargs',
2298 @command('debugwireargs',
2298 [('', 'three', '', 'three'),
2299 [('', 'three', '', 'three'),
2299 ('', 'four', '', 'four'),
2300 ('', 'four', '', 'four'),
2300 ('', 'five', '', 'five'),
2301 ('', 'five', '', 'five'),
2301 ] + cmdutil.remoteopts,
2302 ] + cmdutil.remoteopts,
2302 _('REPO [OPTIONS]... [ONE [TWO]]'),
2303 _('REPO [OPTIONS]... [ONE [TWO]]'),
2303 norepo=True)
2304 norepo=True)
2304 def debugwireargs(ui, repopath, *vals, **opts):
2305 def debugwireargs(ui, repopath, *vals, **opts):
2305 opts = pycompat.byteskwargs(opts)
2306 opts = pycompat.byteskwargs(opts)
2306 repo = hg.peer(ui, opts, repopath)
2307 repo = hg.peer(ui, opts, repopath)
2307 for opt in cmdutil.remoteopts:
2308 for opt in cmdutil.remoteopts:
2308 del opts[opt[1]]
2309 del opts[opt[1]]
2309 args = {}
2310 args = {}
2310 for k, v in opts.iteritems():
2311 for k, v in opts.iteritems():
2311 if v:
2312 if v:
2312 args[k] = v
2313 args[k] = v
2313 # run twice to check that we don't mess up the stream for the next command
2314 # run twice to check that we don't mess up the stream for the next command
2314 res1 = repo.debugwireargs(*vals, **args)
2315 res1 = repo.debugwireargs(*vals, **args)
2315 res2 = repo.debugwireargs(*vals, **args)
2316 res2 = repo.debugwireargs(*vals, **args)
2316 ui.write("%s\n" % res1)
2317 ui.write("%s\n" % res1)
2317 if res1 != res2:
2318 if res1 != res2:
2318 ui.warn("%s\n" % res2)
2319 ui.warn("%s\n" % res2)
@@ -1,212 +1,217 b''
1 hg debuginstall
1 hg debuginstall
2 $ hg debuginstall
2 $ hg debuginstall
3 checking encoding (ascii)...
3 checking encoding (ascii)...
4 checking Python executable (*) (glob)
4 checking Python executable (*) (glob)
5 checking Python version (2.*) (glob)
5 checking Python version (2.*) (glob)
6 checking Python lib (*lib*)... (glob)
6 checking Python lib (*lib*)... (glob)
7 checking Python security support (*) (glob)
7 checking Python security support (*) (glob)
8 TLS 1.2 not supported by Python install; network connections lack modern security (?)
8 TLS 1.2 not supported by Python install; network connections lack modern security (?)
9 SNI not supported by Python install; may have connectivity issues with some servers (?)
9 SNI not supported by Python install; may have connectivity issues with some servers (?)
10 checking Mercurial version (*) (glob)
10 checking Mercurial version (*) (glob)
11 checking Mercurial custom build (*) (glob)
11 checking Mercurial custom build (*) (glob)
12 checking module policy (*) (glob)
12 checking module policy (*) (glob)
13 checking installed modules (*mercurial)... (glob)
13 checking installed modules (*mercurial)... (glob)
14 checking registered compression engines (*zlib*) (glob)
14 checking registered compression engines (*zlib*) (glob)
15 checking available compression engines (*zlib*) (glob)
15 checking available compression engines (*zlib*) (glob)
16 checking available compression engines for wire protocol (*zlib*) (glob)
16 checking available compression engines for wire protocol (*zlib*) (glob)
17 checking templates (*mercurial?templates)... (glob)
17 checking templates (*mercurial?templates)... (glob)
18 checking default template (*mercurial?templates?map-cmdline.default) (glob)
18 checking default template (*mercurial?templates?map-cmdline.default) (glob)
19 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
19 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
20 checking username (test)
20 checking username (test)
21 no problems detected
21 no problems detected
22
22
23 hg debuginstall JSON
23 hg debuginstall JSON
24 $ hg debuginstall -Tjson | sed 's|\\\\|\\|g'
24 $ hg debuginstall -Tjson | sed 's|\\\\|\\|g'
25 [
25 [
26 {
26 {
27 "compengines": ["bz2", "bz2truncated", "none", "zlib"*], (glob)
27 "compengines": ["bz2", "bz2truncated", "none", "zlib"*], (glob)
28 "compenginesavail": ["bz2", "bz2truncated", "none", "zlib"*], (glob)
28 "compenginesavail": ["bz2", "bz2truncated", "none", "zlib"*], (glob)
29 "compenginesserver": [*"zlib"*], (glob)
29 "compenginesserver": [*"zlib"*], (glob)
30 "defaulttemplate": "*mercurial?templates?map-cmdline.default", (glob)
30 "defaulttemplate": "*mercurial?templates?map-cmdline.default", (glob)
31 "defaulttemplateerror": null,
31 "defaulttemplateerror": null,
32 "defaulttemplatenotfound": "default",
32 "defaulttemplatenotfound": "default",
33 "editor": "* -c \"import sys; sys.exit(0)\"", (glob)
33 "editor": "* -c \"import sys; sys.exit(0)\"", (glob)
34 "editornotfound": false,
34 "editornotfound": false,
35 "encoding": "ascii",
35 "encoding": "ascii",
36 "encodingerror": null,
36 "encodingerror": null,
37 "extensionserror": null, (no-pure !)
37 "extensionserror": null, (no-pure !)
38 "hgmodulepolicy": "*", (glob)
38 "hgmodulepolicy": "*", (glob)
39 "hgmodules": "*mercurial", (glob)
39 "hgmodules": "*mercurial", (glob)
40 "hgver": "*", (glob)
40 "hgver": "*", (glob)
41 "hgverextra": "*", (glob)
41 "hgverextra": "*", (glob)
42 "problems": 0,
42 "problems": 0,
43 "pythonexe": "*", (glob)
43 "pythonexe": "*", (glob)
44 "pythonlib": "*", (glob)
44 "pythonlib": "*", (glob)
45 "pythonsecurity": [*], (glob)
45 "pythonsecurity": [*], (glob)
46 "pythonver": "*.*.*", (glob)
46 "pythonver": "*.*.*", (glob)
47 "templatedirs": "*mercurial?templates", (glob)
47 "templatedirs": "*mercurial?templates", (glob)
48 "username": "test",
48 "username": "test",
49 "usernameerror": null,
49 "usernameerror": null,
50 "vinotfound": false
50 "vinotfound": false
51 }
51 }
52 ]
52 ]
53
53
54 hg debuginstall with no username
54 hg debuginstall with no username
55 $ HGUSER= hg debuginstall
55 $ HGUSER= hg debuginstall
56 checking encoding (ascii)...
56 checking encoding (ascii)...
57 checking Python executable (*) (glob)
57 checking Python executable (*) (glob)
58 checking Python version (2.*) (glob)
58 checking Python version (2.*) (glob)
59 checking Python lib (*lib*)... (glob)
59 checking Python lib (*lib*)... (glob)
60 checking Python security support (*) (glob)
60 checking Python security support (*) (glob)
61 TLS 1.2 not supported by Python install; network connections lack modern security (?)
61 TLS 1.2 not supported by Python install; network connections lack modern security (?)
62 SNI not supported by Python install; may have connectivity issues with some servers (?)
62 SNI not supported by Python install; may have connectivity issues with some servers (?)
63 checking Mercurial version (*) (glob)
63 checking Mercurial version (*) (glob)
64 checking Mercurial custom build (*) (glob)
64 checking Mercurial custom build (*) (glob)
65 checking module policy (*) (glob)
65 checking module policy (*) (glob)
66 checking installed modules (*mercurial)... (glob)
66 checking installed modules (*mercurial)... (glob)
67 checking registered compression engines (*zlib*) (glob)
67 checking registered compression engines (*zlib*) (glob)
68 checking available compression engines (*zlib*) (glob)
68 checking available compression engines (*zlib*) (glob)
69 checking available compression engines for wire protocol (*zlib*) (glob)
69 checking available compression engines for wire protocol (*zlib*) (glob)
70 checking templates (*mercurial?templates)... (glob)
70 checking templates (*mercurial?templates)... (glob)
71 checking default template (*mercurial?templates?map-cmdline.default) (glob)
71 checking default template (*mercurial?templates?map-cmdline.default) (glob)
72 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
72 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
73 checking username...
73 checking username...
74 no username supplied
74 no username supplied
75 (specify a username in your configuration file)
75 (specify a username in your configuration file)
76 1 problems detected, please check your install!
76 1 problems detected, please check your install!
77 [1]
77 [1]
78
78
79 hg debuginstall with invalid encoding
80 $ HGENCODING=invalidenc hg debuginstall | grep encoding
81 checking encoding (invalidenc)...
82 unknown encoding: invalidenc
83
79 path variables are expanded (~ is the same as $TESTTMP)
84 path variables are expanded (~ is the same as $TESTTMP)
80 $ mkdir tools
85 $ mkdir tools
81 $ touch tools/testeditor.exe
86 $ touch tools/testeditor.exe
82 #if execbit
87 #if execbit
83 $ chmod 755 tools/testeditor.exe
88 $ chmod 755 tools/testeditor.exe
84 #endif
89 #endif
85 $ hg debuginstall --config ui.editor=~/tools/testeditor.exe
90 $ hg debuginstall --config ui.editor=~/tools/testeditor.exe
86 checking encoding (ascii)...
91 checking encoding (ascii)...
87 checking Python executable (*) (glob)
92 checking Python executable (*) (glob)
88 checking Python version (*) (glob)
93 checking Python version (*) (glob)
89 checking Python lib (*lib*)... (glob)
94 checking Python lib (*lib*)... (glob)
90 checking Python security support (*) (glob)
95 checking Python security support (*) (glob)
91 TLS 1.2 not supported by Python install; network connections lack modern security (?)
96 TLS 1.2 not supported by Python install; network connections lack modern security (?)
92 SNI not supported by Python install; may have connectivity issues with some servers (?)
97 SNI not supported by Python install; may have connectivity issues with some servers (?)
93 checking Mercurial version (*) (glob)
98 checking Mercurial version (*) (glob)
94 checking Mercurial custom build (*) (glob)
99 checking Mercurial custom build (*) (glob)
95 checking module policy (*) (glob)
100 checking module policy (*) (glob)
96 checking installed modules (*mercurial)... (glob)
101 checking installed modules (*mercurial)... (glob)
97 checking registered compression engines (*zlib*) (glob)
102 checking registered compression engines (*zlib*) (glob)
98 checking available compression engines (*zlib*) (glob)
103 checking available compression engines (*zlib*) (glob)
99 checking available compression engines for wire protocol (*zlib*) (glob)
104 checking available compression engines for wire protocol (*zlib*) (glob)
100 checking templates (*mercurial?templates)... (glob)
105 checking templates (*mercurial?templates)... (glob)
101 checking default template (*mercurial?templates?map-cmdline.default) (glob)
106 checking default template (*mercurial?templates?map-cmdline.default) (glob)
102 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
107 checking commit editor... (* -c "import sys; sys.exit(0)") (glob)
103 checking username (test)
108 checking username (test)
104 no problems detected
109 no problems detected
105
110
106 #if test-repo
111 #if test-repo
107 $ . "$TESTDIR/helpers-testrepo.sh"
112 $ . "$TESTDIR/helpers-testrepo.sh"
108
113
109 $ cat >> wixxml.py << EOF
114 $ cat >> wixxml.py << EOF
110 > import os, subprocess, sys
115 > import os, subprocess, sys
111 > import xml.etree.ElementTree as ET
116 > import xml.etree.ElementTree as ET
112 >
117 >
113 > # MSYS mangles the path if it expands $TESTDIR
118 > # MSYS mangles the path if it expands $TESTDIR
114 > testdir = os.environ['TESTDIR']
119 > testdir = os.environ['TESTDIR']
115 > ns = {'wix' : 'http://schemas.microsoft.com/wix/2006/wi'}
120 > ns = {'wix' : 'http://schemas.microsoft.com/wix/2006/wi'}
116 >
121 >
117 > def directory(node, relpath):
122 > def directory(node, relpath):
118 > '''generator of files in the xml node, rooted at relpath'''
123 > '''generator of files in the xml node, rooted at relpath'''
119 > dirs = node.findall('./{%(wix)s}Directory' % ns)
124 > dirs = node.findall('./{%(wix)s}Directory' % ns)
120 >
125 >
121 > for d in dirs:
126 > for d in dirs:
122 > for subfile in directory(d, relpath + d.attrib['Name'] + '/'):
127 > for subfile in directory(d, relpath + d.attrib['Name'] + '/'):
123 > yield subfile
128 > yield subfile
124 >
129 >
125 > files = node.findall('./{%(wix)s}Component/{%(wix)s}File' % ns)
130 > files = node.findall('./{%(wix)s}Component/{%(wix)s}File' % ns)
126 >
131 >
127 > for f in files:
132 > for f in files:
128 > yield relpath + f.attrib['Name']
133 > yield relpath + f.attrib['Name']
129 >
134 >
130 > def hgdirectory(relpath):
135 > def hgdirectory(relpath):
131 > '''generator of tracked files, rooted at relpath'''
136 > '''generator of tracked files, rooted at relpath'''
132 > hgdir = "%s/../mercurial" % (testdir)
137 > hgdir = "%s/../mercurial" % (testdir)
133 > args = ['hg', '--cwd', hgdir, 'files', relpath]
138 > args = ['hg', '--cwd', hgdir, 'files', relpath]
134 > proc = subprocess.Popen(args, stdout=subprocess.PIPE,
139 > proc = subprocess.Popen(args, stdout=subprocess.PIPE,
135 > stderr=subprocess.PIPE)
140 > stderr=subprocess.PIPE)
136 > output = proc.communicate()[0]
141 > output = proc.communicate()[0]
137 >
142 >
138 > slash = '/'
143 > slash = '/'
139 > for line in output.splitlines():
144 > for line in output.splitlines():
140 > if os.name == 'nt':
145 > if os.name == 'nt':
141 > yield line.replace(os.sep, slash)
146 > yield line.replace(os.sep, slash)
142 > else:
147 > else:
143 > yield line
148 > yield line
144 >
149 >
145 > tracked = [f for f in hgdirectory(sys.argv[1])]
150 > tracked = [f for f in hgdirectory(sys.argv[1])]
146 >
151 >
147 > xml = ET.parse("%s/../contrib/wix/%s.wxs" % (testdir, sys.argv[1]))
152 > xml = ET.parse("%s/../contrib/wix/%s.wxs" % (testdir, sys.argv[1]))
148 > root = xml.getroot()
153 > root = xml.getroot()
149 > dir = root.find('.//{%(wix)s}DirectoryRef' % ns)
154 > dir = root.find('.//{%(wix)s}DirectoryRef' % ns)
150 >
155 >
151 > installed = [f for f in directory(dir, '')]
156 > installed = [f for f in directory(dir, '')]
152 >
157 >
153 > print('Not installed:')
158 > print('Not installed:')
154 > for f in sorted(set(tracked) - set(installed)):
159 > for f in sorted(set(tracked) - set(installed)):
155 > print(' %s' % f)
160 > print(' %s' % f)
156 >
161 >
157 > print('Not tracked:')
162 > print('Not tracked:')
158 > for f in sorted(set(installed) - set(tracked)):
163 > for f in sorted(set(installed) - set(tracked)):
159 > print(' %s' % f)
164 > print(' %s' % f)
160 > EOF
165 > EOF
161
166
162 $ ( testrepohgenv; $PYTHON wixxml.py help )
167 $ ( testrepohgenv; $PYTHON wixxml.py help )
163 Not installed:
168 Not installed:
164 help/common.txt
169 help/common.txt
165 help/hg-ssh.8.txt
170 help/hg-ssh.8.txt
166 help/hg.1.txt
171 help/hg.1.txt
167 help/hgignore.5.txt
172 help/hgignore.5.txt
168 help/hgrc.5.txt
173 help/hgrc.5.txt
169 Not tracked:
174 Not tracked:
170
175
171 $ ( testrepohgenv; $PYTHON wixxml.py templates )
176 $ ( testrepohgenv; $PYTHON wixxml.py templates )
172 Not installed:
177 Not installed:
173 Not tracked:
178 Not tracked:
174
179
175 #endif
180 #endif
176
181
177 #if virtualenv
182 #if virtualenv
178
183
179 Verify that Mercurial is installable with pip. Note that this MUST be
184 Verify that Mercurial is installable with pip. Note that this MUST be
180 the last test in this file, because we do some nasty things to the
185 the last test in this file, because we do some nasty things to the
181 shell environment in order to make the virtualenv work reliably.
186 shell environment in order to make the virtualenv work reliably.
182
187
183 $ cd $TESTTMP
188 $ cd $TESTTMP
184 Note: --no-site-packages is deprecated, but some places have an
189 Note: --no-site-packages is deprecated, but some places have an
185 ancient virtualenv from their linux distro or similar and it's not yet
190 ancient virtualenv from their linux distro or similar and it's not yet
186 the default for them.
191 the default for them.
187 $ unset PYTHONPATH
192 $ unset PYTHONPATH
188 $ $PYTHON -m virtualenv --no-site-packages --never-download installenv >> pip.log
193 $ $PYTHON -m virtualenv --no-site-packages --never-download installenv >> pip.log
189 Note: we use this weird path to run pip and hg to avoid platform differences,
194 Note: we use this weird path to run pip and hg to avoid platform differences,
190 since it's bin on most platforms but Scripts on Windows.
195 since it's bin on most platforms but Scripts on Windows.
191 $ ./installenv/*/pip install --no-index $TESTDIR/.. >> pip.log
196 $ ./installenv/*/pip install --no-index $TESTDIR/.. >> pip.log
192 $ ./installenv/*/hg debuginstall || cat pip.log
197 $ ./installenv/*/hg debuginstall || cat pip.log
193 checking encoding (ascii)...
198 checking encoding (ascii)...
194 checking Python executable (*) (glob)
199 checking Python executable (*) (glob)
195 checking Python version (2.*) (glob)
200 checking Python version (2.*) (glob)
196 checking Python lib (*)... (glob)
201 checking Python lib (*)... (glob)
197 checking Python security support (*) (glob)
202 checking Python security support (*) (glob)
198 TLS 1.2 not supported by Python install; network connections lack modern security (?)
203 TLS 1.2 not supported by Python install; network connections lack modern security (?)
199 SNI not supported by Python install; may have connectivity issues with some servers (?)
204 SNI not supported by Python install; may have connectivity issues with some servers (?)
200 checking Mercurial version (*) (glob)
205 checking Mercurial version (*) (glob)
201 checking Mercurial custom build (*) (glob)
206 checking Mercurial custom build (*) (glob)
202 checking module policy (*) (glob)
207 checking module policy (*) (glob)
203 checking installed modules (*/mercurial)... (glob)
208 checking installed modules (*/mercurial)... (glob)
204 checking registered compression engines (*) (glob)
209 checking registered compression engines (*) (glob)
205 checking available compression engines (*) (glob)
210 checking available compression engines (*) (glob)
206 checking available compression engines for wire protocol (*) (glob)
211 checking available compression engines for wire protocol (*) (glob)
207 checking templates ($TESTTMP/installenv/*/site-packages/mercurial/templates)... (glob)
212 checking templates ($TESTTMP/installenv/*/site-packages/mercurial/templates)... (glob)
208 checking default template ($TESTTMP/installenv/*/site-packages/mercurial/templates/map-cmdline.default) (glob)
213 checking default template ($TESTTMP/installenv/*/site-packages/mercurial/templates/map-cmdline.default) (glob)
209 checking commit editor... (*) (glob)
214 checking commit editor... (*) (glob)
210 checking username (test)
215 checking username (test)
211 no problems detected
216 no problems detected
212 #endif
217 #endif
General Comments 0
You need to be logged in to leave comments. Login now