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