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