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