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