##// END OF EJS Templates
debugbuilddag: add a flag to allow running it from a non-empty repository...
marmoute -
r49540:b4bc9c4f default
parent child Browse files
Show More
@@ -1,4877 +1,4884 b''
1 # debugcommands.py - command processing for debug* commands
1 # debugcommands.py - command processing for debug* commands
2 #
2 #
3 # Copyright 2005-2016 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2016 Olivia Mackall <olivia@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 binascii
10 import binascii
11 import codecs
11 import codecs
12 import collections
12 import collections
13 import contextlib
13 import contextlib
14 import difflib
14 import difflib
15 import errno
15 import errno
16 import glob
16 import glob
17 import operator
17 import operator
18 import os
18 import os
19 import platform
19 import platform
20 import random
20 import random
21 import re
21 import re
22 import socket
22 import socket
23 import ssl
23 import ssl
24 import stat
24 import stat
25 import string
25 import string
26 import subprocess
26 import subprocess
27 import sys
27 import sys
28 import time
28 import time
29
29
30 from .i18n import _
30 from .i18n import _
31 from .node import (
31 from .node import (
32 bin,
32 bin,
33 hex,
33 hex,
34 nullrev,
34 nullrev,
35 short,
35 short,
36 )
36 )
37 from .pycompat import (
37 from .pycompat import (
38 getattr,
38 getattr,
39 open,
39 open,
40 )
40 )
41 from . import (
41 from . import (
42 bundle2,
42 bundle2,
43 bundlerepo,
43 bundlerepo,
44 changegroup,
44 changegroup,
45 cmdutil,
45 cmdutil,
46 color,
46 color,
47 context,
47 context,
48 copies,
48 copies,
49 dagparser,
49 dagparser,
50 encoding,
50 encoding,
51 error,
51 error,
52 exchange,
52 exchange,
53 extensions,
53 extensions,
54 filemerge,
54 filemerge,
55 filesetlang,
55 filesetlang,
56 formatter,
56 formatter,
57 hg,
57 hg,
58 httppeer,
58 httppeer,
59 localrepo,
59 localrepo,
60 lock as lockmod,
60 lock as lockmod,
61 logcmdutil,
61 logcmdutil,
62 mergestate as mergestatemod,
62 mergestate as mergestatemod,
63 metadata,
63 metadata,
64 obsolete,
64 obsolete,
65 obsutil,
65 obsutil,
66 pathutil,
66 pathutil,
67 phases,
67 phases,
68 policy,
68 policy,
69 pvec,
69 pvec,
70 pycompat,
70 pycompat,
71 registrar,
71 registrar,
72 repair,
72 repair,
73 repoview,
73 repoview,
74 requirements,
74 requirements,
75 revlog,
75 revlog,
76 revset,
76 revset,
77 revsetlang,
77 revsetlang,
78 scmutil,
78 scmutil,
79 setdiscovery,
79 setdiscovery,
80 simplemerge,
80 simplemerge,
81 sshpeer,
81 sshpeer,
82 sslutil,
82 sslutil,
83 streamclone,
83 streamclone,
84 strip,
84 strip,
85 tags as tagsmod,
85 tags as tagsmod,
86 templater,
86 templater,
87 treediscovery,
87 treediscovery,
88 upgrade,
88 upgrade,
89 url as urlmod,
89 url as urlmod,
90 util,
90 util,
91 vfs as vfsmod,
91 vfs as vfsmod,
92 wireprotoframing,
92 wireprotoframing,
93 wireprotoserver,
93 wireprotoserver,
94 )
94 )
95 from .interfaces import repository
95 from .interfaces import repository
96 from .utils import (
96 from .utils import (
97 cborutil,
97 cborutil,
98 compression,
98 compression,
99 dateutil,
99 dateutil,
100 procutil,
100 procutil,
101 stringutil,
101 stringutil,
102 urlutil,
102 urlutil,
103 )
103 )
104
104
105 from .revlogutils import (
105 from .revlogutils import (
106 deltas as deltautil,
106 deltas as deltautil,
107 nodemap,
107 nodemap,
108 rewrite,
108 rewrite,
109 sidedata,
109 sidedata,
110 )
110 )
111
111
112 release = lockmod.release
112 release = lockmod.release
113
113
114 table = {}
114 table = {}
115 table.update(strip.command._table)
115 table.update(strip.command._table)
116 command = registrar.command(table)
116 command = registrar.command(table)
117
117
118
118
119 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
119 @command(b'debugancestor', [], _(b'[INDEX] REV1 REV2'), optionalrepo=True)
120 def debugancestor(ui, repo, *args):
120 def debugancestor(ui, repo, *args):
121 """find the ancestor revision of two revisions in a given index"""
121 """find the ancestor revision of two revisions in a given index"""
122 if len(args) == 3:
122 if len(args) == 3:
123 index, rev1, rev2 = args
123 index, rev1, rev2 = args
124 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
124 r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
125 lookup = r.lookup
125 lookup = r.lookup
126 elif len(args) == 2:
126 elif len(args) == 2:
127 if not repo:
127 if not repo:
128 raise error.Abort(
128 raise error.Abort(
129 _(b'there is no Mercurial repository here (.hg not found)')
129 _(b'there is no Mercurial repository here (.hg not found)')
130 )
130 )
131 rev1, rev2 = args
131 rev1, rev2 = args
132 r = repo.changelog
132 r = repo.changelog
133 lookup = repo.lookup
133 lookup = repo.lookup
134 else:
134 else:
135 raise error.Abort(_(b'either two or three arguments required'))
135 raise error.Abort(_(b'either two or three arguments required'))
136 a = r.ancestor(lookup(rev1), lookup(rev2))
136 a = r.ancestor(lookup(rev1), lookup(rev2))
137 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
137 ui.write(b'%d:%s\n' % (r.rev(a), hex(a)))
138
138
139
139
140 @command(b'debugantivirusrunning', [])
140 @command(b'debugantivirusrunning', [])
141 def debugantivirusrunning(ui, repo):
141 def debugantivirusrunning(ui, repo):
142 """attempt to trigger an antivirus scanner to see if one is active"""
142 """attempt to trigger an antivirus scanner to see if one is active"""
143 with repo.cachevfs.open('eicar-test-file.com', b'wb') as f:
143 with repo.cachevfs.open('eicar-test-file.com', b'wb') as f:
144 f.write(
144 f.write(
145 util.b85decode(
145 util.b85decode(
146 # This is a base85-armored version of the EICAR test file. See
146 # This is a base85-armored version of the EICAR test file. See
147 # https://en.wikipedia.org/wiki/EICAR_test_file for details.
147 # https://en.wikipedia.org/wiki/EICAR_test_file for details.
148 b'ST#=}P$fV?P+K%yP+C|uG$>GBDK|qyDK~v2MM*<JQY}+dK~6+LQba95P'
148 b'ST#=}P$fV?P+K%yP+C|uG$>GBDK|qyDK~v2MM*<JQY}+dK~6+LQba95P'
149 b'E<)&Nm5l)EmTEQR4qnHOhq9iNGnJx'
149 b'E<)&Nm5l)EmTEQR4qnHOhq9iNGnJx'
150 )
150 )
151 )
151 )
152 # Give an AV engine time to scan the file.
152 # Give an AV engine time to scan the file.
153 time.sleep(2)
153 time.sleep(2)
154 util.unlink(repo.cachevfs.join('eicar-test-file.com'))
154 util.unlink(repo.cachevfs.join('eicar-test-file.com'))
155
155
156
156
157 @command(b'debugapplystreamclonebundle', [], b'FILE')
157 @command(b'debugapplystreamclonebundle', [], b'FILE')
158 def debugapplystreamclonebundle(ui, repo, fname):
158 def debugapplystreamclonebundle(ui, repo, fname):
159 """apply a stream clone bundle file"""
159 """apply a stream clone bundle file"""
160 f = hg.openpath(ui, fname)
160 f = hg.openpath(ui, fname)
161 gen = exchange.readbundle(ui, f, fname)
161 gen = exchange.readbundle(ui, f, fname)
162 gen.apply(repo)
162 gen.apply(repo)
163
163
164
164
165 @command(
165 @command(
166 b'debugbuilddag',
166 b'debugbuilddag',
167 [
167 [
168 (
168 (
169 b'm',
169 b'm',
170 b'mergeable-file',
170 b'mergeable-file',
171 None,
171 None,
172 _(b'add single file mergeable changes'),
172 _(b'add single file mergeable changes'),
173 ),
173 ),
174 (
174 (
175 b'o',
175 b'o',
176 b'overwritten-file',
176 b'overwritten-file',
177 None,
177 None,
178 _(b'add single file all revs overwrite'),
178 _(b'add single file all revs overwrite'),
179 ),
179 ),
180 (b'n', b'new-file', None, _(b'add new file at each rev')),
180 (b'n', b'new-file', None, _(b'add new file at each rev')),
181 (
182 b'',
183 b'from-existing',
184 None,
185 _(b'continue from a non-empty repository'),
186 ),
181 ],
187 ],
182 _(b'[OPTION]... [TEXT]'),
188 _(b'[OPTION]... [TEXT]'),
183 )
189 )
184 def debugbuilddag(
190 def debugbuilddag(
185 ui,
191 ui,
186 repo,
192 repo,
187 text=None,
193 text=None,
188 mergeable_file=False,
194 mergeable_file=False,
189 overwritten_file=False,
195 overwritten_file=False,
190 new_file=False,
196 new_file=False,
197 from_existing=False,
191 ):
198 ):
192 """builds a repo with a given DAG from scratch in the current empty repo
199 """builds a repo with a given DAG from scratch in the current empty repo
193
200
194 The description of the DAG is read from stdin if not given on the
201 The description of the DAG is read from stdin if not given on the
195 command line.
202 command line.
196
203
197 Elements:
204 Elements:
198
205
199 - "+n" is a linear run of n nodes based on the current default parent
206 - "+n" is a linear run of n nodes based on the current default parent
200 - "." is a single node based on the current default parent
207 - "." is a single node based on the current default parent
201 - "$" resets the default parent to null (implied at the start);
208 - "$" resets the default parent to null (implied at the start);
202 otherwise the default parent is always the last node created
209 otherwise the default parent is always the last node created
203 - "<p" sets the default parent to the backref p
210 - "<p" sets the default parent to the backref p
204 - "*p" is a fork at parent p, which is a backref
211 - "*p" is a fork at parent p, which is a backref
205 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
212 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
206 - "/p2" is a merge of the preceding node and p2
213 - "/p2" is a merge of the preceding node and p2
207 - ":tag" defines a local tag for the preceding node
214 - ":tag" defines a local tag for the preceding node
208 - "@branch" sets the named branch for subsequent nodes
215 - "@branch" sets the named branch for subsequent nodes
209 - "#...\\n" is a comment up to the end of the line
216 - "#...\\n" is a comment up to the end of the line
210
217
211 Whitespace between the above elements is ignored.
218 Whitespace between the above elements is ignored.
212
219
213 A backref is either
220 A backref is either
214
221
215 - a number n, which references the node curr-n, where curr is the current
222 - a number n, which references the node curr-n, where curr is the current
216 node, or
223 node, or
217 - the name of a local tag you placed earlier using ":tag", or
224 - the name of a local tag you placed earlier using ":tag", or
218 - empty to denote the default parent.
225 - empty to denote the default parent.
219
226
220 All string valued-elements are either strictly alphanumeric, or must
227 All string valued-elements are either strictly alphanumeric, or must
221 be enclosed in double quotes ("..."), with "\\" as escape character.
228 be enclosed in double quotes ("..."), with "\\" as escape character.
222 """
229 """
223
230
224 if text is None:
231 if text is None:
225 ui.status(_(b"reading DAG from stdin\n"))
232 ui.status(_(b"reading DAG from stdin\n"))
226 text = ui.fin.read()
233 text = ui.fin.read()
227
234
228 cl = repo.changelog
235 cl = repo.changelog
229 if len(cl) > 0:
236 if len(cl) > 0 and not from_existing:
230 raise error.Abort(_(b'repository is not empty'))
237 raise error.Abort(_(b'repository is not empty'))
231
238
232 # determine number of revs in DAG
239 # determine number of revs in DAG
233 total = 0
240 total = 0
234 for type, data in dagparser.parsedag(text):
241 for type, data in dagparser.parsedag(text):
235 if type == b'n':
242 if type == b'n':
236 total += 1
243 total += 1
237
244
238 if mergeable_file:
245 if mergeable_file:
239 linesperrev = 2
246 linesperrev = 2
240 # make a file with k lines per rev
247 # make a file with k lines per rev
241 initialmergedlines = [
248 initialmergedlines = [
242 b'%d' % i for i in pycompat.xrange(0, total * linesperrev)
249 b'%d' % i for i in pycompat.xrange(0, total * linesperrev)
243 ]
250 ]
244 initialmergedlines.append(b"")
251 initialmergedlines.append(b"")
245
252
246 tags = []
253 tags = []
247 progress = ui.makeprogress(
254 progress = ui.makeprogress(
248 _(b'building'), unit=_(b'revisions'), total=total
255 _(b'building'), unit=_(b'revisions'), total=total
249 )
256 )
250 with progress, repo.wlock(), repo.lock(), repo.transaction(b"builddag"):
257 with progress, repo.wlock(), repo.lock(), repo.transaction(b"builddag"):
251 at = -1
258 at = -1
252 atbranch = b'default'
259 atbranch = b'default'
253 nodeids = []
260 nodeids = []
254 id = 0
261 id = 0
255 progress.update(id)
262 progress.update(id)
256 for type, data in dagparser.parsedag(text):
263 for type, data in dagparser.parsedag(text):
257 if type == b'n':
264 if type == b'n':
258 ui.note((b'node %s\n' % pycompat.bytestr(data)))
265 ui.note((b'node %s\n' % pycompat.bytestr(data)))
259 id, ps = data
266 id, ps = data
260
267
261 files = []
268 files = []
262 filecontent = {}
269 filecontent = {}
263
270
264 p2 = None
271 p2 = None
265 if mergeable_file:
272 if mergeable_file:
266 fn = b"mf"
273 fn = b"mf"
267 p1 = repo[ps[0]]
274 p1 = repo[ps[0]]
268 if len(ps) > 1:
275 if len(ps) > 1:
269 p2 = repo[ps[1]]
276 p2 = repo[ps[1]]
270 pa = p1.ancestor(p2)
277 pa = p1.ancestor(p2)
271 base, local, other = [
278 base, local, other = [
272 x[fn].data() for x in (pa, p1, p2)
279 x[fn].data() for x in (pa, p1, p2)
273 ]
280 ]
274 m3 = simplemerge.Merge3Text(base, local, other)
281 m3 = simplemerge.Merge3Text(base, local, other)
275 ml = [
282 ml = [
276 l.strip()
283 l.strip()
277 for l in simplemerge.render_minimized(m3)[0]
284 for l in simplemerge.render_minimized(m3)[0]
278 ]
285 ]
279 ml.append(b"")
286 ml.append(b"")
280 elif at > 0:
287 elif at > 0:
281 ml = p1[fn].data().split(b"\n")
288 ml = p1[fn].data().split(b"\n")
282 else:
289 else:
283 ml = initialmergedlines
290 ml = initialmergedlines
284 ml[id * linesperrev] += b" r%i" % id
291 ml[id * linesperrev] += b" r%i" % id
285 mergedtext = b"\n".join(ml)
292 mergedtext = b"\n".join(ml)
286 files.append(fn)
293 files.append(fn)
287 filecontent[fn] = mergedtext
294 filecontent[fn] = mergedtext
288
295
289 if overwritten_file:
296 if overwritten_file:
290 fn = b"of"
297 fn = b"of"
291 files.append(fn)
298 files.append(fn)
292 filecontent[fn] = b"r%i\n" % id
299 filecontent[fn] = b"r%i\n" % id
293
300
294 if new_file:
301 if new_file:
295 fn = b"nf%i" % id
302 fn = b"nf%i" % id
296 files.append(fn)
303 files.append(fn)
297 filecontent[fn] = b"r%i\n" % id
304 filecontent[fn] = b"r%i\n" % id
298 if len(ps) > 1:
305 if len(ps) > 1:
299 if not p2:
306 if not p2:
300 p2 = repo[ps[1]]
307 p2 = repo[ps[1]]
301 for fn in p2:
308 for fn in p2:
302 if fn.startswith(b"nf"):
309 if fn.startswith(b"nf"):
303 files.append(fn)
310 files.append(fn)
304 filecontent[fn] = p2[fn].data()
311 filecontent[fn] = p2[fn].data()
305
312
306 def fctxfn(repo, cx, path):
313 def fctxfn(repo, cx, path):
307 if path in filecontent:
314 if path in filecontent:
308 return context.memfilectx(
315 return context.memfilectx(
309 repo, cx, path, filecontent[path]
316 repo, cx, path, filecontent[path]
310 )
317 )
311 return None
318 return None
312
319
313 if len(ps) == 0 or ps[0] < 0:
320 if len(ps) == 0 or ps[0] < 0:
314 pars = [None, None]
321 pars = [None, None]
315 elif len(ps) == 1:
322 elif len(ps) == 1:
316 pars = [nodeids[ps[0]], None]
323 pars = [nodeids[ps[0]], None]
317 else:
324 else:
318 pars = [nodeids[p] for p in ps]
325 pars = [nodeids[p] for p in ps]
319 cx = context.memctx(
326 cx = context.memctx(
320 repo,
327 repo,
321 pars,
328 pars,
322 b"r%i" % id,
329 b"r%i" % id,
323 files,
330 files,
324 fctxfn,
331 fctxfn,
325 date=(id, 0),
332 date=(id, 0),
326 user=b"debugbuilddag",
333 user=b"debugbuilddag",
327 extra={b'branch': atbranch},
334 extra={b'branch': atbranch},
328 )
335 )
329 nodeid = repo.commitctx(cx)
336 nodeid = repo.commitctx(cx)
330 nodeids.append(nodeid)
337 nodeids.append(nodeid)
331 at = id
338 at = id
332 elif type == b'l':
339 elif type == b'l':
333 id, name = data
340 id, name = data
334 ui.note((b'tag %s\n' % name))
341 ui.note((b'tag %s\n' % name))
335 tags.append(b"%s %s\n" % (hex(repo.changelog.node(id)), name))
342 tags.append(b"%s %s\n" % (hex(repo.changelog.node(id)), name))
336 elif type == b'a':
343 elif type == b'a':
337 ui.note((b'branch %s\n' % data))
344 ui.note((b'branch %s\n' % data))
338 atbranch = data
345 atbranch = data
339 progress.update(id)
346 progress.update(id)
340
347
341 if tags:
348 if tags:
342 repo.vfs.write(b"localtags", b"".join(tags))
349 repo.vfs.write(b"localtags", b"".join(tags))
343
350
344
351
345 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
352 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
346 indent_string = b' ' * indent
353 indent_string = b' ' * indent
347 if all:
354 if all:
348 ui.writenoi18n(
355 ui.writenoi18n(
349 b"%sformat: id, p1, p2, cset, delta base, len(delta)\n"
356 b"%sformat: id, p1, p2, cset, delta base, len(delta)\n"
350 % indent_string
357 % indent_string
351 )
358 )
352
359
353 def showchunks(named):
360 def showchunks(named):
354 ui.write(b"\n%s%s\n" % (indent_string, named))
361 ui.write(b"\n%s%s\n" % (indent_string, named))
355 for deltadata in gen.deltaiter():
362 for deltadata in gen.deltaiter():
356 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
363 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
357 ui.write(
364 ui.write(
358 b"%s%s %s %s %s %s %d\n"
365 b"%s%s %s %s %s %s %d\n"
359 % (
366 % (
360 indent_string,
367 indent_string,
361 hex(node),
368 hex(node),
362 hex(p1),
369 hex(p1),
363 hex(p2),
370 hex(p2),
364 hex(cs),
371 hex(cs),
365 hex(deltabase),
372 hex(deltabase),
366 len(delta),
373 len(delta),
367 )
374 )
368 )
375 )
369
376
370 gen.changelogheader()
377 gen.changelogheader()
371 showchunks(b"changelog")
378 showchunks(b"changelog")
372 gen.manifestheader()
379 gen.manifestheader()
373 showchunks(b"manifest")
380 showchunks(b"manifest")
374 for chunkdata in iter(gen.filelogheader, {}):
381 for chunkdata in iter(gen.filelogheader, {}):
375 fname = chunkdata[b'filename']
382 fname = chunkdata[b'filename']
376 showchunks(fname)
383 showchunks(fname)
377 else:
384 else:
378 if isinstance(gen, bundle2.unbundle20):
385 if isinstance(gen, bundle2.unbundle20):
379 raise error.Abort(_(b'use debugbundle2 for this file'))
386 raise error.Abort(_(b'use debugbundle2 for this file'))
380 gen.changelogheader()
387 gen.changelogheader()
381 for deltadata in gen.deltaiter():
388 for deltadata in gen.deltaiter():
382 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
389 node, p1, p2, cs, deltabase, delta, flags, sidedata = deltadata
383 ui.write(b"%s%s\n" % (indent_string, hex(node)))
390 ui.write(b"%s%s\n" % (indent_string, hex(node)))
384
391
385
392
386 def _debugobsmarkers(ui, part, indent=0, **opts):
393 def _debugobsmarkers(ui, part, indent=0, **opts):
387 """display version and markers contained in 'data'"""
394 """display version and markers contained in 'data'"""
388 opts = pycompat.byteskwargs(opts)
395 opts = pycompat.byteskwargs(opts)
389 data = part.read()
396 data = part.read()
390 indent_string = b' ' * indent
397 indent_string = b' ' * indent
391 try:
398 try:
392 version, markers = obsolete._readmarkers(data)
399 version, markers = obsolete._readmarkers(data)
393 except error.UnknownVersion as exc:
400 except error.UnknownVersion as exc:
394 msg = b"%sunsupported version: %s (%d bytes)\n"
401 msg = b"%sunsupported version: %s (%d bytes)\n"
395 msg %= indent_string, exc.version, len(data)
402 msg %= indent_string, exc.version, len(data)
396 ui.write(msg)
403 ui.write(msg)
397 else:
404 else:
398 msg = b"%sversion: %d (%d bytes)\n"
405 msg = b"%sversion: %d (%d bytes)\n"
399 msg %= indent_string, version, len(data)
406 msg %= indent_string, version, len(data)
400 ui.write(msg)
407 ui.write(msg)
401 fm = ui.formatter(b'debugobsolete', opts)
408 fm = ui.formatter(b'debugobsolete', opts)
402 for rawmarker in sorted(markers):
409 for rawmarker in sorted(markers):
403 m = obsutil.marker(None, rawmarker)
410 m = obsutil.marker(None, rawmarker)
404 fm.startitem()
411 fm.startitem()
405 fm.plain(indent_string)
412 fm.plain(indent_string)
406 cmdutil.showmarker(fm, m)
413 cmdutil.showmarker(fm, m)
407 fm.end()
414 fm.end()
408
415
409
416
410 def _debugphaseheads(ui, data, indent=0):
417 def _debugphaseheads(ui, data, indent=0):
411 """display version and markers contained in 'data'"""
418 """display version and markers contained in 'data'"""
412 indent_string = b' ' * indent
419 indent_string = b' ' * indent
413 headsbyphase = phases.binarydecode(data)
420 headsbyphase = phases.binarydecode(data)
414 for phase in phases.allphases:
421 for phase in phases.allphases:
415 for head in headsbyphase[phase]:
422 for head in headsbyphase[phase]:
416 ui.write(indent_string)
423 ui.write(indent_string)
417 ui.write(b'%s %s\n' % (hex(head), phases.phasenames[phase]))
424 ui.write(b'%s %s\n' % (hex(head), phases.phasenames[phase]))
418
425
419
426
420 def _quasirepr(thing):
427 def _quasirepr(thing):
421 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
428 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
422 return b'{%s}' % (
429 return b'{%s}' % (
423 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
430 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
424 )
431 )
425 return pycompat.bytestr(repr(thing))
432 return pycompat.bytestr(repr(thing))
426
433
427
434
428 def _debugbundle2(ui, gen, all=None, **opts):
435 def _debugbundle2(ui, gen, all=None, **opts):
429 """lists the contents of a bundle2"""
436 """lists the contents of a bundle2"""
430 if not isinstance(gen, bundle2.unbundle20):
437 if not isinstance(gen, bundle2.unbundle20):
431 raise error.Abort(_(b'not a bundle2 file'))
438 raise error.Abort(_(b'not a bundle2 file'))
432 ui.write((b'Stream params: %s\n' % _quasirepr(gen.params)))
439 ui.write((b'Stream params: %s\n' % _quasirepr(gen.params)))
433 parttypes = opts.get('part_type', [])
440 parttypes = opts.get('part_type', [])
434 for part in gen.iterparts():
441 for part in gen.iterparts():
435 if parttypes and part.type not in parttypes:
442 if parttypes and part.type not in parttypes:
436 continue
443 continue
437 msg = b'%s -- %s (mandatory: %r)\n'
444 msg = b'%s -- %s (mandatory: %r)\n'
438 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
445 ui.write((msg % (part.type, _quasirepr(part.params), part.mandatory)))
439 if part.type == b'changegroup':
446 if part.type == b'changegroup':
440 version = part.params.get(b'version', b'01')
447 version = part.params.get(b'version', b'01')
441 cg = changegroup.getunbundler(version, part, b'UN')
448 cg = changegroup.getunbundler(version, part, b'UN')
442 if not ui.quiet:
449 if not ui.quiet:
443 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
450 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
444 if part.type == b'obsmarkers':
451 if part.type == b'obsmarkers':
445 if not ui.quiet:
452 if not ui.quiet:
446 _debugobsmarkers(ui, part, indent=4, **opts)
453 _debugobsmarkers(ui, part, indent=4, **opts)
447 if part.type == b'phase-heads':
454 if part.type == b'phase-heads':
448 if not ui.quiet:
455 if not ui.quiet:
449 _debugphaseheads(ui, part, indent=4)
456 _debugphaseheads(ui, part, indent=4)
450
457
451
458
452 @command(
459 @command(
453 b'debugbundle',
460 b'debugbundle',
454 [
461 [
455 (b'a', b'all', None, _(b'show all details')),
462 (b'a', b'all', None, _(b'show all details')),
456 (b'', b'part-type', [], _(b'show only the named part type')),
463 (b'', b'part-type', [], _(b'show only the named part type')),
457 (b'', b'spec', None, _(b'print the bundlespec of the bundle')),
464 (b'', b'spec', None, _(b'print the bundlespec of the bundle')),
458 ],
465 ],
459 _(b'FILE'),
466 _(b'FILE'),
460 norepo=True,
467 norepo=True,
461 )
468 )
462 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
469 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
463 """lists the contents of a bundle"""
470 """lists the contents of a bundle"""
464 with hg.openpath(ui, bundlepath) as f:
471 with hg.openpath(ui, bundlepath) as f:
465 if spec:
472 if spec:
466 spec = exchange.getbundlespec(ui, f)
473 spec = exchange.getbundlespec(ui, f)
467 ui.write(b'%s\n' % spec)
474 ui.write(b'%s\n' % spec)
468 return
475 return
469
476
470 gen = exchange.readbundle(ui, f, bundlepath)
477 gen = exchange.readbundle(ui, f, bundlepath)
471 if isinstance(gen, bundle2.unbundle20):
478 if isinstance(gen, bundle2.unbundle20):
472 return _debugbundle2(ui, gen, all=all, **opts)
479 return _debugbundle2(ui, gen, all=all, **opts)
473 _debugchangegroup(ui, gen, all=all, **opts)
480 _debugchangegroup(ui, gen, all=all, **opts)
474
481
475
482
476 @command(b'debugcapabilities', [], _(b'PATH'), norepo=True)
483 @command(b'debugcapabilities', [], _(b'PATH'), norepo=True)
477 def debugcapabilities(ui, path, **opts):
484 def debugcapabilities(ui, path, **opts):
478 """lists the capabilities of a remote peer"""
485 """lists the capabilities of a remote peer"""
479 opts = pycompat.byteskwargs(opts)
486 opts = pycompat.byteskwargs(opts)
480 peer = hg.peer(ui, opts, path)
487 peer = hg.peer(ui, opts, path)
481 try:
488 try:
482 caps = peer.capabilities()
489 caps = peer.capabilities()
483 ui.writenoi18n(b'Main capabilities:\n')
490 ui.writenoi18n(b'Main capabilities:\n')
484 for c in sorted(caps):
491 for c in sorted(caps):
485 ui.write(b' %s\n' % c)
492 ui.write(b' %s\n' % c)
486 b2caps = bundle2.bundle2caps(peer)
493 b2caps = bundle2.bundle2caps(peer)
487 if b2caps:
494 if b2caps:
488 ui.writenoi18n(b'Bundle2 capabilities:\n')
495 ui.writenoi18n(b'Bundle2 capabilities:\n')
489 for key, values in sorted(pycompat.iteritems(b2caps)):
496 for key, values in sorted(pycompat.iteritems(b2caps)):
490 ui.write(b' %s\n' % key)
497 ui.write(b' %s\n' % key)
491 for v in values:
498 for v in values:
492 ui.write(b' %s\n' % v)
499 ui.write(b' %s\n' % v)
493 finally:
500 finally:
494 peer.close()
501 peer.close()
495
502
496
503
497 @command(
504 @command(
498 b'debugchangedfiles',
505 b'debugchangedfiles',
499 [
506 [
500 (
507 (
501 b'',
508 b'',
502 b'compute',
509 b'compute',
503 False,
510 False,
504 b"compute information instead of reading it from storage",
511 b"compute information instead of reading it from storage",
505 ),
512 ),
506 ],
513 ],
507 b'REV',
514 b'REV',
508 )
515 )
509 def debugchangedfiles(ui, repo, rev, **opts):
516 def debugchangedfiles(ui, repo, rev, **opts):
510 """list the stored files changes for a revision"""
517 """list the stored files changes for a revision"""
511 ctx = logcmdutil.revsingle(repo, rev, None)
518 ctx = logcmdutil.revsingle(repo, rev, None)
512 files = None
519 files = None
513
520
514 if opts['compute']:
521 if opts['compute']:
515 files = metadata.compute_all_files_changes(ctx)
522 files = metadata.compute_all_files_changes(ctx)
516 else:
523 else:
517 sd = repo.changelog.sidedata(ctx.rev())
524 sd = repo.changelog.sidedata(ctx.rev())
518 files_block = sd.get(sidedata.SD_FILES)
525 files_block = sd.get(sidedata.SD_FILES)
519 if files_block is not None:
526 if files_block is not None:
520 files = metadata.decode_files_sidedata(sd)
527 files = metadata.decode_files_sidedata(sd)
521 if files is not None:
528 if files is not None:
522 for f in sorted(files.touched):
529 for f in sorted(files.touched):
523 if f in files.added:
530 if f in files.added:
524 action = b"added"
531 action = b"added"
525 elif f in files.removed:
532 elif f in files.removed:
526 action = b"removed"
533 action = b"removed"
527 elif f in files.merged:
534 elif f in files.merged:
528 action = b"merged"
535 action = b"merged"
529 elif f in files.salvaged:
536 elif f in files.salvaged:
530 action = b"salvaged"
537 action = b"salvaged"
531 else:
538 else:
532 action = b"touched"
539 action = b"touched"
533
540
534 copy_parent = b""
541 copy_parent = b""
535 copy_source = b""
542 copy_source = b""
536 if f in files.copied_from_p1:
543 if f in files.copied_from_p1:
537 copy_parent = b"p1"
544 copy_parent = b"p1"
538 copy_source = files.copied_from_p1[f]
545 copy_source = files.copied_from_p1[f]
539 elif f in files.copied_from_p2:
546 elif f in files.copied_from_p2:
540 copy_parent = b"p2"
547 copy_parent = b"p2"
541 copy_source = files.copied_from_p2[f]
548 copy_source = files.copied_from_p2[f]
542
549
543 data = (action, copy_parent, f, copy_source)
550 data = (action, copy_parent, f, copy_source)
544 template = b"%-8s %2s: %s, %s;\n"
551 template = b"%-8s %2s: %s, %s;\n"
545 ui.write(template % data)
552 ui.write(template % data)
546
553
547
554
548 @command(b'debugcheckstate', [], b'')
555 @command(b'debugcheckstate', [], b'')
549 def debugcheckstate(ui, repo):
556 def debugcheckstate(ui, repo):
550 """validate the correctness of the current dirstate"""
557 """validate the correctness of the current dirstate"""
551 parent1, parent2 = repo.dirstate.parents()
558 parent1, parent2 = repo.dirstate.parents()
552 m1 = repo[parent1].manifest()
559 m1 = repo[parent1].manifest()
553 m2 = repo[parent2].manifest()
560 m2 = repo[parent2].manifest()
554 errors = 0
561 errors = 0
555 for err in repo.dirstate.verify(m1, m2):
562 for err in repo.dirstate.verify(m1, m2):
556 ui.warn(err[0] % err[1:])
563 ui.warn(err[0] % err[1:])
557 errors += 1
564 errors += 1
558 if errors:
565 if errors:
559 errstr = _(b".hg/dirstate inconsistent with current parent's manifest")
566 errstr = _(b".hg/dirstate inconsistent with current parent's manifest")
560 raise error.Abort(errstr)
567 raise error.Abort(errstr)
561
568
562
569
563 @command(
570 @command(
564 b'debugcolor',
571 b'debugcolor',
565 [(b'', b'style', None, _(b'show all configured styles'))],
572 [(b'', b'style', None, _(b'show all configured styles'))],
566 b'hg debugcolor',
573 b'hg debugcolor',
567 )
574 )
568 def debugcolor(ui, repo, **opts):
575 def debugcolor(ui, repo, **opts):
569 """show available color, effects or style"""
576 """show available color, effects or style"""
570 ui.writenoi18n(b'color mode: %s\n' % stringutil.pprint(ui._colormode))
577 ui.writenoi18n(b'color mode: %s\n' % stringutil.pprint(ui._colormode))
571 if opts.get('style'):
578 if opts.get('style'):
572 return _debugdisplaystyle(ui)
579 return _debugdisplaystyle(ui)
573 else:
580 else:
574 return _debugdisplaycolor(ui)
581 return _debugdisplaycolor(ui)
575
582
576
583
577 def _debugdisplaycolor(ui):
584 def _debugdisplaycolor(ui):
578 ui = ui.copy()
585 ui = ui.copy()
579 ui._styles.clear()
586 ui._styles.clear()
580 for effect in color._activeeffects(ui).keys():
587 for effect in color._activeeffects(ui).keys():
581 ui._styles[effect] = effect
588 ui._styles[effect] = effect
582 if ui._terminfoparams:
589 if ui._terminfoparams:
583 for k, v in ui.configitems(b'color'):
590 for k, v in ui.configitems(b'color'):
584 if k.startswith(b'color.'):
591 if k.startswith(b'color.'):
585 ui._styles[k] = k[6:]
592 ui._styles[k] = k[6:]
586 elif k.startswith(b'terminfo.'):
593 elif k.startswith(b'terminfo.'):
587 ui._styles[k] = k[9:]
594 ui._styles[k] = k[9:]
588 ui.write(_(b'available colors:\n'))
595 ui.write(_(b'available colors:\n'))
589 # sort label with a '_' after the other to group '_background' entry.
596 # sort label with a '_' after the other to group '_background' entry.
590 items = sorted(ui._styles.items(), key=lambda i: (b'_' in i[0], i[0], i[1]))
597 items = sorted(ui._styles.items(), key=lambda i: (b'_' in i[0], i[0], i[1]))
591 for colorname, label in items:
598 for colorname, label in items:
592 ui.write(b'%s\n' % colorname, label=label)
599 ui.write(b'%s\n' % colorname, label=label)
593
600
594
601
595 def _debugdisplaystyle(ui):
602 def _debugdisplaystyle(ui):
596 ui.write(_(b'available style:\n'))
603 ui.write(_(b'available style:\n'))
597 if not ui._styles:
604 if not ui._styles:
598 return
605 return
599 width = max(len(s) for s in ui._styles)
606 width = max(len(s) for s in ui._styles)
600 for label, effects in sorted(ui._styles.items()):
607 for label, effects in sorted(ui._styles.items()):
601 ui.write(b'%s' % label, label=label)
608 ui.write(b'%s' % label, label=label)
602 if effects:
609 if effects:
603 # 50
610 # 50
604 ui.write(b': ')
611 ui.write(b': ')
605 ui.write(b' ' * (max(0, width - len(label))))
612 ui.write(b' ' * (max(0, width - len(label))))
606 ui.write(b', '.join(ui.label(e, e) for e in effects.split()))
613 ui.write(b', '.join(ui.label(e, e) for e in effects.split()))
607 ui.write(b'\n')
614 ui.write(b'\n')
608
615
609
616
610 @command(b'debugcreatestreamclonebundle', [], b'FILE')
617 @command(b'debugcreatestreamclonebundle', [], b'FILE')
611 def debugcreatestreamclonebundle(ui, repo, fname):
618 def debugcreatestreamclonebundle(ui, repo, fname):
612 """create a stream clone bundle file
619 """create a stream clone bundle file
613
620
614 Stream bundles are special bundles that are essentially archives of
621 Stream bundles are special bundles that are essentially archives of
615 revlog files. They are commonly used for cloning very quickly.
622 revlog files. They are commonly used for cloning very quickly.
616 """
623 """
617 # TODO we may want to turn this into an abort when this functionality
624 # TODO we may want to turn this into an abort when this functionality
618 # is moved into `hg bundle`.
625 # is moved into `hg bundle`.
619 if phases.hassecret(repo):
626 if phases.hassecret(repo):
620 ui.warn(
627 ui.warn(
621 _(
628 _(
622 b'(warning: stream clone bundle will contain secret '
629 b'(warning: stream clone bundle will contain secret '
623 b'revisions)\n'
630 b'revisions)\n'
624 )
631 )
625 )
632 )
626
633
627 requirements, gen = streamclone.generatebundlev1(repo)
634 requirements, gen = streamclone.generatebundlev1(repo)
628 changegroup.writechunks(ui, gen, fname)
635 changegroup.writechunks(ui, gen, fname)
629
636
630 ui.write(_(b'bundle requirements: %s\n') % b', '.join(sorted(requirements)))
637 ui.write(_(b'bundle requirements: %s\n') % b', '.join(sorted(requirements)))
631
638
632
639
633 @command(
640 @command(
634 b'debugdag',
641 b'debugdag',
635 [
642 [
636 (b't', b'tags', None, _(b'use tags as labels')),
643 (b't', b'tags', None, _(b'use tags as labels')),
637 (b'b', b'branches', None, _(b'annotate with branch names')),
644 (b'b', b'branches', None, _(b'annotate with branch names')),
638 (b'', b'dots', None, _(b'use dots for runs')),
645 (b'', b'dots', None, _(b'use dots for runs')),
639 (b's', b'spaces', None, _(b'separate elements by spaces')),
646 (b's', b'spaces', None, _(b'separate elements by spaces')),
640 ],
647 ],
641 _(b'[OPTION]... [FILE [REV]...]'),
648 _(b'[OPTION]... [FILE [REV]...]'),
642 optionalrepo=True,
649 optionalrepo=True,
643 )
650 )
644 def debugdag(ui, repo, file_=None, *revs, **opts):
651 def debugdag(ui, repo, file_=None, *revs, **opts):
645 """format the changelog or an index DAG as a concise textual description
652 """format the changelog or an index DAG as a concise textual description
646
653
647 If you pass a revlog index, the revlog's DAG is emitted. If you list
654 If you pass a revlog index, the revlog's DAG is emitted. If you list
648 revision numbers, they get labeled in the output as rN.
655 revision numbers, they get labeled in the output as rN.
649
656
650 Otherwise, the changelog DAG of the current repo is emitted.
657 Otherwise, the changelog DAG of the current repo is emitted.
651 """
658 """
652 spaces = opts.get('spaces')
659 spaces = opts.get('spaces')
653 dots = opts.get('dots')
660 dots = opts.get('dots')
654 if file_:
661 if file_:
655 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
662 rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
656 revs = {int(r) for r in revs}
663 revs = {int(r) for r in revs}
657
664
658 def events():
665 def events():
659 for r in rlog:
666 for r in rlog:
660 yield b'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
667 yield b'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
661 if r in revs:
668 if r in revs:
662 yield b'l', (r, b"r%i" % r)
669 yield b'l', (r, b"r%i" % r)
663
670
664 elif repo:
671 elif repo:
665 cl = repo.changelog
672 cl = repo.changelog
666 tags = opts.get('tags')
673 tags = opts.get('tags')
667 branches = opts.get('branches')
674 branches = opts.get('branches')
668 if tags:
675 if tags:
669 labels = {}
676 labels = {}
670 for l, n in repo.tags().items():
677 for l, n in repo.tags().items():
671 labels.setdefault(cl.rev(n), []).append(l)
678 labels.setdefault(cl.rev(n), []).append(l)
672
679
673 def events():
680 def events():
674 b = b"default"
681 b = b"default"
675 for r in cl:
682 for r in cl:
676 if branches:
683 if branches:
677 newb = cl.read(cl.node(r))[5][b'branch']
684 newb = cl.read(cl.node(r))[5][b'branch']
678 if newb != b:
685 if newb != b:
679 yield b'a', newb
686 yield b'a', newb
680 b = newb
687 b = newb
681 yield b'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
688 yield b'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
682 if tags:
689 if tags:
683 ls = labels.get(r)
690 ls = labels.get(r)
684 if ls:
691 if ls:
685 for l in ls:
692 for l in ls:
686 yield b'l', (r, l)
693 yield b'l', (r, l)
687
694
688 else:
695 else:
689 raise error.Abort(_(b'need repo for changelog dag'))
696 raise error.Abort(_(b'need repo for changelog dag'))
690
697
691 for line in dagparser.dagtextlines(
698 for line in dagparser.dagtextlines(
692 events(),
699 events(),
693 addspaces=spaces,
700 addspaces=spaces,
694 wraplabels=True,
701 wraplabels=True,
695 wrapannotations=True,
702 wrapannotations=True,
696 wrapnonlinear=dots,
703 wrapnonlinear=dots,
697 usedots=dots,
704 usedots=dots,
698 maxlinewidth=70,
705 maxlinewidth=70,
699 ):
706 ):
700 ui.write(line)
707 ui.write(line)
701 ui.write(b"\n")
708 ui.write(b"\n")
702
709
703
710
704 @command(b'debugdata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
711 @command(b'debugdata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
705 def debugdata(ui, repo, file_, rev=None, **opts):
712 def debugdata(ui, repo, file_, rev=None, **opts):
706 """dump the contents of a data file revision"""
713 """dump the contents of a data file revision"""
707 opts = pycompat.byteskwargs(opts)
714 opts = pycompat.byteskwargs(opts)
708 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
715 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
709 if rev is not None:
716 if rev is not None:
710 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
717 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
711 file_, rev = None, file_
718 file_, rev = None, file_
712 elif rev is None:
719 elif rev is None:
713 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
720 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
714 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
721 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
715 try:
722 try:
716 ui.write(r.rawdata(r.lookup(rev)))
723 ui.write(r.rawdata(r.lookup(rev)))
717 except KeyError:
724 except KeyError:
718 raise error.Abort(_(b'invalid revision identifier %s') % rev)
725 raise error.Abort(_(b'invalid revision identifier %s') % rev)
719
726
720
727
721 @command(
728 @command(
722 b'debugdate',
729 b'debugdate',
723 [(b'e', b'extended', None, _(b'try extended date formats'))],
730 [(b'e', b'extended', None, _(b'try extended date formats'))],
724 _(b'[-e] DATE [RANGE]'),
731 _(b'[-e] DATE [RANGE]'),
725 norepo=True,
732 norepo=True,
726 optionalrepo=True,
733 optionalrepo=True,
727 )
734 )
728 def debugdate(ui, date, range=None, **opts):
735 def debugdate(ui, date, range=None, **opts):
729 """parse and display a date"""
736 """parse and display a date"""
730 if opts["extended"]:
737 if opts["extended"]:
731 d = dateutil.parsedate(date, dateutil.extendeddateformats)
738 d = dateutil.parsedate(date, dateutil.extendeddateformats)
732 else:
739 else:
733 d = dateutil.parsedate(date)
740 d = dateutil.parsedate(date)
734 ui.writenoi18n(b"internal: %d %d\n" % d)
741 ui.writenoi18n(b"internal: %d %d\n" % d)
735 ui.writenoi18n(b"standard: %s\n" % dateutil.datestr(d))
742 ui.writenoi18n(b"standard: %s\n" % dateutil.datestr(d))
736 if range:
743 if range:
737 m = dateutil.matchdate(range)
744 m = dateutil.matchdate(range)
738 ui.writenoi18n(b"match: %s\n" % m(d[0]))
745 ui.writenoi18n(b"match: %s\n" % m(d[0]))
739
746
740
747
741 @command(
748 @command(
742 b'debugdeltachain',
749 b'debugdeltachain',
743 cmdutil.debugrevlogopts + cmdutil.formatteropts,
750 cmdutil.debugrevlogopts + cmdutil.formatteropts,
744 _(b'-c|-m|FILE'),
751 _(b'-c|-m|FILE'),
745 optionalrepo=True,
752 optionalrepo=True,
746 )
753 )
747 def debugdeltachain(ui, repo, file_=None, **opts):
754 def debugdeltachain(ui, repo, file_=None, **opts):
748 """dump information about delta chains in a revlog
755 """dump information about delta chains in a revlog
749
756
750 Output can be templatized. Available template keywords are:
757 Output can be templatized. Available template keywords are:
751
758
752 :``rev``: revision number
759 :``rev``: revision number
753 :``chainid``: delta chain identifier (numbered by unique base)
760 :``chainid``: delta chain identifier (numbered by unique base)
754 :``chainlen``: delta chain length to this revision
761 :``chainlen``: delta chain length to this revision
755 :``prevrev``: previous revision in delta chain
762 :``prevrev``: previous revision in delta chain
756 :``deltatype``: role of delta / how it was computed
763 :``deltatype``: role of delta / how it was computed
757 :``compsize``: compressed size of revision
764 :``compsize``: compressed size of revision
758 :``uncompsize``: uncompressed size of revision
765 :``uncompsize``: uncompressed size of revision
759 :``chainsize``: total size of compressed revisions in chain
766 :``chainsize``: total size of compressed revisions in chain
760 :``chainratio``: total chain size divided by uncompressed revision size
767 :``chainratio``: total chain size divided by uncompressed revision size
761 (new delta chains typically start at ratio 2.00)
768 (new delta chains typically start at ratio 2.00)
762 :``lindist``: linear distance from base revision in delta chain to end
769 :``lindist``: linear distance from base revision in delta chain to end
763 of this revision
770 of this revision
764 :``extradist``: total size of revisions not part of this delta chain from
771 :``extradist``: total size of revisions not part of this delta chain from
765 base of delta chain to end of this revision; a measurement
772 base of delta chain to end of this revision; a measurement
766 of how much extra data we need to read/seek across to read
773 of how much extra data we need to read/seek across to read
767 the delta chain for this revision
774 the delta chain for this revision
768 :``extraratio``: extradist divided by chainsize; another representation of
775 :``extraratio``: extradist divided by chainsize; another representation of
769 how much unrelated data is needed to load this delta chain
776 how much unrelated data is needed to load this delta chain
770
777
771 If the repository is configured to use the sparse read, additional keywords
778 If the repository is configured to use the sparse read, additional keywords
772 are available:
779 are available:
773
780
774 :``readsize``: total size of data read from the disk for a revision
781 :``readsize``: total size of data read from the disk for a revision
775 (sum of the sizes of all the blocks)
782 (sum of the sizes of all the blocks)
776 :``largestblock``: size of the largest block of data read from the disk
783 :``largestblock``: size of the largest block of data read from the disk
777 :``readdensity``: density of useful bytes in the data read from the disk
784 :``readdensity``: density of useful bytes in the data read from the disk
778 :``srchunks``: in how many data hunks the whole revision would be read
785 :``srchunks``: in how many data hunks the whole revision would be read
779
786
780 The sparse read can be enabled with experimental.sparse-read = True
787 The sparse read can be enabled with experimental.sparse-read = True
781 """
788 """
782 opts = pycompat.byteskwargs(opts)
789 opts = pycompat.byteskwargs(opts)
783 r = cmdutil.openrevlog(repo, b'debugdeltachain', file_, opts)
790 r = cmdutil.openrevlog(repo, b'debugdeltachain', file_, opts)
784 index = r.index
791 index = r.index
785 start = r.start
792 start = r.start
786 length = r.length
793 length = r.length
787 generaldelta = r._generaldelta
794 generaldelta = r._generaldelta
788 withsparseread = getattr(r, '_withsparseread', False)
795 withsparseread = getattr(r, '_withsparseread', False)
789
796
790 def revinfo(rev):
797 def revinfo(rev):
791 e = index[rev]
798 e = index[rev]
792 compsize = e[1]
799 compsize = e[1]
793 uncompsize = e[2]
800 uncompsize = e[2]
794 chainsize = 0
801 chainsize = 0
795
802
796 if generaldelta:
803 if generaldelta:
797 if e[3] == e[5]:
804 if e[3] == e[5]:
798 deltatype = b'p1'
805 deltatype = b'p1'
799 elif e[3] == e[6]:
806 elif e[3] == e[6]:
800 deltatype = b'p2'
807 deltatype = b'p2'
801 elif e[3] == rev - 1:
808 elif e[3] == rev - 1:
802 deltatype = b'prev'
809 deltatype = b'prev'
803 elif e[3] == rev:
810 elif e[3] == rev:
804 deltatype = b'base'
811 deltatype = b'base'
805 else:
812 else:
806 deltatype = b'other'
813 deltatype = b'other'
807 else:
814 else:
808 if e[3] == rev:
815 if e[3] == rev:
809 deltatype = b'base'
816 deltatype = b'base'
810 else:
817 else:
811 deltatype = b'prev'
818 deltatype = b'prev'
812
819
813 chain = r._deltachain(rev)[0]
820 chain = r._deltachain(rev)[0]
814 for iterrev in chain:
821 for iterrev in chain:
815 e = index[iterrev]
822 e = index[iterrev]
816 chainsize += e[1]
823 chainsize += e[1]
817
824
818 return compsize, uncompsize, deltatype, chain, chainsize
825 return compsize, uncompsize, deltatype, chain, chainsize
819
826
820 fm = ui.formatter(b'debugdeltachain', opts)
827 fm = ui.formatter(b'debugdeltachain', opts)
821
828
822 fm.plain(
829 fm.plain(
823 b' rev chain# chainlen prev delta '
830 b' rev chain# chainlen prev delta '
824 b'size rawsize chainsize ratio lindist extradist '
831 b'size rawsize chainsize ratio lindist extradist '
825 b'extraratio'
832 b'extraratio'
826 )
833 )
827 if withsparseread:
834 if withsparseread:
828 fm.plain(b' readsize largestblk rddensity srchunks')
835 fm.plain(b' readsize largestblk rddensity srchunks')
829 fm.plain(b'\n')
836 fm.plain(b'\n')
830
837
831 chainbases = {}
838 chainbases = {}
832 for rev in r:
839 for rev in r:
833 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
840 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
834 chainbase = chain[0]
841 chainbase = chain[0]
835 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
842 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
836 basestart = start(chainbase)
843 basestart = start(chainbase)
837 revstart = start(rev)
844 revstart = start(rev)
838 lineardist = revstart + comp - basestart
845 lineardist = revstart + comp - basestart
839 extradist = lineardist - chainsize
846 extradist = lineardist - chainsize
840 try:
847 try:
841 prevrev = chain[-2]
848 prevrev = chain[-2]
842 except IndexError:
849 except IndexError:
843 prevrev = -1
850 prevrev = -1
844
851
845 if uncomp != 0:
852 if uncomp != 0:
846 chainratio = float(chainsize) / float(uncomp)
853 chainratio = float(chainsize) / float(uncomp)
847 else:
854 else:
848 chainratio = chainsize
855 chainratio = chainsize
849
856
850 if chainsize != 0:
857 if chainsize != 0:
851 extraratio = float(extradist) / float(chainsize)
858 extraratio = float(extradist) / float(chainsize)
852 else:
859 else:
853 extraratio = extradist
860 extraratio = extradist
854
861
855 fm.startitem()
862 fm.startitem()
856 fm.write(
863 fm.write(
857 b'rev chainid chainlen prevrev deltatype compsize '
864 b'rev chainid chainlen prevrev deltatype compsize '
858 b'uncompsize chainsize chainratio lindist extradist '
865 b'uncompsize chainsize chainratio lindist extradist '
859 b'extraratio',
866 b'extraratio',
860 b'%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
867 b'%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
861 rev,
868 rev,
862 chainid,
869 chainid,
863 len(chain),
870 len(chain),
864 prevrev,
871 prevrev,
865 deltatype,
872 deltatype,
866 comp,
873 comp,
867 uncomp,
874 uncomp,
868 chainsize,
875 chainsize,
869 chainratio,
876 chainratio,
870 lineardist,
877 lineardist,
871 extradist,
878 extradist,
872 extraratio,
879 extraratio,
873 rev=rev,
880 rev=rev,
874 chainid=chainid,
881 chainid=chainid,
875 chainlen=len(chain),
882 chainlen=len(chain),
876 prevrev=prevrev,
883 prevrev=prevrev,
877 deltatype=deltatype,
884 deltatype=deltatype,
878 compsize=comp,
885 compsize=comp,
879 uncompsize=uncomp,
886 uncompsize=uncomp,
880 chainsize=chainsize,
887 chainsize=chainsize,
881 chainratio=chainratio,
888 chainratio=chainratio,
882 lindist=lineardist,
889 lindist=lineardist,
883 extradist=extradist,
890 extradist=extradist,
884 extraratio=extraratio,
891 extraratio=extraratio,
885 )
892 )
886 if withsparseread:
893 if withsparseread:
887 readsize = 0
894 readsize = 0
888 largestblock = 0
895 largestblock = 0
889 srchunks = 0
896 srchunks = 0
890
897
891 for revschunk in deltautil.slicechunk(r, chain):
898 for revschunk in deltautil.slicechunk(r, chain):
892 srchunks += 1
899 srchunks += 1
893 blkend = start(revschunk[-1]) + length(revschunk[-1])
900 blkend = start(revschunk[-1]) + length(revschunk[-1])
894 blksize = blkend - start(revschunk[0])
901 blksize = blkend - start(revschunk[0])
895
902
896 readsize += blksize
903 readsize += blksize
897 if largestblock < blksize:
904 if largestblock < blksize:
898 largestblock = blksize
905 largestblock = blksize
899
906
900 if readsize:
907 if readsize:
901 readdensity = float(chainsize) / float(readsize)
908 readdensity = float(chainsize) / float(readsize)
902 else:
909 else:
903 readdensity = 1
910 readdensity = 1
904
911
905 fm.write(
912 fm.write(
906 b'readsize largestblock readdensity srchunks',
913 b'readsize largestblock readdensity srchunks',
907 b' %10d %10d %9.5f %8d',
914 b' %10d %10d %9.5f %8d',
908 readsize,
915 readsize,
909 largestblock,
916 largestblock,
910 readdensity,
917 readdensity,
911 srchunks,
918 srchunks,
912 readsize=readsize,
919 readsize=readsize,
913 largestblock=largestblock,
920 largestblock=largestblock,
914 readdensity=readdensity,
921 readdensity=readdensity,
915 srchunks=srchunks,
922 srchunks=srchunks,
916 )
923 )
917
924
918 fm.plain(b'\n')
925 fm.plain(b'\n')
919
926
920 fm.end()
927 fm.end()
921
928
922
929
923 @command(
930 @command(
924 b'debugdirstate|debugstate',
931 b'debugdirstate|debugstate',
925 [
932 [
926 (
933 (
927 b'',
934 b'',
928 b'nodates',
935 b'nodates',
929 None,
936 None,
930 _(b'do not display the saved mtime (DEPRECATED)'),
937 _(b'do not display the saved mtime (DEPRECATED)'),
931 ),
938 ),
932 (b'', b'dates', True, _(b'display the saved mtime')),
939 (b'', b'dates', True, _(b'display the saved mtime')),
933 (b'', b'datesort', None, _(b'sort by saved mtime')),
940 (b'', b'datesort', None, _(b'sort by saved mtime')),
934 (
941 (
935 b'',
942 b'',
936 b'all',
943 b'all',
937 False,
944 False,
938 _(b'display dirstate-v2 tree nodes that would not exist in v1'),
945 _(b'display dirstate-v2 tree nodes that would not exist in v1'),
939 ),
946 ),
940 ],
947 ],
941 _(b'[OPTION]...'),
948 _(b'[OPTION]...'),
942 )
949 )
943 def debugstate(ui, repo, **opts):
950 def debugstate(ui, repo, **opts):
944 """show the contents of the current dirstate"""
951 """show the contents of the current dirstate"""
945
952
946 nodates = not opts['dates']
953 nodates = not opts['dates']
947 if opts.get('nodates') is not None:
954 if opts.get('nodates') is not None:
948 nodates = True
955 nodates = True
949 datesort = opts.get('datesort')
956 datesort = opts.get('datesort')
950
957
951 if datesort:
958 if datesort:
952
959
953 def keyfunc(entry):
960 def keyfunc(entry):
954 filename, _state, _mode, _size, mtime = entry
961 filename, _state, _mode, _size, mtime = entry
955 return (mtime, filename)
962 return (mtime, filename)
956
963
957 else:
964 else:
958 keyfunc = None # sort by filename
965 keyfunc = None # sort by filename
959 entries = list(repo.dirstate._map.debug_iter(all=opts['all']))
966 entries = list(repo.dirstate._map.debug_iter(all=opts['all']))
960 entries.sort(key=keyfunc)
967 entries.sort(key=keyfunc)
961 for entry in entries:
968 for entry in entries:
962 filename, state, mode, size, mtime = entry
969 filename, state, mode, size, mtime = entry
963 if mtime == -1:
970 if mtime == -1:
964 timestr = b'unset '
971 timestr = b'unset '
965 elif nodates:
972 elif nodates:
966 timestr = b'set '
973 timestr = b'set '
967 else:
974 else:
968 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(mtime))
975 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(mtime))
969 timestr = encoding.strtolocal(timestr)
976 timestr = encoding.strtolocal(timestr)
970 if mode & 0o20000:
977 if mode & 0o20000:
971 mode = b'lnk'
978 mode = b'lnk'
972 else:
979 else:
973 mode = b'%3o' % (mode & 0o777 & ~util.umask)
980 mode = b'%3o' % (mode & 0o777 & ~util.umask)
974 ui.write(b"%c %s %10d %s%s\n" % (state, mode, size, timestr, filename))
981 ui.write(b"%c %s %10d %s%s\n" % (state, mode, size, timestr, filename))
975 for f in repo.dirstate.copies():
982 for f in repo.dirstate.copies():
976 ui.write(_(b"copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
983 ui.write(_(b"copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
977
984
978
985
979 @command(
986 @command(
980 b'debugdirstateignorepatternshash',
987 b'debugdirstateignorepatternshash',
981 [],
988 [],
982 _(b''),
989 _(b''),
983 )
990 )
984 def debugdirstateignorepatternshash(ui, repo, **opts):
991 def debugdirstateignorepatternshash(ui, repo, **opts):
985 """show the hash of ignore patterns stored in dirstate if v2,
992 """show the hash of ignore patterns stored in dirstate if v2,
986 or nothing for dirstate-v2
993 or nothing for dirstate-v2
987 """
994 """
988 if repo.dirstate._use_dirstate_v2:
995 if repo.dirstate._use_dirstate_v2:
989 docket = repo.dirstate._map.docket
996 docket = repo.dirstate._map.docket
990 hash_len = 20 # 160 bits for SHA-1
997 hash_len = 20 # 160 bits for SHA-1
991 hash_bytes = docket.tree_metadata[-hash_len:]
998 hash_bytes = docket.tree_metadata[-hash_len:]
992 ui.write(binascii.hexlify(hash_bytes) + b'\n')
999 ui.write(binascii.hexlify(hash_bytes) + b'\n')
993
1000
994
1001
995 @command(
1002 @command(
996 b'debugdiscovery',
1003 b'debugdiscovery',
997 [
1004 [
998 (b'', b'old', None, _(b'use old-style discovery')),
1005 (b'', b'old', None, _(b'use old-style discovery')),
999 (
1006 (
1000 b'',
1007 b'',
1001 b'nonheads',
1008 b'nonheads',
1002 None,
1009 None,
1003 _(b'use old-style discovery with non-heads included'),
1010 _(b'use old-style discovery with non-heads included'),
1004 ),
1011 ),
1005 (b'', b'rev', [], b'restrict discovery to this set of revs'),
1012 (b'', b'rev', [], b'restrict discovery to this set of revs'),
1006 (b'', b'seed', b'12323', b'specify the random seed use for discovery'),
1013 (b'', b'seed', b'12323', b'specify the random seed use for discovery'),
1007 (
1014 (
1008 b'',
1015 b'',
1009 b'local-as-revs',
1016 b'local-as-revs',
1010 b"",
1017 b"",
1011 b'treat local has having these revisions only',
1018 b'treat local has having these revisions only',
1012 ),
1019 ),
1013 (
1020 (
1014 b'',
1021 b'',
1015 b'remote-as-revs',
1022 b'remote-as-revs',
1016 b"",
1023 b"",
1017 b'use local as remote, with only these these revisions',
1024 b'use local as remote, with only these these revisions',
1018 ),
1025 ),
1019 ]
1026 ]
1020 + cmdutil.remoteopts
1027 + cmdutil.remoteopts
1021 + cmdutil.formatteropts,
1028 + cmdutil.formatteropts,
1022 _(b'[--rev REV] [OTHER]'),
1029 _(b'[--rev REV] [OTHER]'),
1023 )
1030 )
1024 def debugdiscovery(ui, repo, remoteurl=b"default", **opts):
1031 def debugdiscovery(ui, repo, remoteurl=b"default", **opts):
1025 """runs the changeset discovery protocol in isolation
1032 """runs the changeset discovery protocol in isolation
1026
1033
1027 The local peer can be "replaced" by a subset of the local repository by
1034 The local peer can be "replaced" by a subset of the local repository by
1028 using the `--local-as-revs` flag. Int he same way, usual `remote` peer can
1035 using the `--local-as-revs` flag. Int he same way, usual `remote` peer can
1029 be "replaced" by a subset of the local repository using the
1036 be "replaced" by a subset of the local repository using the
1030 `--local-as-revs` flag. This is useful to efficiently debug pathological
1037 `--local-as-revs` flag. This is useful to efficiently debug pathological
1031 discovery situation.
1038 discovery situation.
1032
1039
1033 The following developer oriented config are relevant for people playing with this command:
1040 The following developer oriented config are relevant for people playing with this command:
1034
1041
1035 * devel.discovery.exchange-heads=True
1042 * devel.discovery.exchange-heads=True
1036
1043
1037 If False, the discovery will not start with
1044 If False, the discovery will not start with
1038 remote head fetching and local head querying.
1045 remote head fetching and local head querying.
1039
1046
1040 * devel.discovery.grow-sample=True
1047 * devel.discovery.grow-sample=True
1041
1048
1042 If False, the sample size used in set discovery will not be increased
1049 If False, the sample size used in set discovery will not be increased
1043 through the process
1050 through the process
1044
1051
1045 * devel.discovery.grow-sample.dynamic=True
1052 * devel.discovery.grow-sample.dynamic=True
1046
1053
1047 When discovery.grow-sample.dynamic is True, the default, the sample size is
1054 When discovery.grow-sample.dynamic is True, the default, the sample size is
1048 adapted to the shape of the undecided set (it is set to the max of:
1055 adapted to the shape of the undecided set (it is set to the max of:
1049 <target-size>, len(roots(undecided)), len(heads(undecided)
1056 <target-size>, len(roots(undecided)), len(heads(undecided)
1050
1057
1051 * devel.discovery.grow-sample.rate=1.05
1058 * devel.discovery.grow-sample.rate=1.05
1052
1059
1053 the rate at which the sample grow
1060 the rate at which the sample grow
1054
1061
1055 * devel.discovery.randomize=True
1062 * devel.discovery.randomize=True
1056
1063
1057 If andom sampling during discovery are deterministic. It is meant for
1064 If andom sampling during discovery are deterministic. It is meant for
1058 integration tests.
1065 integration tests.
1059
1066
1060 * devel.discovery.sample-size=200
1067 * devel.discovery.sample-size=200
1061
1068
1062 Control the initial size of the discovery sample
1069 Control the initial size of the discovery sample
1063
1070
1064 * devel.discovery.sample-size.initial=100
1071 * devel.discovery.sample-size.initial=100
1065
1072
1066 Control the initial size of the discovery for initial change
1073 Control the initial size of the discovery for initial change
1067 """
1074 """
1068 opts = pycompat.byteskwargs(opts)
1075 opts = pycompat.byteskwargs(opts)
1069 unfi = repo.unfiltered()
1076 unfi = repo.unfiltered()
1070
1077
1071 # setup potential extra filtering
1078 # setup potential extra filtering
1072 local_revs = opts[b"local_as_revs"]
1079 local_revs = opts[b"local_as_revs"]
1073 remote_revs = opts[b"remote_as_revs"]
1080 remote_revs = opts[b"remote_as_revs"]
1074
1081
1075 # make sure tests are repeatable
1082 # make sure tests are repeatable
1076 random.seed(int(opts[b'seed']))
1083 random.seed(int(opts[b'seed']))
1077
1084
1078 if not remote_revs:
1085 if not remote_revs:
1079
1086
1080 remoteurl, branches = urlutil.get_unique_pull_path(
1087 remoteurl, branches = urlutil.get_unique_pull_path(
1081 b'debugdiscovery', repo, ui, remoteurl
1088 b'debugdiscovery', repo, ui, remoteurl
1082 )
1089 )
1083 remote = hg.peer(repo, opts, remoteurl)
1090 remote = hg.peer(repo, opts, remoteurl)
1084 ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(remoteurl))
1091 ui.status(_(b'comparing with %s\n') % urlutil.hidepassword(remoteurl))
1085 else:
1092 else:
1086 branches = (None, [])
1093 branches = (None, [])
1087 remote_filtered_revs = logcmdutil.revrange(
1094 remote_filtered_revs = logcmdutil.revrange(
1088 unfi, [b"not (::(%s))" % remote_revs]
1095 unfi, [b"not (::(%s))" % remote_revs]
1089 )
1096 )
1090 remote_filtered_revs = frozenset(remote_filtered_revs)
1097 remote_filtered_revs = frozenset(remote_filtered_revs)
1091
1098
1092 def remote_func(x):
1099 def remote_func(x):
1093 return remote_filtered_revs
1100 return remote_filtered_revs
1094
1101
1095 repoview.filtertable[b'debug-discovery-remote-filter'] = remote_func
1102 repoview.filtertable[b'debug-discovery-remote-filter'] = remote_func
1096
1103
1097 remote = repo.peer()
1104 remote = repo.peer()
1098 remote._repo = remote._repo.filtered(b'debug-discovery-remote-filter')
1105 remote._repo = remote._repo.filtered(b'debug-discovery-remote-filter')
1099
1106
1100 if local_revs:
1107 if local_revs:
1101 local_filtered_revs = logcmdutil.revrange(
1108 local_filtered_revs = logcmdutil.revrange(
1102 unfi, [b"not (::(%s))" % local_revs]
1109 unfi, [b"not (::(%s))" % local_revs]
1103 )
1110 )
1104 local_filtered_revs = frozenset(local_filtered_revs)
1111 local_filtered_revs = frozenset(local_filtered_revs)
1105
1112
1106 def local_func(x):
1113 def local_func(x):
1107 return local_filtered_revs
1114 return local_filtered_revs
1108
1115
1109 repoview.filtertable[b'debug-discovery-local-filter'] = local_func
1116 repoview.filtertable[b'debug-discovery-local-filter'] = local_func
1110 repo = repo.filtered(b'debug-discovery-local-filter')
1117 repo = repo.filtered(b'debug-discovery-local-filter')
1111
1118
1112 data = {}
1119 data = {}
1113 if opts.get(b'old'):
1120 if opts.get(b'old'):
1114
1121
1115 def doit(pushedrevs, remoteheads, remote=remote):
1122 def doit(pushedrevs, remoteheads, remote=remote):
1116 if not util.safehasattr(remote, b'branches'):
1123 if not util.safehasattr(remote, b'branches'):
1117 # enable in-client legacy support
1124 # enable in-client legacy support
1118 remote = localrepo.locallegacypeer(remote.local())
1125 remote = localrepo.locallegacypeer(remote.local())
1119 common, _in, hds = treediscovery.findcommonincoming(
1126 common, _in, hds = treediscovery.findcommonincoming(
1120 repo, remote, force=True, audit=data
1127 repo, remote, force=True, audit=data
1121 )
1128 )
1122 common = set(common)
1129 common = set(common)
1123 if not opts.get(b'nonheads'):
1130 if not opts.get(b'nonheads'):
1124 ui.writenoi18n(
1131 ui.writenoi18n(
1125 b"unpruned common: %s\n"
1132 b"unpruned common: %s\n"
1126 % b" ".join(sorted(short(n) for n in common))
1133 % b" ".join(sorted(short(n) for n in common))
1127 )
1134 )
1128
1135
1129 clnode = repo.changelog.node
1136 clnode = repo.changelog.node
1130 common = repo.revs(b'heads(::%ln)', common)
1137 common = repo.revs(b'heads(::%ln)', common)
1131 common = {clnode(r) for r in common}
1138 common = {clnode(r) for r in common}
1132 return common, hds
1139 return common, hds
1133
1140
1134 else:
1141 else:
1135
1142
1136 def doit(pushedrevs, remoteheads, remote=remote):
1143 def doit(pushedrevs, remoteheads, remote=remote):
1137 nodes = None
1144 nodes = None
1138 if pushedrevs:
1145 if pushedrevs:
1139 revs = logcmdutil.revrange(repo, pushedrevs)
1146 revs = logcmdutil.revrange(repo, pushedrevs)
1140 nodes = [repo[r].node() for r in revs]
1147 nodes = [repo[r].node() for r in revs]
1141 common, any, hds = setdiscovery.findcommonheads(
1148 common, any, hds = setdiscovery.findcommonheads(
1142 ui, repo, remote, ancestorsof=nodes, audit=data
1149 ui, repo, remote, ancestorsof=nodes, audit=data
1143 )
1150 )
1144 return common, hds
1151 return common, hds
1145
1152
1146 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
1153 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
1147 localrevs = opts[b'rev']
1154 localrevs = opts[b'rev']
1148
1155
1149 fm = ui.formatter(b'debugdiscovery', opts)
1156 fm = ui.formatter(b'debugdiscovery', opts)
1150 if fm.strict_format:
1157 if fm.strict_format:
1151
1158
1152 @contextlib.contextmanager
1159 @contextlib.contextmanager
1153 def may_capture_output():
1160 def may_capture_output():
1154 ui.pushbuffer()
1161 ui.pushbuffer()
1155 yield
1162 yield
1156 data[b'output'] = ui.popbuffer()
1163 data[b'output'] = ui.popbuffer()
1157
1164
1158 else:
1165 else:
1159 may_capture_output = util.nullcontextmanager
1166 may_capture_output = util.nullcontextmanager
1160 with may_capture_output():
1167 with may_capture_output():
1161 with util.timedcm('debug-discovery') as t:
1168 with util.timedcm('debug-discovery') as t:
1162 common, hds = doit(localrevs, remoterevs)
1169 common, hds = doit(localrevs, remoterevs)
1163
1170
1164 # compute all statistics
1171 # compute all statistics
1165 heads_common = set(common)
1172 heads_common = set(common)
1166 heads_remote = set(hds)
1173 heads_remote = set(hds)
1167 heads_local = set(repo.heads())
1174 heads_local = set(repo.heads())
1168 # note: they cannot be a local or remote head that is in common and not
1175 # note: they cannot be a local or remote head that is in common and not
1169 # itself a head of common.
1176 # itself a head of common.
1170 heads_common_local = heads_common & heads_local
1177 heads_common_local = heads_common & heads_local
1171 heads_common_remote = heads_common & heads_remote
1178 heads_common_remote = heads_common & heads_remote
1172 heads_common_both = heads_common & heads_remote & heads_local
1179 heads_common_both = heads_common & heads_remote & heads_local
1173
1180
1174 all = repo.revs(b'all()')
1181 all = repo.revs(b'all()')
1175 common = repo.revs(b'::%ln', common)
1182 common = repo.revs(b'::%ln', common)
1176 roots_common = repo.revs(b'roots(::%ld)', common)
1183 roots_common = repo.revs(b'roots(::%ld)', common)
1177 missing = repo.revs(b'not ::%ld', common)
1184 missing = repo.revs(b'not ::%ld', common)
1178 heads_missing = repo.revs(b'heads(%ld)', missing)
1185 heads_missing = repo.revs(b'heads(%ld)', missing)
1179 roots_missing = repo.revs(b'roots(%ld)', missing)
1186 roots_missing = repo.revs(b'roots(%ld)', missing)
1180 assert len(common) + len(missing) == len(all)
1187 assert len(common) + len(missing) == len(all)
1181
1188
1182 initial_undecided = repo.revs(
1189 initial_undecided = repo.revs(
1183 b'not (::%ln or %ln::)', heads_common_remote, heads_common_local
1190 b'not (::%ln or %ln::)', heads_common_remote, heads_common_local
1184 )
1191 )
1185 heads_initial_undecided = repo.revs(b'heads(%ld)', initial_undecided)
1192 heads_initial_undecided = repo.revs(b'heads(%ld)', initial_undecided)
1186 roots_initial_undecided = repo.revs(b'roots(%ld)', initial_undecided)
1193 roots_initial_undecided = repo.revs(b'roots(%ld)', initial_undecided)
1187 common_initial_undecided = initial_undecided & common
1194 common_initial_undecided = initial_undecided & common
1188 missing_initial_undecided = initial_undecided & missing
1195 missing_initial_undecided = initial_undecided & missing
1189
1196
1190 data[b'elapsed'] = t.elapsed
1197 data[b'elapsed'] = t.elapsed
1191 data[b'nb-common-heads'] = len(heads_common)
1198 data[b'nb-common-heads'] = len(heads_common)
1192 data[b'nb-common-heads-local'] = len(heads_common_local)
1199 data[b'nb-common-heads-local'] = len(heads_common_local)
1193 data[b'nb-common-heads-remote'] = len(heads_common_remote)
1200 data[b'nb-common-heads-remote'] = len(heads_common_remote)
1194 data[b'nb-common-heads-both'] = len(heads_common_both)
1201 data[b'nb-common-heads-both'] = len(heads_common_both)
1195 data[b'nb-common-roots'] = len(roots_common)
1202 data[b'nb-common-roots'] = len(roots_common)
1196 data[b'nb-head-local'] = len(heads_local)
1203 data[b'nb-head-local'] = len(heads_local)
1197 data[b'nb-head-local-missing'] = len(heads_local) - len(heads_common_local)
1204 data[b'nb-head-local-missing'] = len(heads_local) - len(heads_common_local)
1198 data[b'nb-head-remote'] = len(heads_remote)
1205 data[b'nb-head-remote'] = len(heads_remote)
1199 data[b'nb-head-remote-unknown'] = len(heads_remote) - len(
1206 data[b'nb-head-remote-unknown'] = len(heads_remote) - len(
1200 heads_common_remote
1207 heads_common_remote
1201 )
1208 )
1202 data[b'nb-revs'] = len(all)
1209 data[b'nb-revs'] = len(all)
1203 data[b'nb-revs-common'] = len(common)
1210 data[b'nb-revs-common'] = len(common)
1204 data[b'nb-revs-missing'] = len(missing)
1211 data[b'nb-revs-missing'] = len(missing)
1205 data[b'nb-missing-heads'] = len(heads_missing)
1212 data[b'nb-missing-heads'] = len(heads_missing)
1206 data[b'nb-missing-roots'] = len(roots_missing)
1213 data[b'nb-missing-roots'] = len(roots_missing)
1207 data[b'nb-ini_und'] = len(initial_undecided)
1214 data[b'nb-ini_und'] = len(initial_undecided)
1208 data[b'nb-ini_und-heads'] = len(heads_initial_undecided)
1215 data[b'nb-ini_und-heads'] = len(heads_initial_undecided)
1209 data[b'nb-ini_und-roots'] = len(roots_initial_undecided)
1216 data[b'nb-ini_und-roots'] = len(roots_initial_undecided)
1210 data[b'nb-ini_und-common'] = len(common_initial_undecided)
1217 data[b'nb-ini_und-common'] = len(common_initial_undecided)
1211 data[b'nb-ini_und-missing'] = len(missing_initial_undecided)
1218 data[b'nb-ini_und-missing'] = len(missing_initial_undecided)
1212
1219
1213 fm.startitem()
1220 fm.startitem()
1214 fm.data(**pycompat.strkwargs(data))
1221 fm.data(**pycompat.strkwargs(data))
1215 # display discovery summary
1222 # display discovery summary
1216 fm.plain(b"elapsed time: %(elapsed)f seconds\n" % data)
1223 fm.plain(b"elapsed time: %(elapsed)f seconds\n" % data)
1217 fm.plain(b"round-trips: %(total-roundtrips)9d\n" % data)
1224 fm.plain(b"round-trips: %(total-roundtrips)9d\n" % data)
1218 fm.plain(b"heads summary:\n")
1225 fm.plain(b"heads summary:\n")
1219 fm.plain(b" total common heads: %(nb-common-heads)9d\n" % data)
1226 fm.plain(b" total common heads: %(nb-common-heads)9d\n" % data)
1220 fm.plain(b" also local heads: %(nb-common-heads-local)9d\n" % data)
1227 fm.plain(b" also local heads: %(nb-common-heads-local)9d\n" % data)
1221 fm.plain(b" also remote heads: %(nb-common-heads-remote)9d\n" % data)
1228 fm.plain(b" also remote heads: %(nb-common-heads-remote)9d\n" % data)
1222 fm.plain(b" both: %(nb-common-heads-both)9d\n" % data)
1229 fm.plain(b" both: %(nb-common-heads-both)9d\n" % data)
1223 fm.plain(b" local heads: %(nb-head-local)9d\n" % data)
1230 fm.plain(b" local heads: %(nb-head-local)9d\n" % data)
1224 fm.plain(b" common: %(nb-common-heads-local)9d\n" % data)
1231 fm.plain(b" common: %(nb-common-heads-local)9d\n" % data)
1225 fm.plain(b" missing: %(nb-head-local-missing)9d\n" % data)
1232 fm.plain(b" missing: %(nb-head-local-missing)9d\n" % data)
1226 fm.plain(b" remote heads: %(nb-head-remote)9d\n" % data)
1233 fm.plain(b" remote heads: %(nb-head-remote)9d\n" % data)
1227 fm.plain(b" common: %(nb-common-heads-remote)9d\n" % data)
1234 fm.plain(b" common: %(nb-common-heads-remote)9d\n" % data)
1228 fm.plain(b" unknown: %(nb-head-remote-unknown)9d\n" % data)
1235 fm.plain(b" unknown: %(nb-head-remote-unknown)9d\n" % data)
1229 fm.plain(b"local changesets: %(nb-revs)9d\n" % data)
1236 fm.plain(b"local changesets: %(nb-revs)9d\n" % data)
1230 fm.plain(b" common: %(nb-revs-common)9d\n" % data)
1237 fm.plain(b" common: %(nb-revs-common)9d\n" % data)
1231 fm.plain(b" heads: %(nb-common-heads)9d\n" % data)
1238 fm.plain(b" heads: %(nb-common-heads)9d\n" % data)
1232 fm.plain(b" roots: %(nb-common-roots)9d\n" % data)
1239 fm.plain(b" roots: %(nb-common-roots)9d\n" % data)
1233 fm.plain(b" missing: %(nb-revs-missing)9d\n" % data)
1240 fm.plain(b" missing: %(nb-revs-missing)9d\n" % data)
1234 fm.plain(b" heads: %(nb-missing-heads)9d\n" % data)
1241 fm.plain(b" heads: %(nb-missing-heads)9d\n" % data)
1235 fm.plain(b" roots: %(nb-missing-roots)9d\n" % data)
1242 fm.plain(b" roots: %(nb-missing-roots)9d\n" % data)
1236 fm.plain(b" first undecided set: %(nb-ini_und)9d\n" % data)
1243 fm.plain(b" first undecided set: %(nb-ini_und)9d\n" % data)
1237 fm.plain(b" heads: %(nb-ini_und-heads)9d\n" % data)
1244 fm.plain(b" heads: %(nb-ini_und-heads)9d\n" % data)
1238 fm.plain(b" roots: %(nb-ini_und-roots)9d\n" % data)
1245 fm.plain(b" roots: %(nb-ini_und-roots)9d\n" % data)
1239 fm.plain(b" common: %(nb-ini_und-common)9d\n" % data)
1246 fm.plain(b" common: %(nb-ini_und-common)9d\n" % data)
1240 fm.plain(b" missing: %(nb-ini_und-missing)9d\n" % data)
1247 fm.plain(b" missing: %(nb-ini_und-missing)9d\n" % data)
1241
1248
1242 if ui.verbose:
1249 if ui.verbose:
1243 fm.plain(
1250 fm.plain(
1244 b"common heads: %s\n"
1251 b"common heads: %s\n"
1245 % b" ".join(sorted(short(n) for n in heads_common))
1252 % b" ".join(sorted(short(n) for n in heads_common))
1246 )
1253 )
1247 fm.end()
1254 fm.end()
1248
1255
1249
1256
1250 _chunksize = 4 << 10
1257 _chunksize = 4 << 10
1251
1258
1252
1259
1253 @command(
1260 @command(
1254 b'debugdownload',
1261 b'debugdownload',
1255 [
1262 [
1256 (b'o', b'output', b'', _(b'path')),
1263 (b'o', b'output', b'', _(b'path')),
1257 ],
1264 ],
1258 optionalrepo=True,
1265 optionalrepo=True,
1259 )
1266 )
1260 def debugdownload(ui, repo, url, output=None, **opts):
1267 def debugdownload(ui, repo, url, output=None, **opts):
1261 """download a resource using Mercurial logic and config"""
1268 """download a resource using Mercurial logic and config"""
1262 fh = urlmod.open(ui, url, output)
1269 fh = urlmod.open(ui, url, output)
1263
1270
1264 dest = ui
1271 dest = ui
1265 if output:
1272 if output:
1266 dest = open(output, b"wb", _chunksize)
1273 dest = open(output, b"wb", _chunksize)
1267 try:
1274 try:
1268 data = fh.read(_chunksize)
1275 data = fh.read(_chunksize)
1269 while data:
1276 while data:
1270 dest.write(data)
1277 dest.write(data)
1271 data = fh.read(_chunksize)
1278 data = fh.read(_chunksize)
1272 finally:
1279 finally:
1273 if output:
1280 if output:
1274 dest.close()
1281 dest.close()
1275
1282
1276
1283
1277 @command(b'debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
1284 @command(b'debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
1278 def debugextensions(ui, repo, **opts):
1285 def debugextensions(ui, repo, **opts):
1279 '''show information about active extensions'''
1286 '''show information about active extensions'''
1280 opts = pycompat.byteskwargs(opts)
1287 opts = pycompat.byteskwargs(opts)
1281 exts = extensions.extensions(ui)
1288 exts = extensions.extensions(ui)
1282 hgver = util.version()
1289 hgver = util.version()
1283 fm = ui.formatter(b'debugextensions', opts)
1290 fm = ui.formatter(b'debugextensions', opts)
1284 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
1291 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
1285 isinternal = extensions.ismoduleinternal(extmod)
1292 isinternal = extensions.ismoduleinternal(extmod)
1286 extsource = None
1293 extsource = None
1287
1294
1288 if util.safehasattr(extmod, '__file__'):
1295 if util.safehasattr(extmod, '__file__'):
1289 extsource = pycompat.fsencode(extmod.__file__)
1296 extsource = pycompat.fsencode(extmod.__file__)
1290 elif getattr(sys, 'oxidized', False):
1297 elif getattr(sys, 'oxidized', False):
1291 extsource = pycompat.sysexecutable
1298 extsource = pycompat.sysexecutable
1292 if isinternal:
1299 if isinternal:
1293 exttestedwith = [] # never expose magic string to users
1300 exttestedwith = [] # never expose magic string to users
1294 else:
1301 else:
1295 exttestedwith = getattr(extmod, 'testedwith', b'').split()
1302 exttestedwith = getattr(extmod, 'testedwith', b'').split()
1296 extbuglink = getattr(extmod, 'buglink', None)
1303 extbuglink = getattr(extmod, 'buglink', None)
1297
1304
1298 fm.startitem()
1305 fm.startitem()
1299
1306
1300 if ui.quiet or ui.verbose:
1307 if ui.quiet or ui.verbose:
1301 fm.write(b'name', b'%s\n', extname)
1308 fm.write(b'name', b'%s\n', extname)
1302 else:
1309 else:
1303 fm.write(b'name', b'%s', extname)
1310 fm.write(b'name', b'%s', extname)
1304 if isinternal or hgver in exttestedwith:
1311 if isinternal or hgver in exttestedwith:
1305 fm.plain(b'\n')
1312 fm.plain(b'\n')
1306 elif not exttestedwith:
1313 elif not exttestedwith:
1307 fm.plain(_(b' (untested!)\n'))
1314 fm.plain(_(b' (untested!)\n'))
1308 else:
1315 else:
1309 lasttestedversion = exttestedwith[-1]
1316 lasttestedversion = exttestedwith[-1]
1310 fm.plain(b' (%s!)\n' % lasttestedversion)
1317 fm.plain(b' (%s!)\n' % lasttestedversion)
1311
1318
1312 fm.condwrite(
1319 fm.condwrite(
1313 ui.verbose and extsource,
1320 ui.verbose and extsource,
1314 b'source',
1321 b'source',
1315 _(b' location: %s\n'),
1322 _(b' location: %s\n'),
1316 extsource or b"",
1323 extsource or b"",
1317 )
1324 )
1318
1325
1319 if ui.verbose:
1326 if ui.verbose:
1320 fm.plain(_(b' bundled: %s\n') % [b'no', b'yes'][isinternal])
1327 fm.plain(_(b' bundled: %s\n') % [b'no', b'yes'][isinternal])
1321 fm.data(bundled=isinternal)
1328 fm.data(bundled=isinternal)
1322
1329
1323 fm.condwrite(
1330 fm.condwrite(
1324 ui.verbose and exttestedwith,
1331 ui.verbose and exttestedwith,
1325 b'testedwith',
1332 b'testedwith',
1326 _(b' tested with: %s\n'),
1333 _(b' tested with: %s\n'),
1327 fm.formatlist(exttestedwith, name=b'ver'),
1334 fm.formatlist(exttestedwith, name=b'ver'),
1328 )
1335 )
1329
1336
1330 fm.condwrite(
1337 fm.condwrite(
1331 ui.verbose and extbuglink,
1338 ui.verbose and extbuglink,
1332 b'buglink',
1339 b'buglink',
1333 _(b' bug reporting: %s\n'),
1340 _(b' bug reporting: %s\n'),
1334 extbuglink or b"",
1341 extbuglink or b"",
1335 )
1342 )
1336
1343
1337 fm.end()
1344 fm.end()
1338
1345
1339
1346
1340 @command(
1347 @command(
1341 b'debugfileset',
1348 b'debugfileset',
1342 [
1349 [
1343 (
1350 (
1344 b'r',
1351 b'r',
1345 b'rev',
1352 b'rev',
1346 b'',
1353 b'',
1347 _(b'apply the filespec on this revision'),
1354 _(b'apply the filespec on this revision'),
1348 _(b'REV'),
1355 _(b'REV'),
1349 ),
1356 ),
1350 (
1357 (
1351 b'',
1358 b'',
1352 b'all-files',
1359 b'all-files',
1353 False,
1360 False,
1354 _(b'test files from all revisions and working directory'),
1361 _(b'test files from all revisions and working directory'),
1355 ),
1362 ),
1356 (
1363 (
1357 b's',
1364 b's',
1358 b'show-matcher',
1365 b'show-matcher',
1359 None,
1366 None,
1360 _(b'print internal representation of matcher'),
1367 _(b'print internal representation of matcher'),
1361 ),
1368 ),
1362 (
1369 (
1363 b'p',
1370 b'p',
1364 b'show-stage',
1371 b'show-stage',
1365 [],
1372 [],
1366 _(b'print parsed tree at the given stage'),
1373 _(b'print parsed tree at the given stage'),
1367 _(b'NAME'),
1374 _(b'NAME'),
1368 ),
1375 ),
1369 ],
1376 ],
1370 _(b'[-r REV] [--all-files] [OPTION]... FILESPEC'),
1377 _(b'[-r REV] [--all-files] [OPTION]... FILESPEC'),
1371 )
1378 )
1372 def debugfileset(ui, repo, expr, **opts):
1379 def debugfileset(ui, repo, expr, **opts):
1373 '''parse and apply a fileset specification'''
1380 '''parse and apply a fileset specification'''
1374 from . import fileset
1381 from . import fileset
1375
1382
1376 fileset.symbols # force import of fileset so we have predicates to optimize
1383 fileset.symbols # force import of fileset so we have predicates to optimize
1377 opts = pycompat.byteskwargs(opts)
1384 opts = pycompat.byteskwargs(opts)
1378 ctx = logcmdutil.revsingle(repo, opts.get(b'rev'), None)
1385 ctx = logcmdutil.revsingle(repo, opts.get(b'rev'), None)
1379
1386
1380 stages = [
1387 stages = [
1381 (b'parsed', pycompat.identity),
1388 (b'parsed', pycompat.identity),
1382 (b'analyzed', filesetlang.analyze),
1389 (b'analyzed', filesetlang.analyze),
1383 (b'optimized', filesetlang.optimize),
1390 (b'optimized', filesetlang.optimize),
1384 ]
1391 ]
1385 stagenames = {n for n, f in stages}
1392 stagenames = {n for n, f in stages}
1386
1393
1387 showalways = set()
1394 showalways = set()
1388 if ui.verbose and not opts[b'show_stage']:
1395 if ui.verbose and not opts[b'show_stage']:
1389 # show parsed tree by --verbose (deprecated)
1396 # show parsed tree by --verbose (deprecated)
1390 showalways.add(b'parsed')
1397 showalways.add(b'parsed')
1391 if opts[b'show_stage'] == [b'all']:
1398 if opts[b'show_stage'] == [b'all']:
1392 showalways.update(stagenames)
1399 showalways.update(stagenames)
1393 else:
1400 else:
1394 for n in opts[b'show_stage']:
1401 for n in opts[b'show_stage']:
1395 if n not in stagenames:
1402 if n not in stagenames:
1396 raise error.Abort(_(b'invalid stage name: %s') % n)
1403 raise error.Abort(_(b'invalid stage name: %s') % n)
1397 showalways.update(opts[b'show_stage'])
1404 showalways.update(opts[b'show_stage'])
1398
1405
1399 tree = filesetlang.parse(expr)
1406 tree = filesetlang.parse(expr)
1400 for n, f in stages:
1407 for n, f in stages:
1401 tree = f(tree)
1408 tree = f(tree)
1402 if n in showalways:
1409 if n in showalways:
1403 if opts[b'show_stage'] or n != b'parsed':
1410 if opts[b'show_stage'] or n != b'parsed':
1404 ui.write(b"* %s:\n" % n)
1411 ui.write(b"* %s:\n" % n)
1405 ui.write(filesetlang.prettyformat(tree), b"\n")
1412 ui.write(filesetlang.prettyformat(tree), b"\n")
1406
1413
1407 files = set()
1414 files = set()
1408 if opts[b'all_files']:
1415 if opts[b'all_files']:
1409 for r in repo:
1416 for r in repo:
1410 c = repo[r]
1417 c = repo[r]
1411 files.update(c.files())
1418 files.update(c.files())
1412 files.update(c.substate)
1419 files.update(c.substate)
1413 if opts[b'all_files'] or ctx.rev() is None:
1420 if opts[b'all_files'] or ctx.rev() is None:
1414 wctx = repo[None]
1421 wctx = repo[None]
1415 files.update(
1422 files.update(
1416 repo.dirstate.walk(
1423 repo.dirstate.walk(
1417 scmutil.matchall(repo),
1424 scmutil.matchall(repo),
1418 subrepos=list(wctx.substate),
1425 subrepos=list(wctx.substate),
1419 unknown=True,
1426 unknown=True,
1420 ignored=True,
1427 ignored=True,
1421 )
1428 )
1422 )
1429 )
1423 files.update(wctx.substate)
1430 files.update(wctx.substate)
1424 else:
1431 else:
1425 files.update(ctx.files())
1432 files.update(ctx.files())
1426 files.update(ctx.substate)
1433 files.update(ctx.substate)
1427
1434
1428 m = ctx.matchfileset(repo.getcwd(), expr)
1435 m = ctx.matchfileset(repo.getcwd(), expr)
1429 if opts[b'show_matcher'] or (opts[b'show_matcher'] is None and ui.verbose):
1436 if opts[b'show_matcher'] or (opts[b'show_matcher'] is None and ui.verbose):
1430 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
1437 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
1431 for f in sorted(files):
1438 for f in sorted(files):
1432 if not m(f):
1439 if not m(f):
1433 continue
1440 continue
1434 ui.write(b"%s\n" % f)
1441 ui.write(b"%s\n" % f)
1435
1442
1436
1443
1437 @command(
1444 @command(
1438 b"debug-repair-issue6528",
1445 b"debug-repair-issue6528",
1439 [
1446 [
1440 (
1447 (
1441 b'',
1448 b'',
1442 b'to-report',
1449 b'to-report',
1443 b'',
1450 b'',
1444 _(b'build a report of affected revisions to this file'),
1451 _(b'build a report of affected revisions to this file'),
1445 _(b'FILE'),
1452 _(b'FILE'),
1446 ),
1453 ),
1447 (
1454 (
1448 b'',
1455 b'',
1449 b'from-report',
1456 b'from-report',
1450 b'',
1457 b'',
1451 _(b'repair revisions listed in this report file'),
1458 _(b'repair revisions listed in this report file'),
1452 _(b'FILE'),
1459 _(b'FILE'),
1453 ),
1460 ),
1454 (
1461 (
1455 b'',
1462 b'',
1456 b'paranoid',
1463 b'paranoid',
1457 False,
1464 False,
1458 _(b'check that both detection methods do the same thing'),
1465 _(b'check that both detection methods do the same thing'),
1459 ),
1466 ),
1460 ]
1467 ]
1461 + cmdutil.dryrunopts,
1468 + cmdutil.dryrunopts,
1462 )
1469 )
1463 def debug_repair_issue6528(ui, repo, **opts):
1470 def debug_repair_issue6528(ui, repo, **opts):
1464 """find affected revisions and repair them. See issue6528 for more details.
1471 """find affected revisions and repair them. See issue6528 for more details.
1465
1472
1466 The `--to-report` and `--from-report` flags allow you to cache and reuse the
1473 The `--to-report` and `--from-report` flags allow you to cache and reuse the
1467 computation of affected revisions for a given repository across clones.
1474 computation of affected revisions for a given repository across clones.
1468 The report format is line-based (with empty lines ignored):
1475 The report format is line-based (with empty lines ignored):
1469
1476
1470 ```
1477 ```
1471 <ascii-hex of the affected revision>,... <unencoded filelog index filename>
1478 <ascii-hex of the affected revision>,... <unencoded filelog index filename>
1472 ```
1479 ```
1473
1480
1474 There can be multiple broken revisions per filelog, they are separated by
1481 There can be multiple broken revisions per filelog, they are separated by
1475 a comma with no spaces. The only space is between the revision(s) and the
1482 a comma with no spaces. The only space is between the revision(s) and the
1476 filename.
1483 filename.
1477
1484
1478 Note that this does *not* mean that this repairs future affected revisions,
1485 Note that this does *not* mean that this repairs future affected revisions,
1479 that needs a separate fix at the exchange level that was introduced in
1486 that needs a separate fix at the exchange level that was introduced in
1480 Mercurial 5.9.1.
1487 Mercurial 5.9.1.
1481
1488
1482 There is a `--paranoid` flag to test that the fast implementation is correct
1489 There is a `--paranoid` flag to test that the fast implementation is correct
1483 by checking it against the slow implementation. Since this matter is quite
1490 by checking it against the slow implementation. Since this matter is quite
1484 urgent and testing every edge-case is probably quite costly, we use this
1491 urgent and testing every edge-case is probably quite costly, we use this
1485 method to test on large repositories as a fuzzing method of sorts.
1492 method to test on large repositories as a fuzzing method of sorts.
1486 """
1493 """
1487 cmdutil.check_incompatible_arguments(
1494 cmdutil.check_incompatible_arguments(
1488 opts, 'to_report', ['from_report', 'dry_run']
1495 opts, 'to_report', ['from_report', 'dry_run']
1489 )
1496 )
1490 dry_run = opts.get('dry_run')
1497 dry_run = opts.get('dry_run')
1491 to_report = opts.get('to_report')
1498 to_report = opts.get('to_report')
1492 from_report = opts.get('from_report')
1499 from_report = opts.get('from_report')
1493 paranoid = opts.get('paranoid')
1500 paranoid = opts.get('paranoid')
1494 # TODO maybe add filelog pattern and revision pattern parameters to help
1501 # TODO maybe add filelog pattern and revision pattern parameters to help
1495 # narrow down the search for users that know what they're looking for?
1502 # narrow down the search for users that know what they're looking for?
1496
1503
1497 if requirements.REVLOGV1_REQUIREMENT not in repo.requirements:
1504 if requirements.REVLOGV1_REQUIREMENT not in repo.requirements:
1498 msg = b"can only repair revlogv1 repositories, v2 is not affected"
1505 msg = b"can only repair revlogv1 repositories, v2 is not affected"
1499 raise error.Abort(_(msg))
1506 raise error.Abort(_(msg))
1500
1507
1501 rewrite.repair_issue6528(
1508 rewrite.repair_issue6528(
1502 ui,
1509 ui,
1503 repo,
1510 repo,
1504 dry_run=dry_run,
1511 dry_run=dry_run,
1505 to_report=to_report,
1512 to_report=to_report,
1506 from_report=from_report,
1513 from_report=from_report,
1507 paranoid=paranoid,
1514 paranoid=paranoid,
1508 )
1515 )
1509
1516
1510
1517
1511 @command(b'debugformat', [] + cmdutil.formatteropts)
1518 @command(b'debugformat', [] + cmdutil.formatteropts)
1512 def debugformat(ui, repo, **opts):
1519 def debugformat(ui, repo, **opts):
1513 """display format information about the current repository
1520 """display format information about the current repository
1514
1521
1515 Use --verbose to get extra information about current config value and
1522 Use --verbose to get extra information about current config value and
1516 Mercurial default."""
1523 Mercurial default."""
1517 opts = pycompat.byteskwargs(opts)
1524 opts = pycompat.byteskwargs(opts)
1518 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
1525 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
1519 maxvariantlength = max(len(b'format-variant'), maxvariantlength)
1526 maxvariantlength = max(len(b'format-variant'), maxvariantlength)
1520
1527
1521 def makeformatname(name):
1528 def makeformatname(name):
1522 return b'%s:' + (b' ' * (maxvariantlength - len(name)))
1529 return b'%s:' + (b' ' * (maxvariantlength - len(name)))
1523
1530
1524 fm = ui.formatter(b'debugformat', opts)
1531 fm = ui.formatter(b'debugformat', opts)
1525 if fm.isplain():
1532 if fm.isplain():
1526
1533
1527 def formatvalue(value):
1534 def formatvalue(value):
1528 if util.safehasattr(value, b'startswith'):
1535 if util.safehasattr(value, b'startswith'):
1529 return value
1536 return value
1530 if value:
1537 if value:
1531 return b'yes'
1538 return b'yes'
1532 else:
1539 else:
1533 return b'no'
1540 return b'no'
1534
1541
1535 else:
1542 else:
1536 formatvalue = pycompat.identity
1543 formatvalue = pycompat.identity
1537
1544
1538 fm.plain(b'format-variant')
1545 fm.plain(b'format-variant')
1539 fm.plain(b' ' * (maxvariantlength - len(b'format-variant')))
1546 fm.plain(b' ' * (maxvariantlength - len(b'format-variant')))
1540 fm.plain(b' repo')
1547 fm.plain(b' repo')
1541 if ui.verbose:
1548 if ui.verbose:
1542 fm.plain(b' config default')
1549 fm.plain(b' config default')
1543 fm.plain(b'\n')
1550 fm.plain(b'\n')
1544 for fv in upgrade.allformatvariant:
1551 for fv in upgrade.allformatvariant:
1545 fm.startitem()
1552 fm.startitem()
1546 repovalue = fv.fromrepo(repo)
1553 repovalue = fv.fromrepo(repo)
1547 configvalue = fv.fromconfig(repo)
1554 configvalue = fv.fromconfig(repo)
1548
1555
1549 if repovalue != configvalue:
1556 if repovalue != configvalue:
1550 namelabel = b'formatvariant.name.mismatchconfig'
1557 namelabel = b'formatvariant.name.mismatchconfig'
1551 repolabel = b'formatvariant.repo.mismatchconfig'
1558 repolabel = b'formatvariant.repo.mismatchconfig'
1552 elif repovalue != fv.default:
1559 elif repovalue != fv.default:
1553 namelabel = b'formatvariant.name.mismatchdefault'
1560 namelabel = b'formatvariant.name.mismatchdefault'
1554 repolabel = b'formatvariant.repo.mismatchdefault'
1561 repolabel = b'formatvariant.repo.mismatchdefault'
1555 else:
1562 else:
1556 namelabel = b'formatvariant.name.uptodate'
1563 namelabel = b'formatvariant.name.uptodate'
1557 repolabel = b'formatvariant.repo.uptodate'
1564 repolabel = b'formatvariant.repo.uptodate'
1558
1565
1559 fm.write(b'name', makeformatname(fv.name), fv.name, label=namelabel)
1566 fm.write(b'name', makeformatname(fv.name), fv.name, label=namelabel)
1560 fm.write(b'repo', b' %3s', formatvalue(repovalue), label=repolabel)
1567 fm.write(b'repo', b' %3s', formatvalue(repovalue), label=repolabel)
1561 if fv.default != configvalue:
1568 if fv.default != configvalue:
1562 configlabel = b'formatvariant.config.special'
1569 configlabel = b'formatvariant.config.special'
1563 else:
1570 else:
1564 configlabel = b'formatvariant.config.default'
1571 configlabel = b'formatvariant.config.default'
1565 fm.condwrite(
1572 fm.condwrite(
1566 ui.verbose,
1573 ui.verbose,
1567 b'config',
1574 b'config',
1568 b' %6s',
1575 b' %6s',
1569 formatvalue(configvalue),
1576 formatvalue(configvalue),
1570 label=configlabel,
1577 label=configlabel,
1571 )
1578 )
1572 fm.condwrite(
1579 fm.condwrite(
1573 ui.verbose,
1580 ui.verbose,
1574 b'default',
1581 b'default',
1575 b' %7s',
1582 b' %7s',
1576 formatvalue(fv.default),
1583 formatvalue(fv.default),
1577 label=b'formatvariant.default',
1584 label=b'formatvariant.default',
1578 )
1585 )
1579 fm.plain(b'\n')
1586 fm.plain(b'\n')
1580 fm.end()
1587 fm.end()
1581
1588
1582
1589
1583 @command(b'debugfsinfo', [], _(b'[PATH]'), norepo=True)
1590 @command(b'debugfsinfo', [], _(b'[PATH]'), norepo=True)
1584 def debugfsinfo(ui, path=b"."):
1591 def debugfsinfo(ui, path=b"."):
1585 """show information detected about current filesystem"""
1592 """show information detected about current filesystem"""
1586 ui.writenoi18n(b'path: %s\n' % path)
1593 ui.writenoi18n(b'path: %s\n' % path)
1587 ui.writenoi18n(
1594 ui.writenoi18n(
1588 b'mounted on: %s\n' % (util.getfsmountpoint(path) or b'(unknown)')
1595 b'mounted on: %s\n' % (util.getfsmountpoint(path) or b'(unknown)')
1589 )
1596 )
1590 ui.writenoi18n(b'exec: %s\n' % (util.checkexec(path) and b'yes' or b'no'))
1597 ui.writenoi18n(b'exec: %s\n' % (util.checkexec(path) and b'yes' or b'no'))
1591 ui.writenoi18n(b'fstype: %s\n' % (util.getfstype(path) or b'(unknown)'))
1598 ui.writenoi18n(b'fstype: %s\n' % (util.getfstype(path) or b'(unknown)'))
1592 ui.writenoi18n(
1599 ui.writenoi18n(
1593 b'symlink: %s\n' % (util.checklink(path) and b'yes' or b'no')
1600 b'symlink: %s\n' % (util.checklink(path) and b'yes' or b'no')
1594 )
1601 )
1595 ui.writenoi18n(
1602 ui.writenoi18n(
1596 b'hardlink: %s\n' % (util.checknlink(path) and b'yes' or b'no')
1603 b'hardlink: %s\n' % (util.checknlink(path) and b'yes' or b'no')
1597 )
1604 )
1598 casesensitive = b'(unknown)'
1605 casesensitive = b'(unknown)'
1599 try:
1606 try:
1600 with pycompat.namedtempfile(prefix=b'.debugfsinfo', dir=path) as f:
1607 with pycompat.namedtempfile(prefix=b'.debugfsinfo', dir=path) as f:
1601 casesensitive = util.fscasesensitive(f.name) and b'yes' or b'no'
1608 casesensitive = util.fscasesensitive(f.name) and b'yes' or b'no'
1602 except OSError:
1609 except OSError:
1603 pass
1610 pass
1604 ui.writenoi18n(b'case-sensitive: %s\n' % casesensitive)
1611 ui.writenoi18n(b'case-sensitive: %s\n' % casesensitive)
1605
1612
1606
1613
1607 @command(
1614 @command(
1608 b'debuggetbundle',
1615 b'debuggetbundle',
1609 [
1616 [
1610 (b'H', b'head', [], _(b'id of head node'), _(b'ID')),
1617 (b'H', b'head', [], _(b'id of head node'), _(b'ID')),
1611 (b'C', b'common', [], _(b'id of common node'), _(b'ID')),
1618 (b'C', b'common', [], _(b'id of common node'), _(b'ID')),
1612 (
1619 (
1613 b't',
1620 b't',
1614 b'type',
1621 b'type',
1615 b'bzip2',
1622 b'bzip2',
1616 _(b'bundle compression type to use'),
1623 _(b'bundle compression type to use'),
1617 _(b'TYPE'),
1624 _(b'TYPE'),
1618 ),
1625 ),
1619 ],
1626 ],
1620 _(b'REPO FILE [-H|-C ID]...'),
1627 _(b'REPO FILE [-H|-C ID]...'),
1621 norepo=True,
1628 norepo=True,
1622 )
1629 )
1623 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1630 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1624 """retrieves a bundle from a repo
1631 """retrieves a bundle from a repo
1625
1632
1626 Every ID must be a full-length hex node id string. Saves the bundle to the
1633 Every ID must be a full-length hex node id string. Saves the bundle to the
1627 given file.
1634 given file.
1628 """
1635 """
1629 opts = pycompat.byteskwargs(opts)
1636 opts = pycompat.byteskwargs(opts)
1630 repo = hg.peer(ui, opts, repopath)
1637 repo = hg.peer(ui, opts, repopath)
1631 if not repo.capable(b'getbundle'):
1638 if not repo.capable(b'getbundle'):
1632 raise error.Abort(b"getbundle() not supported by target repository")
1639 raise error.Abort(b"getbundle() not supported by target repository")
1633 args = {}
1640 args = {}
1634 if common:
1641 if common:
1635 args['common'] = [bin(s) for s in common]
1642 args['common'] = [bin(s) for s in common]
1636 if head:
1643 if head:
1637 args['heads'] = [bin(s) for s in head]
1644 args['heads'] = [bin(s) for s in head]
1638 # TODO: get desired bundlecaps from command line.
1645 # TODO: get desired bundlecaps from command line.
1639 args['bundlecaps'] = None
1646 args['bundlecaps'] = None
1640 bundle = repo.getbundle(b'debug', **args)
1647 bundle = repo.getbundle(b'debug', **args)
1641
1648
1642 bundletype = opts.get(b'type', b'bzip2').lower()
1649 bundletype = opts.get(b'type', b'bzip2').lower()
1643 btypes = {
1650 btypes = {
1644 b'none': b'HG10UN',
1651 b'none': b'HG10UN',
1645 b'bzip2': b'HG10BZ',
1652 b'bzip2': b'HG10BZ',
1646 b'gzip': b'HG10GZ',
1653 b'gzip': b'HG10GZ',
1647 b'bundle2': b'HG20',
1654 b'bundle2': b'HG20',
1648 }
1655 }
1649 bundletype = btypes.get(bundletype)
1656 bundletype = btypes.get(bundletype)
1650 if bundletype not in bundle2.bundletypes:
1657 if bundletype not in bundle2.bundletypes:
1651 raise error.Abort(_(b'unknown bundle type specified with --type'))
1658 raise error.Abort(_(b'unknown bundle type specified with --type'))
1652 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1659 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
1653
1660
1654
1661
1655 @command(b'debugignore', [], b'[FILE]')
1662 @command(b'debugignore', [], b'[FILE]')
1656 def debugignore(ui, repo, *files, **opts):
1663 def debugignore(ui, repo, *files, **opts):
1657 """display the combined ignore pattern and information about ignored files
1664 """display the combined ignore pattern and information about ignored files
1658
1665
1659 With no argument display the combined ignore pattern.
1666 With no argument display the combined ignore pattern.
1660
1667
1661 Given space separated file names, shows if the given file is ignored and
1668 Given space separated file names, shows if the given file is ignored and
1662 if so, show the ignore rule (file and line number) that matched it.
1669 if so, show the ignore rule (file and line number) that matched it.
1663 """
1670 """
1664 ignore = repo.dirstate._ignore
1671 ignore = repo.dirstate._ignore
1665 if not files:
1672 if not files:
1666 # Show all the patterns
1673 # Show all the patterns
1667 ui.write(b"%s\n" % pycompat.byterepr(ignore))
1674 ui.write(b"%s\n" % pycompat.byterepr(ignore))
1668 else:
1675 else:
1669 m = scmutil.match(repo[None], pats=files)
1676 m = scmutil.match(repo[None], pats=files)
1670 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1677 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
1671 for f in m.files():
1678 for f in m.files():
1672 nf = util.normpath(f)
1679 nf = util.normpath(f)
1673 ignored = None
1680 ignored = None
1674 ignoredata = None
1681 ignoredata = None
1675 if nf != b'.':
1682 if nf != b'.':
1676 if ignore(nf):
1683 if ignore(nf):
1677 ignored = nf
1684 ignored = nf
1678 ignoredata = repo.dirstate._ignorefileandline(nf)
1685 ignoredata = repo.dirstate._ignorefileandline(nf)
1679 else:
1686 else:
1680 for p in pathutil.finddirs(nf):
1687 for p in pathutil.finddirs(nf):
1681 if ignore(p):
1688 if ignore(p):
1682 ignored = p
1689 ignored = p
1683 ignoredata = repo.dirstate._ignorefileandline(p)
1690 ignoredata = repo.dirstate._ignorefileandline(p)
1684 break
1691 break
1685 if ignored:
1692 if ignored:
1686 if ignored == nf:
1693 if ignored == nf:
1687 ui.write(_(b"%s is ignored\n") % uipathfn(f))
1694 ui.write(_(b"%s is ignored\n") % uipathfn(f))
1688 else:
1695 else:
1689 ui.write(
1696 ui.write(
1690 _(
1697 _(
1691 b"%s is ignored because of "
1698 b"%s is ignored because of "
1692 b"containing directory %s\n"
1699 b"containing directory %s\n"
1693 )
1700 )
1694 % (uipathfn(f), ignored)
1701 % (uipathfn(f), ignored)
1695 )
1702 )
1696 ignorefile, lineno, line = ignoredata
1703 ignorefile, lineno, line = ignoredata
1697 ui.write(
1704 ui.write(
1698 _(b"(ignore rule in %s, line %d: '%s')\n")
1705 _(b"(ignore rule in %s, line %d: '%s')\n")
1699 % (ignorefile, lineno, line)
1706 % (ignorefile, lineno, line)
1700 )
1707 )
1701 else:
1708 else:
1702 ui.write(_(b"%s is not ignored\n") % uipathfn(f))
1709 ui.write(_(b"%s is not ignored\n") % uipathfn(f))
1703
1710
1704
1711
1705 @command(
1712 @command(
1706 b'debugindex',
1713 b'debugindex',
1707 cmdutil.debugrevlogopts + cmdutil.formatteropts,
1714 cmdutil.debugrevlogopts + cmdutil.formatteropts,
1708 _(b'-c|-m|FILE'),
1715 _(b'-c|-m|FILE'),
1709 )
1716 )
1710 def debugindex(ui, repo, file_=None, **opts):
1717 def debugindex(ui, repo, file_=None, **opts):
1711 """dump index data for a storage primitive"""
1718 """dump index data for a storage primitive"""
1712 opts = pycompat.byteskwargs(opts)
1719 opts = pycompat.byteskwargs(opts)
1713 store = cmdutil.openstorage(repo, b'debugindex', file_, opts)
1720 store = cmdutil.openstorage(repo, b'debugindex', file_, opts)
1714
1721
1715 if ui.debugflag:
1722 if ui.debugflag:
1716 shortfn = hex
1723 shortfn = hex
1717 else:
1724 else:
1718 shortfn = short
1725 shortfn = short
1719
1726
1720 idlen = 12
1727 idlen = 12
1721 for i in store:
1728 for i in store:
1722 idlen = len(shortfn(store.node(i)))
1729 idlen = len(shortfn(store.node(i)))
1723 break
1730 break
1724
1731
1725 fm = ui.formatter(b'debugindex', opts)
1732 fm = ui.formatter(b'debugindex', opts)
1726 fm.plain(
1733 fm.plain(
1727 b' rev linkrev %s %s p2\n'
1734 b' rev linkrev %s %s p2\n'
1728 % (b'nodeid'.ljust(idlen), b'p1'.ljust(idlen))
1735 % (b'nodeid'.ljust(idlen), b'p1'.ljust(idlen))
1729 )
1736 )
1730
1737
1731 for rev in store:
1738 for rev in store:
1732 node = store.node(rev)
1739 node = store.node(rev)
1733 parents = store.parents(node)
1740 parents = store.parents(node)
1734
1741
1735 fm.startitem()
1742 fm.startitem()
1736 fm.write(b'rev', b'%6d ', rev)
1743 fm.write(b'rev', b'%6d ', rev)
1737 fm.write(b'linkrev', b'%7d ', store.linkrev(rev))
1744 fm.write(b'linkrev', b'%7d ', store.linkrev(rev))
1738 fm.write(b'node', b'%s ', shortfn(node))
1745 fm.write(b'node', b'%s ', shortfn(node))
1739 fm.write(b'p1', b'%s ', shortfn(parents[0]))
1746 fm.write(b'p1', b'%s ', shortfn(parents[0]))
1740 fm.write(b'p2', b'%s', shortfn(parents[1]))
1747 fm.write(b'p2', b'%s', shortfn(parents[1]))
1741 fm.plain(b'\n')
1748 fm.plain(b'\n')
1742
1749
1743 fm.end()
1750 fm.end()
1744
1751
1745
1752
1746 @command(
1753 @command(
1747 b'debugindexdot',
1754 b'debugindexdot',
1748 cmdutil.debugrevlogopts,
1755 cmdutil.debugrevlogopts,
1749 _(b'-c|-m|FILE'),
1756 _(b'-c|-m|FILE'),
1750 optionalrepo=True,
1757 optionalrepo=True,
1751 )
1758 )
1752 def debugindexdot(ui, repo, file_=None, **opts):
1759 def debugindexdot(ui, repo, file_=None, **opts):
1753 """dump an index DAG as a graphviz dot file"""
1760 """dump an index DAG as a graphviz dot file"""
1754 opts = pycompat.byteskwargs(opts)
1761 opts = pycompat.byteskwargs(opts)
1755 r = cmdutil.openstorage(repo, b'debugindexdot', file_, opts)
1762 r = cmdutil.openstorage(repo, b'debugindexdot', file_, opts)
1756 ui.writenoi18n(b"digraph G {\n")
1763 ui.writenoi18n(b"digraph G {\n")
1757 for i in r:
1764 for i in r:
1758 node = r.node(i)
1765 node = r.node(i)
1759 pp = r.parents(node)
1766 pp = r.parents(node)
1760 ui.write(b"\t%d -> %d\n" % (r.rev(pp[0]), i))
1767 ui.write(b"\t%d -> %d\n" % (r.rev(pp[0]), i))
1761 if pp[1] != repo.nullid:
1768 if pp[1] != repo.nullid:
1762 ui.write(b"\t%d -> %d\n" % (r.rev(pp[1]), i))
1769 ui.write(b"\t%d -> %d\n" % (r.rev(pp[1]), i))
1763 ui.write(b"}\n")
1770 ui.write(b"}\n")
1764
1771
1765
1772
1766 @command(b'debugindexstats', [])
1773 @command(b'debugindexstats', [])
1767 def debugindexstats(ui, repo):
1774 def debugindexstats(ui, repo):
1768 """show stats related to the changelog index"""
1775 """show stats related to the changelog index"""
1769 repo.changelog.shortest(repo.nullid, 1)
1776 repo.changelog.shortest(repo.nullid, 1)
1770 index = repo.changelog.index
1777 index = repo.changelog.index
1771 if not util.safehasattr(index, b'stats'):
1778 if not util.safehasattr(index, b'stats'):
1772 raise error.Abort(_(b'debugindexstats only works with native code'))
1779 raise error.Abort(_(b'debugindexstats only works with native code'))
1773 for k, v in sorted(index.stats().items()):
1780 for k, v in sorted(index.stats().items()):
1774 ui.write(b'%s: %d\n' % (k, v))
1781 ui.write(b'%s: %d\n' % (k, v))
1775
1782
1776
1783
1777 @command(b'debuginstall', [] + cmdutil.formatteropts, b'', norepo=True)
1784 @command(b'debuginstall', [] + cmdutil.formatteropts, b'', norepo=True)
1778 def debuginstall(ui, **opts):
1785 def debuginstall(ui, **opts):
1779 """test Mercurial installation
1786 """test Mercurial installation
1780
1787
1781 Returns 0 on success.
1788 Returns 0 on success.
1782 """
1789 """
1783 opts = pycompat.byteskwargs(opts)
1790 opts = pycompat.byteskwargs(opts)
1784
1791
1785 problems = 0
1792 problems = 0
1786
1793
1787 fm = ui.formatter(b'debuginstall', opts)
1794 fm = ui.formatter(b'debuginstall', opts)
1788 fm.startitem()
1795 fm.startitem()
1789
1796
1790 # encoding might be unknown or wrong. don't translate these messages.
1797 # encoding might be unknown or wrong. don't translate these messages.
1791 fm.write(b'encoding', b"checking encoding (%s)...\n", encoding.encoding)
1798 fm.write(b'encoding', b"checking encoding (%s)...\n", encoding.encoding)
1792 err = None
1799 err = None
1793 try:
1800 try:
1794 codecs.lookup(pycompat.sysstr(encoding.encoding))
1801 codecs.lookup(pycompat.sysstr(encoding.encoding))
1795 except LookupError as inst:
1802 except LookupError as inst:
1796 err = stringutil.forcebytestr(inst)
1803 err = stringutil.forcebytestr(inst)
1797 problems += 1
1804 problems += 1
1798 fm.condwrite(
1805 fm.condwrite(
1799 err,
1806 err,
1800 b'encodingerror',
1807 b'encodingerror',
1801 b" %s\n (check that your locale is properly set)\n",
1808 b" %s\n (check that your locale is properly set)\n",
1802 err,
1809 err,
1803 )
1810 )
1804
1811
1805 # Python
1812 # Python
1806 pythonlib = None
1813 pythonlib = None
1807 if util.safehasattr(os, '__file__'):
1814 if util.safehasattr(os, '__file__'):
1808 pythonlib = os.path.dirname(pycompat.fsencode(os.__file__))
1815 pythonlib = os.path.dirname(pycompat.fsencode(os.__file__))
1809 elif getattr(sys, 'oxidized', False):
1816 elif getattr(sys, 'oxidized', False):
1810 pythonlib = pycompat.sysexecutable
1817 pythonlib = pycompat.sysexecutable
1811
1818
1812 fm.write(
1819 fm.write(
1813 b'pythonexe',
1820 b'pythonexe',
1814 _(b"checking Python executable (%s)\n"),
1821 _(b"checking Python executable (%s)\n"),
1815 pycompat.sysexecutable or _(b"unknown"),
1822 pycompat.sysexecutable or _(b"unknown"),
1816 )
1823 )
1817 fm.write(
1824 fm.write(
1818 b'pythonimplementation',
1825 b'pythonimplementation',
1819 _(b"checking Python implementation (%s)\n"),
1826 _(b"checking Python implementation (%s)\n"),
1820 pycompat.sysbytes(platform.python_implementation()),
1827 pycompat.sysbytes(platform.python_implementation()),
1821 )
1828 )
1822 fm.write(
1829 fm.write(
1823 b'pythonver',
1830 b'pythonver',
1824 _(b"checking Python version (%s)\n"),
1831 _(b"checking Python version (%s)\n"),
1825 (b"%d.%d.%d" % sys.version_info[:3]),
1832 (b"%d.%d.%d" % sys.version_info[:3]),
1826 )
1833 )
1827 fm.write(
1834 fm.write(
1828 b'pythonlib',
1835 b'pythonlib',
1829 _(b"checking Python lib (%s)...\n"),
1836 _(b"checking Python lib (%s)...\n"),
1830 pythonlib or _(b"unknown"),
1837 pythonlib or _(b"unknown"),
1831 )
1838 )
1832
1839
1833 try:
1840 try:
1834 from . import rustext # pytype: disable=import-error
1841 from . import rustext # pytype: disable=import-error
1835
1842
1836 rustext.__doc__ # trigger lazy import
1843 rustext.__doc__ # trigger lazy import
1837 except ImportError:
1844 except ImportError:
1838 rustext = None
1845 rustext = None
1839
1846
1840 security = set(sslutil.supportedprotocols)
1847 security = set(sslutil.supportedprotocols)
1841 if sslutil.hassni:
1848 if sslutil.hassni:
1842 security.add(b'sni')
1849 security.add(b'sni')
1843
1850
1844 fm.write(
1851 fm.write(
1845 b'pythonsecurity',
1852 b'pythonsecurity',
1846 _(b"checking Python security support (%s)\n"),
1853 _(b"checking Python security support (%s)\n"),
1847 fm.formatlist(sorted(security), name=b'protocol', fmt=b'%s', sep=b','),
1854 fm.formatlist(sorted(security), name=b'protocol', fmt=b'%s', sep=b','),
1848 )
1855 )
1849
1856
1850 # These are warnings, not errors. So don't increment problem count. This
1857 # These are warnings, not errors. So don't increment problem count. This
1851 # may change in the future.
1858 # may change in the future.
1852 if b'tls1.2' not in security:
1859 if b'tls1.2' not in security:
1853 fm.plain(
1860 fm.plain(
1854 _(
1861 _(
1855 b' TLS 1.2 not supported by Python install; '
1862 b' TLS 1.2 not supported by Python install; '
1856 b'network connections lack modern security\n'
1863 b'network connections lack modern security\n'
1857 )
1864 )
1858 )
1865 )
1859 if b'sni' not in security:
1866 if b'sni' not in security:
1860 fm.plain(
1867 fm.plain(
1861 _(
1868 _(
1862 b' SNI not supported by Python install; may have '
1869 b' SNI not supported by Python install; may have '
1863 b'connectivity issues with some servers\n'
1870 b'connectivity issues with some servers\n'
1864 )
1871 )
1865 )
1872 )
1866
1873
1867 fm.plain(
1874 fm.plain(
1868 _(
1875 _(
1869 b"checking Rust extensions (%s)\n"
1876 b"checking Rust extensions (%s)\n"
1870 % (b'missing' if rustext is None else b'installed')
1877 % (b'missing' if rustext is None else b'installed')
1871 ),
1878 ),
1872 )
1879 )
1873
1880
1874 # TODO print CA cert info
1881 # TODO print CA cert info
1875
1882
1876 # hg version
1883 # hg version
1877 hgver = util.version()
1884 hgver = util.version()
1878 fm.write(
1885 fm.write(
1879 b'hgver', _(b"checking Mercurial version (%s)\n"), hgver.split(b'+')[0]
1886 b'hgver', _(b"checking Mercurial version (%s)\n"), hgver.split(b'+')[0]
1880 )
1887 )
1881 fm.write(
1888 fm.write(
1882 b'hgverextra',
1889 b'hgverextra',
1883 _(b"checking Mercurial custom build (%s)\n"),
1890 _(b"checking Mercurial custom build (%s)\n"),
1884 b'+'.join(hgver.split(b'+')[1:]),
1891 b'+'.join(hgver.split(b'+')[1:]),
1885 )
1892 )
1886
1893
1887 # compiled modules
1894 # compiled modules
1888 hgmodules = None
1895 hgmodules = None
1889 if util.safehasattr(sys.modules[__name__], '__file__'):
1896 if util.safehasattr(sys.modules[__name__], '__file__'):
1890 hgmodules = os.path.dirname(pycompat.fsencode(__file__))
1897 hgmodules = os.path.dirname(pycompat.fsencode(__file__))
1891 elif getattr(sys, 'oxidized', False):
1898 elif getattr(sys, 'oxidized', False):
1892 hgmodules = pycompat.sysexecutable
1899 hgmodules = pycompat.sysexecutable
1893
1900
1894 fm.write(
1901 fm.write(
1895 b'hgmodulepolicy', _(b"checking module policy (%s)\n"), policy.policy
1902 b'hgmodulepolicy', _(b"checking module policy (%s)\n"), policy.policy
1896 )
1903 )
1897 fm.write(
1904 fm.write(
1898 b'hgmodules',
1905 b'hgmodules',
1899 _(b"checking installed modules (%s)...\n"),
1906 _(b"checking installed modules (%s)...\n"),
1900 hgmodules or _(b"unknown"),
1907 hgmodules or _(b"unknown"),
1901 )
1908 )
1902
1909
1903 rustandc = policy.policy in (b'rust+c', b'rust+c-allow')
1910 rustandc = policy.policy in (b'rust+c', b'rust+c-allow')
1904 rustext = rustandc # for now, that's the only case
1911 rustext = rustandc # for now, that's the only case
1905 cext = policy.policy in (b'c', b'allow') or rustandc
1912 cext = policy.policy in (b'c', b'allow') or rustandc
1906 nopure = cext or rustext
1913 nopure = cext or rustext
1907 if nopure:
1914 if nopure:
1908 err = None
1915 err = None
1909 try:
1916 try:
1910 if cext:
1917 if cext:
1911 from .cext import ( # pytype: disable=import-error
1918 from .cext import ( # pytype: disable=import-error
1912 base85,
1919 base85,
1913 bdiff,
1920 bdiff,
1914 mpatch,
1921 mpatch,
1915 osutil,
1922 osutil,
1916 )
1923 )
1917
1924
1918 # quiet pyflakes
1925 # quiet pyflakes
1919 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
1926 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
1920 if rustext:
1927 if rustext:
1921 from .rustext import ( # pytype: disable=import-error
1928 from .rustext import ( # pytype: disable=import-error
1922 ancestor,
1929 ancestor,
1923 dirstate,
1930 dirstate,
1924 )
1931 )
1925
1932
1926 dir(ancestor), dir(dirstate) # quiet pyflakes
1933 dir(ancestor), dir(dirstate) # quiet pyflakes
1927 except Exception as inst:
1934 except Exception as inst:
1928 err = stringutil.forcebytestr(inst)
1935 err = stringutil.forcebytestr(inst)
1929 problems += 1
1936 problems += 1
1930 fm.condwrite(err, b'extensionserror', b" %s\n", err)
1937 fm.condwrite(err, b'extensionserror', b" %s\n", err)
1931
1938
1932 compengines = util.compengines._engines.values()
1939 compengines = util.compengines._engines.values()
1933 fm.write(
1940 fm.write(
1934 b'compengines',
1941 b'compengines',
1935 _(b'checking registered compression engines (%s)\n'),
1942 _(b'checking registered compression engines (%s)\n'),
1936 fm.formatlist(
1943 fm.formatlist(
1937 sorted(e.name() for e in compengines),
1944 sorted(e.name() for e in compengines),
1938 name=b'compengine',
1945 name=b'compengine',
1939 fmt=b'%s',
1946 fmt=b'%s',
1940 sep=b', ',
1947 sep=b', ',
1941 ),
1948 ),
1942 )
1949 )
1943 fm.write(
1950 fm.write(
1944 b'compenginesavail',
1951 b'compenginesavail',
1945 _(b'checking available compression engines (%s)\n'),
1952 _(b'checking available compression engines (%s)\n'),
1946 fm.formatlist(
1953 fm.formatlist(
1947 sorted(e.name() for e in compengines if e.available()),
1954 sorted(e.name() for e in compengines if e.available()),
1948 name=b'compengine',
1955 name=b'compengine',
1949 fmt=b'%s',
1956 fmt=b'%s',
1950 sep=b', ',
1957 sep=b', ',
1951 ),
1958 ),
1952 )
1959 )
1953 wirecompengines = compression.compengines.supportedwireengines(
1960 wirecompengines = compression.compengines.supportedwireengines(
1954 compression.SERVERROLE
1961 compression.SERVERROLE
1955 )
1962 )
1956 fm.write(
1963 fm.write(
1957 b'compenginesserver',
1964 b'compenginesserver',
1958 _(
1965 _(
1959 b'checking available compression engines '
1966 b'checking available compression engines '
1960 b'for wire protocol (%s)\n'
1967 b'for wire protocol (%s)\n'
1961 ),
1968 ),
1962 fm.formatlist(
1969 fm.formatlist(
1963 [e.name() for e in wirecompengines if e.wireprotosupport()],
1970 [e.name() for e in wirecompengines if e.wireprotosupport()],
1964 name=b'compengine',
1971 name=b'compengine',
1965 fmt=b'%s',
1972 fmt=b'%s',
1966 sep=b', ',
1973 sep=b', ',
1967 ),
1974 ),
1968 )
1975 )
1969 re2 = b'missing'
1976 re2 = b'missing'
1970 if util._re2:
1977 if util._re2:
1971 re2 = b'available'
1978 re2 = b'available'
1972 fm.plain(_(b'checking "re2" regexp engine (%s)\n') % re2)
1979 fm.plain(_(b'checking "re2" regexp engine (%s)\n') % re2)
1973 fm.data(re2=bool(util._re2))
1980 fm.data(re2=bool(util._re2))
1974
1981
1975 # templates
1982 # templates
1976 p = templater.templatedir()
1983 p = templater.templatedir()
1977 fm.write(b'templatedirs', b'checking templates (%s)...\n', p or b'')
1984 fm.write(b'templatedirs', b'checking templates (%s)...\n', p or b'')
1978 fm.condwrite(not p, b'', _(b" no template directories found\n"))
1985 fm.condwrite(not p, b'', _(b" no template directories found\n"))
1979 if p:
1986 if p:
1980 (m, fp) = templater.try_open_template(b"map-cmdline.default")
1987 (m, fp) = templater.try_open_template(b"map-cmdline.default")
1981 if m:
1988 if m:
1982 # template found, check if it is working
1989 # template found, check if it is working
1983 err = None
1990 err = None
1984 try:
1991 try:
1985 templater.templater.frommapfile(m)
1992 templater.templater.frommapfile(m)
1986 except Exception as inst:
1993 except Exception as inst:
1987 err = stringutil.forcebytestr(inst)
1994 err = stringutil.forcebytestr(inst)
1988 p = None
1995 p = None
1989 fm.condwrite(err, b'defaulttemplateerror', b" %s\n", err)
1996 fm.condwrite(err, b'defaulttemplateerror', b" %s\n", err)
1990 else:
1997 else:
1991 p = None
1998 p = None
1992 fm.condwrite(
1999 fm.condwrite(
1993 p, b'defaulttemplate', _(b"checking default template (%s)\n"), m
2000 p, b'defaulttemplate', _(b"checking default template (%s)\n"), m
1994 )
2001 )
1995 fm.condwrite(
2002 fm.condwrite(
1996 not m,
2003 not m,
1997 b'defaulttemplatenotfound',
2004 b'defaulttemplatenotfound',
1998 _(b" template '%s' not found\n"),
2005 _(b" template '%s' not found\n"),
1999 b"default",
2006 b"default",
2000 )
2007 )
2001 if not p:
2008 if not p:
2002 problems += 1
2009 problems += 1
2003 fm.condwrite(
2010 fm.condwrite(
2004 not p, b'', _(b" (templates seem to have been installed incorrectly)\n")
2011 not p, b'', _(b" (templates seem to have been installed incorrectly)\n")
2005 )
2012 )
2006
2013
2007 # editor
2014 # editor
2008 editor = ui.geteditor()
2015 editor = ui.geteditor()
2009 editor = util.expandpath(editor)
2016 editor = util.expandpath(editor)
2010 editorbin = procutil.shellsplit(editor)[0]
2017 editorbin = procutil.shellsplit(editor)[0]
2011 fm.write(b'editor', _(b"checking commit editor... (%s)\n"), editorbin)
2018 fm.write(b'editor', _(b"checking commit editor... (%s)\n"), editorbin)
2012 cmdpath = procutil.findexe(editorbin)
2019 cmdpath = procutil.findexe(editorbin)
2013 fm.condwrite(
2020 fm.condwrite(
2014 not cmdpath and editor == b'vi',
2021 not cmdpath and editor == b'vi',
2015 b'vinotfound',
2022 b'vinotfound',
2016 _(
2023 _(
2017 b" No commit editor set and can't find %s in PATH\n"
2024 b" No commit editor set and can't find %s in PATH\n"
2018 b" (specify a commit editor in your configuration"
2025 b" (specify a commit editor in your configuration"
2019 b" file)\n"
2026 b" file)\n"
2020 ),
2027 ),
2021 not cmdpath and editor == b'vi' and editorbin,
2028 not cmdpath and editor == b'vi' and editorbin,
2022 )
2029 )
2023 fm.condwrite(
2030 fm.condwrite(
2024 not cmdpath and editor != b'vi',
2031 not cmdpath and editor != b'vi',
2025 b'editornotfound',
2032 b'editornotfound',
2026 _(
2033 _(
2027 b" Can't find editor '%s' in PATH\n"
2034 b" Can't find editor '%s' in PATH\n"
2028 b" (specify a commit editor in your configuration"
2035 b" (specify a commit editor in your configuration"
2029 b" file)\n"
2036 b" file)\n"
2030 ),
2037 ),
2031 not cmdpath and editorbin,
2038 not cmdpath and editorbin,
2032 )
2039 )
2033 if not cmdpath and editor != b'vi':
2040 if not cmdpath and editor != b'vi':
2034 problems += 1
2041 problems += 1
2035
2042
2036 # check username
2043 # check username
2037 username = None
2044 username = None
2038 err = None
2045 err = None
2039 try:
2046 try:
2040 username = ui.username()
2047 username = ui.username()
2041 except error.Abort as e:
2048 except error.Abort as e:
2042 err = e.message
2049 err = e.message
2043 problems += 1
2050 problems += 1
2044
2051
2045 fm.condwrite(
2052 fm.condwrite(
2046 username, b'username', _(b"checking username (%s)\n"), username
2053 username, b'username', _(b"checking username (%s)\n"), username
2047 )
2054 )
2048 fm.condwrite(
2055 fm.condwrite(
2049 err,
2056 err,
2050 b'usernameerror',
2057 b'usernameerror',
2051 _(
2058 _(
2052 b"checking username...\n %s\n"
2059 b"checking username...\n %s\n"
2053 b" (specify a username in your configuration file)\n"
2060 b" (specify a username in your configuration file)\n"
2054 ),
2061 ),
2055 err,
2062 err,
2056 )
2063 )
2057
2064
2058 for name, mod in extensions.extensions():
2065 for name, mod in extensions.extensions():
2059 handler = getattr(mod, 'debuginstall', None)
2066 handler = getattr(mod, 'debuginstall', None)
2060 if handler is not None:
2067 if handler is not None:
2061 problems += handler(ui, fm)
2068 problems += handler(ui, fm)
2062
2069
2063 fm.condwrite(not problems, b'', _(b"no problems detected\n"))
2070 fm.condwrite(not problems, b'', _(b"no problems detected\n"))
2064 if not problems:
2071 if not problems:
2065 fm.data(problems=problems)
2072 fm.data(problems=problems)
2066 fm.condwrite(
2073 fm.condwrite(
2067 problems,
2074 problems,
2068 b'problems',
2075 b'problems',
2069 _(b"%d problems detected, please check your install!\n"),
2076 _(b"%d problems detected, please check your install!\n"),
2070 problems,
2077 problems,
2071 )
2078 )
2072 fm.end()
2079 fm.end()
2073
2080
2074 return problems
2081 return problems
2075
2082
2076
2083
2077 @command(b'debugknown', [], _(b'REPO ID...'), norepo=True)
2084 @command(b'debugknown', [], _(b'REPO ID...'), norepo=True)
2078 def debugknown(ui, repopath, *ids, **opts):
2085 def debugknown(ui, repopath, *ids, **opts):
2079 """test whether node ids are known to a repo
2086 """test whether node ids are known to a repo
2080
2087
2081 Every ID must be a full-length hex node id string. Returns a list of 0s
2088 Every ID must be a full-length hex node id string. Returns a list of 0s
2082 and 1s indicating unknown/known.
2089 and 1s indicating unknown/known.
2083 """
2090 """
2084 opts = pycompat.byteskwargs(opts)
2091 opts = pycompat.byteskwargs(opts)
2085 repo = hg.peer(ui, opts, repopath)
2092 repo = hg.peer(ui, opts, repopath)
2086 if not repo.capable(b'known'):
2093 if not repo.capable(b'known'):
2087 raise error.Abort(b"known() not supported by target repository")
2094 raise error.Abort(b"known() not supported by target repository")
2088 flags = repo.known([bin(s) for s in ids])
2095 flags = repo.known([bin(s) for s in ids])
2089 ui.write(b"%s\n" % (b"".join([f and b"1" or b"0" for f in flags])))
2096 ui.write(b"%s\n" % (b"".join([f and b"1" or b"0" for f in flags])))
2090
2097
2091
2098
2092 @command(b'debuglabelcomplete', [], _(b'LABEL...'))
2099 @command(b'debuglabelcomplete', [], _(b'LABEL...'))
2093 def debuglabelcomplete(ui, repo, *args):
2100 def debuglabelcomplete(ui, repo, *args):
2094 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2101 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2095 debugnamecomplete(ui, repo, *args)
2102 debugnamecomplete(ui, repo, *args)
2096
2103
2097
2104
2098 @command(
2105 @command(
2099 b'debuglocks',
2106 b'debuglocks',
2100 [
2107 [
2101 (b'L', b'force-free-lock', None, _(b'free the store lock (DANGEROUS)')),
2108 (b'L', b'force-free-lock', None, _(b'free the store lock (DANGEROUS)')),
2102 (
2109 (
2103 b'W',
2110 b'W',
2104 b'force-free-wlock',
2111 b'force-free-wlock',
2105 None,
2112 None,
2106 _(b'free the working state lock (DANGEROUS)'),
2113 _(b'free the working state lock (DANGEROUS)'),
2107 ),
2114 ),
2108 (b's', b'set-lock', None, _(b'set the store lock until stopped')),
2115 (b's', b'set-lock', None, _(b'set the store lock until stopped')),
2109 (
2116 (
2110 b'S',
2117 b'S',
2111 b'set-wlock',
2118 b'set-wlock',
2112 None,
2119 None,
2113 _(b'set the working state lock until stopped'),
2120 _(b'set the working state lock until stopped'),
2114 ),
2121 ),
2115 ],
2122 ],
2116 _(b'[OPTION]...'),
2123 _(b'[OPTION]...'),
2117 )
2124 )
2118 def debuglocks(ui, repo, **opts):
2125 def debuglocks(ui, repo, **opts):
2119 """show or modify state of locks
2126 """show or modify state of locks
2120
2127
2121 By default, this command will show which locks are held. This
2128 By default, this command will show which locks are held. This
2122 includes the user and process holding the lock, the amount of time
2129 includes the user and process holding the lock, the amount of time
2123 the lock has been held, and the machine name where the process is
2130 the lock has been held, and the machine name where the process is
2124 running if it's not local.
2131 running if it's not local.
2125
2132
2126 Locks protect the integrity of Mercurial's data, so should be
2133 Locks protect the integrity of Mercurial's data, so should be
2127 treated with care. System crashes or other interruptions may cause
2134 treated with care. System crashes or other interruptions may cause
2128 locks to not be properly released, though Mercurial will usually
2135 locks to not be properly released, though Mercurial will usually
2129 detect and remove such stale locks automatically.
2136 detect and remove such stale locks automatically.
2130
2137
2131 However, detecting stale locks may not always be possible (for
2138 However, detecting stale locks may not always be possible (for
2132 instance, on a shared filesystem). Removing locks may also be
2139 instance, on a shared filesystem). Removing locks may also be
2133 blocked by filesystem permissions.
2140 blocked by filesystem permissions.
2134
2141
2135 Setting a lock will prevent other commands from changing the data.
2142 Setting a lock will prevent other commands from changing the data.
2136 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
2143 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
2137 The set locks are removed when the command exits.
2144 The set locks are removed when the command exits.
2138
2145
2139 Returns 0 if no locks are held.
2146 Returns 0 if no locks are held.
2140
2147
2141 """
2148 """
2142
2149
2143 if opts.get('force_free_lock'):
2150 if opts.get('force_free_lock'):
2144 repo.svfs.unlink(b'lock')
2151 repo.svfs.unlink(b'lock')
2145 if opts.get('force_free_wlock'):
2152 if opts.get('force_free_wlock'):
2146 repo.vfs.unlink(b'wlock')
2153 repo.vfs.unlink(b'wlock')
2147 if opts.get('force_free_lock') or opts.get('force_free_wlock'):
2154 if opts.get('force_free_lock') or opts.get('force_free_wlock'):
2148 return 0
2155 return 0
2149
2156
2150 locks = []
2157 locks = []
2151 try:
2158 try:
2152 if opts.get('set_wlock'):
2159 if opts.get('set_wlock'):
2153 try:
2160 try:
2154 locks.append(repo.wlock(False))
2161 locks.append(repo.wlock(False))
2155 except error.LockHeld:
2162 except error.LockHeld:
2156 raise error.Abort(_(b'wlock is already held'))
2163 raise error.Abort(_(b'wlock is already held'))
2157 if opts.get('set_lock'):
2164 if opts.get('set_lock'):
2158 try:
2165 try:
2159 locks.append(repo.lock(False))
2166 locks.append(repo.lock(False))
2160 except error.LockHeld:
2167 except error.LockHeld:
2161 raise error.Abort(_(b'lock is already held'))
2168 raise error.Abort(_(b'lock is already held'))
2162 if len(locks):
2169 if len(locks):
2163 ui.promptchoice(_(b"ready to release the lock (y)? $$ &Yes"))
2170 ui.promptchoice(_(b"ready to release the lock (y)? $$ &Yes"))
2164 return 0
2171 return 0
2165 finally:
2172 finally:
2166 release(*locks)
2173 release(*locks)
2167
2174
2168 now = time.time()
2175 now = time.time()
2169 held = 0
2176 held = 0
2170
2177
2171 def report(vfs, name, method):
2178 def report(vfs, name, method):
2172 # this causes stale locks to get reaped for more accurate reporting
2179 # this causes stale locks to get reaped for more accurate reporting
2173 try:
2180 try:
2174 l = method(False)
2181 l = method(False)
2175 except error.LockHeld:
2182 except error.LockHeld:
2176 l = None
2183 l = None
2177
2184
2178 if l:
2185 if l:
2179 l.release()
2186 l.release()
2180 else:
2187 else:
2181 try:
2188 try:
2182 st = vfs.lstat(name)
2189 st = vfs.lstat(name)
2183 age = now - st[stat.ST_MTIME]
2190 age = now - st[stat.ST_MTIME]
2184 user = util.username(st.st_uid)
2191 user = util.username(st.st_uid)
2185 locker = vfs.readlock(name)
2192 locker = vfs.readlock(name)
2186 if b":" in locker:
2193 if b":" in locker:
2187 host, pid = locker.split(b':')
2194 host, pid = locker.split(b':')
2188 if host == socket.gethostname():
2195 if host == socket.gethostname():
2189 locker = b'user %s, process %s' % (user or b'None', pid)
2196 locker = b'user %s, process %s' % (user or b'None', pid)
2190 else:
2197 else:
2191 locker = b'user %s, process %s, host %s' % (
2198 locker = b'user %s, process %s, host %s' % (
2192 user or b'None',
2199 user or b'None',
2193 pid,
2200 pid,
2194 host,
2201 host,
2195 )
2202 )
2196 ui.writenoi18n(b"%-6s %s (%ds)\n" % (name + b":", locker, age))
2203 ui.writenoi18n(b"%-6s %s (%ds)\n" % (name + b":", locker, age))
2197 return 1
2204 return 1
2198 except OSError as e:
2205 except OSError as e:
2199 if e.errno != errno.ENOENT:
2206 if e.errno != errno.ENOENT:
2200 raise
2207 raise
2201
2208
2202 ui.writenoi18n(b"%-6s free\n" % (name + b":"))
2209 ui.writenoi18n(b"%-6s free\n" % (name + b":"))
2203 return 0
2210 return 0
2204
2211
2205 held += report(repo.svfs, b"lock", repo.lock)
2212 held += report(repo.svfs, b"lock", repo.lock)
2206 held += report(repo.vfs, b"wlock", repo.wlock)
2213 held += report(repo.vfs, b"wlock", repo.wlock)
2207
2214
2208 return held
2215 return held
2209
2216
2210
2217
2211 @command(
2218 @command(
2212 b'debugmanifestfulltextcache',
2219 b'debugmanifestfulltextcache',
2213 [
2220 [
2214 (b'', b'clear', False, _(b'clear the cache')),
2221 (b'', b'clear', False, _(b'clear the cache')),
2215 (
2222 (
2216 b'a',
2223 b'a',
2217 b'add',
2224 b'add',
2218 [],
2225 [],
2219 _(b'add the given manifest nodes to the cache'),
2226 _(b'add the given manifest nodes to the cache'),
2220 _(b'NODE'),
2227 _(b'NODE'),
2221 ),
2228 ),
2222 ],
2229 ],
2223 b'',
2230 b'',
2224 )
2231 )
2225 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
2232 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
2226 """show, clear or amend the contents of the manifest fulltext cache"""
2233 """show, clear or amend the contents of the manifest fulltext cache"""
2227
2234
2228 def getcache():
2235 def getcache():
2229 r = repo.manifestlog.getstorage(b'')
2236 r = repo.manifestlog.getstorage(b'')
2230 try:
2237 try:
2231 return r._fulltextcache
2238 return r._fulltextcache
2232 except AttributeError:
2239 except AttributeError:
2233 msg = _(
2240 msg = _(
2234 b"Current revlog implementation doesn't appear to have a "
2241 b"Current revlog implementation doesn't appear to have a "
2235 b"manifest fulltext cache\n"
2242 b"manifest fulltext cache\n"
2236 )
2243 )
2237 raise error.Abort(msg)
2244 raise error.Abort(msg)
2238
2245
2239 if opts.get('clear'):
2246 if opts.get('clear'):
2240 with repo.wlock():
2247 with repo.wlock():
2241 cache = getcache()
2248 cache = getcache()
2242 cache.clear(clear_persisted_data=True)
2249 cache.clear(clear_persisted_data=True)
2243 return
2250 return
2244
2251
2245 if add:
2252 if add:
2246 with repo.wlock():
2253 with repo.wlock():
2247 m = repo.manifestlog
2254 m = repo.manifestlog
2248 store = m.getstorage(b'')
2255 store = m.getstorage(b'')
2249 for n in add:
2256 for n in add:
2250 try:
2257 try:
2251 manifest = m[store.lookup(n)]
2258 manifest = m[store.lookup(n)]
2252 except error.LookupError as e:
2259 except error.LookupError as e:
2253 raise error.Abort(
2260 raise error.Abort(
2254 bytes(e), hint=b"Check your manifest node id"
2261 bytes(e), hint=b"Check your manifest node id"
2255 )
2262 )
2256 manifest.read() # stores revisision in cache too
2263 manifest.read() # stores revisision in cache too
2257 return
2264 return
2258
2265
2259 cache = getcache()
2266 cache = getcache()
2260 if not len(cache):
2267 if not len(cache):
2261 ui.write(_(b'cache empty\n'))
2268 ui.write(_(b'cache empty\n'))
2262 else:
2269 else:
2263 ui.write(
2270 ui.write(
2264 _(
2271 _(
2265 b'cache contains %d manifest entries, in order of most to '
2272 b'cache contains %d manifest entries, in order of most to '
2266 b'least recent:\n'
2273 b'least recent:\n'
2267 )
2274 )
2268 % (len(cache),)
2275 % (len(cache),)
2269 )
2276 )
2270 totalsize = 0
2277 totalsize = 0
2271 for nodeid in cache:
2278 for nodeid in cache:
2272 # Use cache.get to not update the LRU order
2279 # Use cache.get to not update the LRU order
2273 data = cache.peek(nodeid)
2280 data = cache.peek(nodeid)
2274 size = len(data)
2281 size = len(data)
2275 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
2282 totalsize += size + 24 # 20 bytes nodeid, 4 bytes size
2276 ui.write(
2283 ui.write(
2277 _(b'id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
2284 _(b'id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
2278 )
2285 )
2279 ondisk = cache._opener.stat(b'manifestfulltextcache').st_size
2286 ondisk = cache._opener.stat(b'manifestfulltextcache').st_size
2280 ui.write(
2287 ui.write(
2281 _(b'total cache data size %s, on-disk %s\n')
2288 _(b'total cache data size %s, on-disk %s\n')
2282 % (util.bytecount(totalsize), util.bytecount(ondisk))
2289 % (util.bytecount(totalsize), util.bytecount(ondisk))
2283 )
2290 )
2284
2291
2285
2292
2286 @command(b'debugmergestate', [] + cmdutil.templateopts, b'')
2293 @command(b'debugmergestate', [] + cmdutil.templateopts, b'')
2287 def debugmergestate(ui, repo, *args, **opts):
2294 def debugmergestate(ui, repo, *args, **opts):
2288 """print merge state
2295 """print merge state
2289
2296
2290 Use --verbose to print out information about whether v1 or v2 merge state
2297 Use --verbose to print out information about whether v1 or v2 merge state
2291 was chosen."""
2298 was chosen."""
2292
2299
2293 if ui.verbose:
2300 if ui.verbose:
2294 ms = mergestatemod.mergestate(repo)
2301 ms = mergestatemod.mergestate(repo)
2295
2302
2296 # sort so that reasonable information is on top
2303 # sort so that reasonable information is on top
2297 v1records = ms._readrecordsv1()
2304 v1records = ms._readrecordsv1()
2298 v2records = ms._readrecordsv2()
2305 v2records = ms._readrecordsv2()
2299
2306
2300 if not v1records and not v2records:
2307 if not v1records and not v2records:
2301 pass
2308 pass
2302 elif not v2records:
2309 elif not v2records:
2303 ui.writenoi18n(b'no version 2 merge state\n')
2310 ui.writenoi18n(b'no version 2 merge state\n')
2304 elif ms._v1v2match(v1records, v2records):
2311 elif ms._v1v2match(v1records, v2records):
2305 ui.writenoi18n(b'v1 and v2 states match: using v2\n')
2312 ui.writenoi18n(b'v1 and v2 states match: using v2\n')
2306 else:
2313 else:
2307 ui.writenoi18n(b'v1 and v2 states mismatch: using v1\n')
2314 ui.writenoi18n(b'v1 and v2 states mismatch: using v1\n')
2308
2315
2309 opts = pycompat.byteskwargs(opts)
2316 opts = pycompat.byteskwargs(opts)
2310 if not opts[b'template']:
2317 if not opts[b'template']:
2311 opts[b'template'] = (
2318 opts[b'template'] = (
2312 b'{if(commits, "", "no merge state found\n")}'
2319 b'{if(commits, "", "no merge state found\n")}'
2313 b'{commits % "{name}{if(label, " ({label})")}: {node}\n"}'
2320 b'{commits % "{name}{if(label, " ({label})")}: {node}\n"}'
2314 b'{files % "file: {path} (state \\"{state}\\")\n'
2321 b'{files % "file: {path} (state \\"{state}\\")\n'
2315 b'{if(local_path, "'
2322 b'{if(local_path, "'
2316 b' local path: {local_path} (hash {local_key}, flags \\"{local_flags}\\")\n'
2323 b' local path: {local_path} (hash {local_key}, flags \\"{local_flags}\\")\n'
2317 b' ancestor path: {ancestor_path} (node {ancestor_node})\n'
2324 b' ancestor path: {ancestor_path} (node {ancestor_node})\n'
2318 b' other path: {other_path} (node {other_node})\n'
2325 b' other path: {other_path} (node {other_node})\n'
2319 b'")}'
2326 b'")}'
2320 b'{if(rename_side, "'
2327 b'{if(rename_side, "'
2321 b' rename side: {rename_side}\n'
2328 b' rename side: {rename_side}\n'
2322 b' renamed path: {renamed_path}\n'
2329 b' renamed path: {renamed_path}\n'
2323 b'")}'
2330 b'")}'
2324 b'{extras % " extra: {key} = {value}\n"}'
2331 b'{extras % " extra: {key} = {value}\n"}'
2325 b'"}'
2332 b'"}'
2326 b'{extras % "extra: {file} ({key} = {value})\n"}'
2333 b'{extras % "extra: {file} ({key} = {value})\n"}'
2327 )
2334 )
2328
2335
2329 ms = mergestatemod.mergestate.read(repo)
2336 ms = mergestatemod.mergestate.read(repo)
2330
2337
2331 fm = ui.formatter(b'debugmergestate', opts)
2338 fm = ui.formatter(b'debugmergestate', opts)
2332 fm.startitem()
2339 fm.startitem()
2333
2340
2334 fm_commits = fm.nested(b'commits')
2341 fm_commits = fm.nested(b'commits')
2335 if ms.active():
2342 if ms.active():
2336 for name, node, label_index in (
2343 for name, node, label_index in (
2337 (b'local', ms.local, 0),
2344 (b'local', ms.local, 0),
2338 (b'other', ms.other, 1),
2345 (b'other', ms.other, 1),
2339 ):
2346 ):
2340 fm_commits.startitem()
2347 fm_commits.startitem()
2341 fm_commits.data(name=name)
2348 fm_commits.data(name=name)
2342 fm_commits.data(node=hex(node))
2349 fm_commits.data(node=hex(node))
2343 if ms._labels and len(ms._labels) > label_index:
2350 if ms._labels and len(ms._labels) > label_index:
2344 fm_commits.data(label=ms._labels[label_index])
2351 fm_commits.data(label=ms._labels[label_index])
2345 fm_commits.end()
2352 fm_commits.end()
2346
2353
2347 fm_files = fm.nested(b'files')
2354 fm_files = fm.nested(b'files')
2348 if ms.active():
2355 if ms.active():
2349 for f in ms:
2356 for f in ms:
2350 fm_files.startitem()
2357 fm_files.startitem()
2351 fm_files.data(path=f)
2358 fm_files.data(path=f)
2352 state = ms._state[f]
2359 state = ms._state[f]
2353 fm_files.data(state=state[0])
2360 fm_files.data(state=state[0])
2354 if state[0] in (
2361 if state[0] in (
2355 mergestatemod.MERGE_RECORD_UNRESOLVED,
2362 mergestatemod.MERGE_RECORD_UNRESOLVED,
2356 mergestatemod.MERGE_RECORD_RESOLVED,
2363 mergestatemod.MERGE_RECORD_RESOLVED,
2357 ):
2364 ):
2358 fm_files.data(local_key=state[1])
2365 fm_files.data(local_key=state[1])
2359 fm_files.data(local_path=state[2])
2366 fm_files.data(local_path=state[2])
2360 fm_files.data(ancestor_path=state[3])
2367 fm_files.data(ancestor_path=state[3])
2361 fm_files.data(ancestor_node=state[4])
2368 fm_files.data(ancestor_node=state[4])
2362 fm_files.data(other_path=state[5])
2369 fm_files.data(other_path=state[5])
2363 fm_files.data(other_node=state[6])
2370 fm_files.data(other_node=state[6])
2364 fm_files.data(local_flags=state[7])
2371 fm_files.data(local_flags=state[7])
2365 elif state[0] in (
2372 elif state[0] in (
2366 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
2373 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
2367 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
2374 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
2368 ):
2375 ):
2369 fm_files.data(renamed_path=state[1])
2376 fm_files.data(renamed_path=state[1])
2370 fm_files.data(rename_side=state[2])
2377 fm_files.data(rename_side=state[2])
2371 fm_extras = fm_files.nested(b'extras')
2378 fm_extras = fm_files.nested(b'extras')
2372 for k, v in sorted(ms.extras(f).items()):
2379 for k, v in sorted(ms.extras(f).items()):
2373 fm_extras.startitem()
2380 fm_extras.startitem()
2374 fm_extras.data(key=k)
2381 fm_extras.data(key=k)
2375 fm_extras.data(value=v)
2382 fm_extras.data(value=v)
2376 fm_extras.end()
2383 fm_extras.end()
2377
2384
2378 fm_files.end()
2385 fm_files.end()
2379
2386
2380 fm_extras = fm.nested(b'extras')
2387 fm_extras = fm.nested(b'extras')
2381 for f, d in sorted(pycompat.iteritems(ms.allextras())):
2388 for f, d in sorted(pycompat.iteritems(ms.allextras())):
2382 if f in ms:
2389 if f in ms:
2383 # If file is in mergestate, we have already processed it's extras
2390 # If file is in mergestate, we have already processed it's extras
2384 continue
2391 continue
2385 for k, v in pycompat.iteritems(d):
2392 for k, v in pycompat.iteritems(d):
2386 fm_extras.startitem()
2393 fm_extras.startitem()
2387 fm_extras.data(file=f)
2394 fm_extras.data(file=f)
2388 fm_extras.data(key=k)
2395 fm_extras.data(key=k)
2389 fm_extras.data(value=v)
2396 fm_extras.data(value=v)
2390 fm_extras.end()
2397 fm_extras.end()
2391
2398
2392 fm.end()
2399 fm.end()
2393
2400
2394
2401
2395 @command(b'debugnamecomplete', [], _(b'NAME...'))
2402 @command(b'debugnamecomplete', [], _(b'NAME...'))
2396 def debugnamecomplete(ui, repo, *args):
2403 def debugnamecomplete(ui, repo, *args):
2397 '''complete "names" - tags, open branch names, bookmark names'''
2404 '''complete "names" - tags, open branch names, bookmark names'''
2398
2405
2399 names = set()
2406 names = set()
2400 # since we previously only listed open branches, we will handle that
2407 # since we previously only listed open branches, we will handle that
2401 # specially (after this for loop)
2408 # specially (after this for loop)
2402 for name, ns in pycompat.iteritems(repo.names):
2409 for name, ns in pycompat.iteritems(repo.names):
2403 if name != b'branches':
2410 if name != b'branches':
2404 names.update(ns.listnames(repo))
2411 names.update(ns.listnames(repo))
2405 names.update(
2412 names.update(
2406 tag
2413 tag
2407 for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
2414 for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
2408 if not closed
2415 if not closed
2409 )
2416 )
2410 completions = set()
2417 completions = set()
2411 if not args:
2418 if not args:
2412 args = [b'']
2419 args = [b'']
2413 for a in args:
2420 for a in args:
2414 completions.update(n for n in names if n.startswith(a))
2421 completions.update(n for n in names if n.startswith(a))
2415 ui.write(b'\n'.join(sorted(completions)))
2422 ui.write(b'\n'.join(sorted(completions)))
2416 ui.write(b'\n')
2423 ui.write(b'\n')
2417
2424
2418
2425
2419 @command(
2426 @command(
2420 b'debugnodemap',
2427 b'debugnodemap',
2421 [
2428 [
2422 (
2429 (
2423 b'',
2430 b'',
2424 b'dump-new',
2431 b'dump-new',
2425 False,
2432 False,
2426 _(b'write a (new) persistent binary nodemap on stdout'),
2433 _(b'write a (new) persistent binary nodemap on stdout'),
2427 ),
2434 ),
2428 (b'', b'dump-disk', False, _(b'dump on-disk data on stdout')),
2435 (b'', b'dump-disk', False, _(b'dump on-disk data on stdout')),
2429 (
2436 (
2430 b'',
2437 b'',
2431 b'check',
2438 b'check',
2432 False,
2439 False,
2433 _(b'check that the data on disk data are correct.'),
2440 _(b'check that the data on disk data are correct.'),
2434 ),
2441 ),
2435 (
2442 (
2436 b'',
2443 b'',
2437 b'metadata',
2444 b'metadata',
2438 False,
2445 False,
2439 _(b'display the on disk meta data for the nodemap'),
2446 _(b'display the on disk meta data for the nodemap'),
2440 ),
2447 ),
2441 ],
2448 ],
2442 )
2449 )
2443 def debugnodemap(ui, repo, **opts):
2450 def debugnodemap(ui, repo, **opts):
2444 """write and inspect on disk nodemap"""
2451 """write and inspect on disk nodemap"""
2445 if opts['dump_new']:
2452 if opts['dump_new']:
2446 unfi = repo.unfiltered()
2453 unfi = repo.unfiltered()
2447 cl = unfi.changelog
2454 cl = unfi.changelog
2448 if util.safehasattr(cl.index, "nodemap_data_all"):
2455 if util.safehasattr(cl.index, "nodemap_data_all"):
2449 data = cl.index.nodemap_data_all()
2456 data = cl.index.nodemap_data_all()
2450 else:
2457 else:
2451 data = nodemap.persistent_data(cl.index)
2458 data = nodemap.persistent_data(cl.index)
2452 ui.write(data)
2459 ui.write(data)
2453 elif opts['dump_disk']:
2460 elif opts['dump_disk']:
2454 unfi = repo.unfiltered()
2461 unfi = repo.unfiltered()
2455 cl = unfi.changelog
2462 cl = unfi.changelog
2456 nm_data = nodemap.persisted_data(cl)
2463 nm_data = nodemap.persisted_data(cl)
2457 if nm_data is not None:
2464 if nm_data is not None:
2458 docket, data = nm_data
2465 docket, data = nm_data
2459 ui.write(data[:])
2466 ui.write(data[:])
2460 elif opts['check']:
2467 elif opts['check']:
2461 unfi = repo.unfiltered()
2468 unfi = repo.unfiltered()
2462 cl = unfi.changelog
2469 cl = unfi.changelog
2463 nm_data = nodemap.persisted_data(cl)
2470 nm_data = nodemap.persisted_data(cl)
2464 if nm_data is not None:
2471 if nm_data is not None:
2465 docket, data = nm_data
2472 docket, data = nm_data
2466 return nodemap.check_data(ui, cl.index, data)
2473 return nodemap.check_data(ui, cl.index, data)
2467 elif opts['metadata']:
2474 elif opts['metadata']:
2468 unfi = repo.unfiltered()
2475 unfi = repo.unfiltered()
2469 cl = unfi.changelog
2476 cl = unfi.changelog
2470 nm_data = nodemap.persisted_data(cl)
2477 nm_data = nodemap.persisted_data(cl)
2471 if nm_data is not None:
2478 if nm_data is not None:
2472 docket, data = nm_data
2479 docket, data = nm_data
2473 ui.write((b"uid: %s\n") % docket.uid)
2480 ui.write((b"uid: %s\n") % docket.uid)
2474 ui.write((b"tip-rev: %d\n") % docket.tip_rev)
2481 ui.write((b"tip-rev: %d\n") % docket.tip_rev)
2475 ui.write((b"tip-node: %s\n") % hex(docket.tip_node))
2482 ui.write((b"tip-node: %s\n") % hex(docket.tip_node))
2476 ui.write((b"data-length: %d\n") % docket.data_length)
2483 ui.write((b"data-length: %d\n") % docket.data_length)
2477 ui.write((b"data-unused: %d\n") % docket.data_unused)
2484 ui.write((b"data-unused: %d\n") % docket.data_unused)
2478 unused_perc = docket.data_unused * 100.0 / docket.data_length
2485 unused_perc = docket.data_unused * 100.0 / docket.data_length
2479 ui.write((b"data-unused: %2.3f%%\n") % unused_perc)
2486 ui.write((b"data-unused: %2.3f%%\n") % unused_perc)
2480
2487
2481
2488
2482 @command(
2489 @command(
2483 b'debugobsolete',
2490 b'debugobsolete',
2484 [
2491 [
2485 (b'', b'flags', 0, _(b'markers flag')),
2492 (b'', b'flags', 0, _(b'markers flag')),
2486 (
2493 (
2487 b'',
2494 b'',
2488 b'record-parents',
2495 b'record-parents',
2489 False,
2496 False,
2490 _(b'record parent information for the precursor'),
2497 _(b'record parent information for the precursor'),
2491 ),
2498 ),
2492 (b'r', b'rev', [], _(b'display markers relevant to REV')),
2499 (b'r', b'rev', [], _(b'display markers relevant to REV')),
2493 (
2500 (
2494 b'',
2501 b'',
2495 b'exclusive',
2502 b'exclusive',
2496 False,
2503 False,
2497 _(b'restrict display to markers only relevant to REV'),
2504 _(b'restrict display to markers only relevant to REV'),
2498 ),
2505 ),
2499 (b'', b'index', False, _(b'display index of the marker')),
2506 (b'', b'index', False, _(b'display index of the marker')),
2500 (b'', b'delete', [], _(b'delete markers specified by indices')),
2507 (b'', b'delete', [], _(b'delete markers specified by indices')),
2501 ]
2508 ]
2502 + cmdutil.commitopts2
2509 + cmdutil.commitopts2
2503 + cmdutil.formatteropts,
2510 + cmdutil.formatteropts,
2504 _(b'[OBSOLETED [REPLACEMENT ...]]'),
2511 _(b'[OBSOLETED [REPLACEMENT ...]]'),
2505 )
2512 )
2506 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2513 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2507 """create arbitrary obsolete marker
2514 """create arbitrary obsolete marker
2508
2515
2509 With no arguments, displays the list of obsolescence markers."""
2516 With no arguments, displays the list of obsolescence markers."""
2510
2517
2511 opts = pycompat.byteskwargs(opts)
2518 opts = pycompat.byteskwargs(opts)
2512
2519
2513 def parsenodeid(s):
2520 def parsenodeid(s):
2514 try:
2521 try:
2515 # We do not use revsingle/revrange functions here to accept
2522 # We do not use revsingle/revrange functions here to accept
2516 # arbitrary node identifiers, possibly not present in the
2523 # arbitrary node identifiers, possibly not present in the
2517 # local repository.
2524 # local repository.
2518 n = bin(s)
2525 n = bin(s)
2519 if len(n) != repo.nodeconstants.nodelen:
2526 if len(n) != repo.nodeconstants.nodelen:
2520 raise TypeError()
2527 raise TypeError()
2521 return n
2528 return n
2522 except TypeError:
2529 except TypeError:
2523 raise error.InputError(
2530 raise error.InputError(
2524 b'changeset references must be full hexadecimal '
2531 b'changeset references must be full hexadecimal '
2525 b'node identifiers'
2532 b'node identifiers'
2526 )
2533 )
2527
2534
2528 if opts.get(b'delete'):
2535 if opts.get(b'delete'):
2529 indices = []
2536 indices = []
2530 for v in opts.get(b'delete'):
2537 for v in opts.get(b'delete'):
2531 try:
2538 try:
2532 indices.append(int(v))
2539 indices.append(int(v))
2533 except ValueError:
2540 except ValueError:
2534 raise error.InputError(
2541 raise error.InputError(
2535 _(b'invalid index value: %r') % v,
2542 _(b'invalid index value: %r') % v,
2536 hint=_(b'use integers for indices'),
2543 hint=_(b'use integers for indices'),
2537 )
2544 )
2538
2545
2539 if repo.currenttransaction():
2546 if repo.currenttransaction():
2540 raise error.Abort(
2547 raise error.Abort(
2541 _(b'cannot delete obsmarkers in the middle of transaction.')
2548 _(b'cannot delete obsmarkers in the middle of transaction.')
2542 )
2549 )
2543
2550
2544 with repo.lock():
2551 with repo.lock():
2545 n = repair.deleteobsmarkers(repo.obsstore, indices)
2552 n = repair.deleteobsmarkers(repo.obsstore, indices)
2546 ui.write(_(b'deleted %i obsolescence markers\n') % n)
2553 ui.write(_(b'deleted %i obsolescence markers\n') % n)
2547
2554
2548 return
2555 return
2549
2556
2550 if precursor is not None:
2557 if precursor is not None:
2551 if opts[b'rev']:
2558 if opts[b'rev']:
2552 raise error.InputError(
2559 raise error.InputError(
2553 b'cannot select revision when creating marker'
2560 b'cannot select revision when creating marker'
2554 )
2561 )
2555 metadata = {}
2562 metadata = {}
2556 metadata[b'user'] = encoding.fromlocal(opts[b'user'] or ui.username())
2563 metadata[b'user'] = encoding.fromlocal(opts[b'user'] or ui.username())
2557 succs = tuple(parsenodeid(succ) for succ in successors)
2564 succs = tuple(parsenodeid(succ) for succ in successors)
2558 l = repo.lock()
2565 l = repo.lock()
2559 try:
2566 try:
2560 tr = repo.transaction(b'debugobsolete')
2567 tr = repo.transaction(b'debugobsolete')
2561 try:
2568 try:
2562 date = opts.get(b'date')
2569 date = opts.get(b'date')
2563 if date:
2570 if date:
2564 date = dateutil.parsedate(date)
2571 date = dateutil.parsedate(date)
2565 else:
2572 else:
2566 date = None
2573 date = None
2567 prec = parsenodeid(precursor)
2574 prec = parsenodeid(precursor)
2568 parents = None
2575 parents = None
2569 if opts[b'record_parents']:
2576 if opts[b'record_parents']:
2570 if prec not in repo.unfiltered():
2577 if prec not in repo.unfiltered():
2571 raise error.Abort(
2578 raise error.Abort(
2572 b'cannot used --record-parents on '
2579 b'cannot used --record-parents on '
2573 b'unknown changesets'
2580 b'unknown changesets'
2574 )
2581 )
2575 parents = repo.unfiltered()[prec].parents()
2582 parents = repo.unfiltered()[prec].parents()
2576 parents = tuple(p.node() for p in parents)
2583 parents = tuple(p.node() for p in parents)
2577 repo.obsstore.create(
2584 repo.obsstore.create(
2578 tr,
2585 tr,
2579 prec,
2586 prec,
2580 succs,
2587 succs,
2581 opts[b'flags'],
2588 opts[b'flags'],
2582 parents=parents,
2589 parents=parents,
2583 date=date,
2590 date=date,
2584 metadata=metadata,
2591 metadata=metadata,
2585 ui=ui,
2592 ui=ui,
2586 )
2593 )
2587 tr.close()
2594 tr.close()
2588 except ValueError as exc:
2595 except ValueError as exc:
2589 raise error.Abort(
2596 raise error.Abort(
2590 _(b'bad obsmarker input: %s') % stringutil.forcebytestr(exc)
2597 _(b'bad obsmarker input: %s') % stringutil.forcebytestr(exc)
2591 )
2598 )
2592 finally:
2599 finally:
2593 tr.release()
2600 tr.release()
2594 finally:
2601 finally:
2595 l.release()
2602 l.release()
2596 else:
2603 else:
2597 if opts[b'rev']:
2604 if opts[b'rev']:
2598 revs = logcmdutil.revrange(repo, opts[b'rev'])
2605 revs = logcmdutil.revrange(repo, opts[b'rev'])
2599 nodes = [repo[r].node() for r in revs]
2606 nodes = [repo[r].node() for r in revs]
2600 markers = list(
2607 markers = list(
2601 obsutil.getmarkers(
2608 obsutil.getmarkers(
2602 repo, nodes=nodes, exclusive=opts[b'exclusive']
2609 repo, nodes=nodes, exclusive=opts[b'exclusive']
2603 )
2610 )
2604 )
2611 )
2605 markers.sort(key=lambda x: x._data)
2612 markers.sort(key=lambda x: x._data)
2606 else:
2613 else:
2607 markers = obsutil.getmarkers(repo)
2614 markers = obsutil.getmarkers(repo)
2608
2615
2609 markerstoiter = markers
2616 markerstoiter = markers
2610 isrelevant = lambda m: True
2617 isrelevant = lambda m: True
2611 if opts.get(b'rev') and opts.get(b'index'):
2618 if opts.get(b'rev') and opts.get(b'index'):
2612 markerstoiter = obsutil.getmarkers(repo)
2619 markerstoiter = obsutil.getmarkers(repo)
2613 markerset = set(markers)
2620 markerset = set(markers)
2614 isrelevant = lambda m: m in markerset
2621 isrelevant = lambda m: m in markerset
2615
2622
2616 fm = ui.formatter(b'debugobsolete', opts)
2623 fm = ui.formatter(b'debugobsolete', opts)
2617 for i, m in enumerate(markerstoiter):
2624 for i, m in enumerate(markerstoiter):
2618 if not isrelevant(m):
2625 if not isrelevant(m):
2619 # marker can be irrelevant when we're iterating over a set
2626 # marker can be irrelevant when we're iterating over a set
2620 # of markers (markerstoiter) which is bigger than the set
2627 # of markers (markerstoiter) which is bigger than the set
2621 # of markers we want to display (markers)
2628 # of markers we want to display (markers)
2622 # this can happen if both --index and --rev options are
2629 # this can happen if both --index and --rev options are
2623 # provided and thus we need to iterate over all of the markers
2630 # provided and thus we need to iterate over all of the markers
2624 # to get the correct indices, but only display the ones that
2631 # to get the correct indices, but only display the ones that
2625 # are relevant to --rev value
2632 # are relevant to --rev value
2626 continue
2633 continue
2627 fm.startitem()
2634 fm.startitem()
2628 ind = i if opts.get(b'index') else None
2635 ind = i if opts.get(b'index') else None
2629 cmdutil.showmarker(fm, m, index=ind)
2636 cmdutil.showmarker(fm, m, index=ind)
2630 fm.end()
2637 fm.end()
2631
2638
2632
2639
2633 @command(
2640 @command(
2634 b'debugp1copies',
2641 b'debugp1copies',
2635 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2642 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2636 _(b'[-r REV]'),
2643 _(b'[-r REV]'),
2637 )
2644 )
2638 def debugp1copies(ui, repo, **opts):
2645 def debugp1copies(ui, repo, **opts):
2639 """dump copy information compared to p1"""
2646 """dump copy information compared to p1"""
2640
2647
2641 opts = pycompat.byteskwargs(opts)
2648 opts = pycompat.byteskwargs(opts)
2642 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2649 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2643 for dst, src in ctx.p1copies().items():
2650 for dst, src in ctx.p1copies().items():
2644 ui.write(b'%s -> %s\n' % (src, dst))
2651 ui.write(b'%s -> %s\n' % (src, dst))
2645
2652
2646
2653
2647 @command(
2654 @command(
2648 b'debugp2copies',
2655 b'debugp2copies',
2649 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2656 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2650 _(b'[-r REV]'),
2657 _(b'[-r REV]'),
2651 )
2658 )
2652 def debugp1copies(ui, repo, **opts):
2659 def debugp1copies(ui, repo, **opts):
2653 """dump copy information compared to p2"""
2660 """dump copy information compared to p2"""
2654
2661
2655 opts = pycompat.byteskwargs(opts)
2662 opts = pycompat.byteskwargs(opts)
2656 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2663 ctx = scmutil.revsingle(repo, opts.get(b'rev'), default=None)
2657 for dst, src in ctx.p2copies().items():
2664 for dst, src in ctx.p2copies().items():
2658 ui.write(b'%s -> %s\n' % (src, dst))
2665 ui.write(b'%s -> %s\n' % (src, dst))
2659
2666
2660
2667
2661 @command(
2668 @command(
2662 b'debugpathcomplete',
2669 b'debugpathcomplete',
2663 [
2670 [
2664 (b'f', b'full', None, _(b'complete an entire path')),
2671 (b'f', b'full', None, _(b'complete an entire path')),
2665 (b'n', b'normal', None, _(b'show only normal files')),
2672 (b'n', b'normal', None, _(b'show only normal files')),
2666 (b'a', b'added', None, _(b'show only added files')),
2673 (b'a', b'added', None, _(b'show only added files')),
2667 (b'r', b'removed', None, _(b'show only removed files')),
2674 (b'r', b'removed', None, _(b'show only removed files')),
2668 ],
2675 ],
2669 _(b'FILESPEC...'),
2676 _(b'FILESPEC...'),
2670 )
2677 )
2671 def debugpathcomplete(ui, repo, *specs, **opts):
2678 def debugpathcomplete(ui, repo, *specs, **opts):
2672 """complete part or all of a tracked path
2679 """complete part or all of a tracked path
2673
2680
2674 This command supports shells that offer path name completion. It
2681 This command supports shells that offer path name completion. It
2675 currently completes only files already known to the dirstate.
2682 currently completes only files already known to the dirstate.
2676
2683
2677 Completion extends only to the next path segment unless
2684 Completion extends only to the next path segment unless
2678 --full is specified, in which case entire paths are used."""
2685 --full is specified, in which case entire paths are used."""
2679
2686
2680 def complete(path, acceptable):
2687 def complete(path, acceptable):
2681 dirstate = repo.dirstate
2688 dirstate = repo.dirstate
2682 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
2689 spec = os.path.normpath(os.path.join(encoding.getcwd(), path))
2683 rootdir = repo.root + pycompat.ossep
2690 rootdir = repo.root + pycompat.ossep
2684 if spec != repo.root and not spec.startswith(rootdir):
2691 if spec != repo.root and not spec.startswith(rootdir):
2685 return [], []
2692 return [], []
2686 if os.path.isdir(spec):
2693 if os.path.isdir(spec):
2687 spec += b'/'
2694 spec += b'/'
2688 spec = spec[len(rootdir) :]
2695 spec = spec[len(rootdir) :]
2689 fixpaths = pycompat.ossep != b'/'
2696 fixpaths = pycompat.ossep != b'/'
2690 if fixpaths:
2697 if fixpaths:
2691 spec = spec.replace(pycompat.ossep, b'/')
2698 spec = spec.replace(pycompat.ossep, b'/')
2692 speclen = len(spec)
2699 speclen = len(spec)
2693 fullpaths = opts['full']
2700 fullpaths = opts['full']
2694 files, dirs = set(), set()
2701 files, dirs = set(), set()
2695 adddir, addfile = dirs.add, files.add
2702 adddir, addfile = dirs.add, files.add
2696 for f, st in pycompat.iteritems(dirstate):
2703 for f, st in pycompat.iteritems(dirstate):
2697 if f.startswith(spec) and st.state in acceptable:
2704 if f.startswith(spec) and st.state in acceptable:
2698 if fixpaths:
2705 if fixpaths:
2699 f = f.replace(b'/', pycompat.ossep)
2706 f = f.replace(b'/', pycompat.ossep)
2700 if fullpaths:
2707 if fullpaths:
2701 addfile(f)
2708 addfile(f)
2702 continue
2709 continue
2703 s = f.find(pycompat.ossep, speclen)
2710 s = f.find(pycompat.ossep, speclen)
2704 if s >= 0:
2711 if s >= 0:
2705 adddir(f[:s])
2712 adddir(f[:s])
2706 else:
2713 else:
2707 addfile(f)
2714 addfile(f)
2708 return files, dirs
2715 return files, dirs
2709
2716
2710 acceptable = b''
2717 acceptable = b''
2711 if opts['normal']:
2718 if opts['normal']:
2712 acceptable += b'nm'
2719 acceptable += b'nm'
2713 if opts['added']:
2720 if opts['added']:
2714 acceptable += b'a'
2721 acceptable += b'a'
2715 if opts['removed']:
2722 if opts['removed']:
2716 acceptable += b'r'
2723 acceptable += b'r'
2717 cwd = repo.getcwd()
2724 cwd = repo.getcwd()
2718 if not specs:
2725 if not specs:
2719 specs = [b'.']
2726 specs = [b'.']
2720
2727
2721 files, dirs = set(), set()
2728 files, dirs = set(), set()
2722 for spec in specs:
2729 for spec in specs:
2723 f, d = complete(spec, acceptable or b'nmar')
2730 f, d = complete(spec, acceptable or b'nmar')
2724 files.update(f)
2731 files.update(f)
2725 dirs.update(d)
2732 dirs.update(d)
2726 files.update(dirs)
2733 files.update(dirs)
2727 ui.write(b'\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2734 ui.write(b'\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2728 ui.write(b'\n')
2735 ui.write(b'\n')
2729
2736
2730
2737
2731 @command(
2738 @command(
2732 b'debugpathcopies',
2739 b'debugpathcopies',
2733 cmdutil.walkopts,
2740 cmdutil.walkopts,
2734 b'hg debugpathcopies REV1 REV2 [FILE]',
2741 b'hg debugpathcopies REV1 REV2 [FILE]',
2735 inferrepo=True,
2742 inferrepo=True,
2736 )
2743 )
2737 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
2744 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
2738 """show copies between two revisions"""
2745 """show copies between two revisions"""
2739 ctx1 = scmutil.revsingle(repo, rev1)
2746 ctx1 = scmutil.revsingle(repo, rev1)
2740 ctx2 = scmutil.revsingle(repo, rev2)
2747 ctx2 = scmutil.revsingle(repo, rev2)
2741 m = scmutil.match(ctx1, pats, opts)
2748 m = scmutil.match(ctx1, pats, opts)
2742 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
2749 for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
2743 ui.write(b'%s -> %s\n' % (src, dst))
2750 ui.write(b'%s -> %s\n' % (src, dst))
2744
2751
2745
2752
2746 @command(b'debugpeer', [], _(b'PATH'), norepo=True)
2753 @command(b'debugpeer', [], _(b'PATH'), norepo=True)
2747 def debugpeer(ui, path):
2754 def debugpeer(ui, path):
2748 """establish a connection to a peer repository"""
2755 """establish a connection to a peer repository"""
2749 # Always enable peer request logging. Requires --debug to display
2756 # Always enable peer request logging. Requires --debug to display
2750 # though.
2757 # though.
2751 overrides = {
2758 overrides = {
2752 (b'devel', b'debug.peer-request'): True,
2759 (b'devel', b'debug.peer-request'): True,
2753 }
2760 }
2754
2761
2755 with ui.configoverride(overrides):
2762 with ui.configoverride(overrides):
2756 peer = hg.peer(ui, {}, path)
2763 peer = hg.peer(ui, {}, path)
2757
2764
2758 try:
2765 try:
2759 local = peer.local() is not None
2766 local = peer.local() is not None
2760 canpush = peer.canpush()
2767 canpush = peer.canpush()
2761
2768
2762 ui.write(_(b'url: %s\n') % peer.url())
2769 ui.write(_(b'url: %s\n') % peer.url())
2763 ui.write(_(b'local: %s\n') % (_(b'yes') if local else _(b'no')))
2770 ui.write(_(b'local: %s\n') % (_(b'yes') if local else _(b'no')))
2764 ui.write(
2771 ui.write(
2765 _(b'pushable: %s\n') % (_(b'yes') if canpush else _(b'no'))
2772 _(b'pushable: %s\n') % (_(b'yes') if canpush else _(b'no'))
2766 )
2773 )
2767 finally:
2774 finally:
2768 peer.close()
2775 peer.close()
2769
2776
2770
2777
2771 @command(
2778 @command(
2772 b'debugpickmergetool',
2779 b'debugpickmergetool',
2773 [
2780 [
2774 (b'r', b'rev', b'', _(b'check for files in this revision'), _(b'REV')),
2781 (b'r', b'rev', b'', _(b'check for files in this revision'), _(b'REV')),
2775 (b'', b'changedelete', None, _(b'emulate merging change and delete')),
2782 (b'', b'changedelete', None, _(b'emulate merging change and delete')),
2776 ]
2783 ]
2777 + cmdutil.walkopts
2784 + cmdutil.walkopts
2778 + cmdutil.mergetoolopts,
2785 + cmdutil.mergetoolopts,
2779 _(b'[PATTERN]...'),
2786 _(b'[PATTERN]...'),
2780 inferrepo=True,
2787 inferrepo=True,
2781 )
2788 )
2782 def debugpickmergetool(ui, repo, *pats, **opts):
2789 def debugpickmergetool(ui, repo, *pats, **opts):
2783 """examine which merge tool is chosen for specified file
2790 """examine which merge tool is chosen for specified file
2784
2791
2785 As described in :hg:`help merge-tools`, Mercurial examines
2792 As described in :hg:`help merge-tools`, Mercurial examines
2786 configurations below in this order to decide which merge tool is
2793 configurations below in this order to decide which merge tool is
2787 chosen for specified file.
2794 chosen for specified file.
2788
2795
2789 1. ``--tool`` option
2796 1. ``--tool`` option
2790 2. ``HGMERGE`` environment variable
2797 2. ``HGMERGE`` environment variable
2791 3. configurations in ``merge-patterns`` section
2798 3. configurations in ``merge-patterns`` section
2792 4. configuration of ``ui.merge``
2799 4. configuration of ``ui.merge``
2793 5. configurations in ``merge-tools`` section
2800 5. configurations in ``merge-tools`` section
2794 6. ``hgmerge`` tool (for historical reason only)
2801 6. ``hgmerge`` tool (for historical reason only)
2795 7. default tool for fallback (``:merge`` or ``:prompt``)
2802 7. default tool for fallback (``:merge`` or ``:prompt``)
2796
2803
2797 This command writes out examination result in the style below::
2804 This command writes out examination result in the style below::
2798
2805
2799 FILE = MERGETOOL
2806 FILE = MERGETOOL
2800
2807
2801 By default, all files known in the first parent context of the
2808 By default, all files known in the first parent context of the
2802 working directory are examined. Use file patterns and/or -I/-X
2809 working directory are examined. Use file patterns and/or -I/-X
2803 options to limit target files. -r/--rev is also useful to examine
2810 options to limit target files. -r/--rev is also useful to examine
2804 files in another context without actual updating to it.
2811 files in another context without actual updating to it.
2805
2812
2806 With --debug, this command shows warning messages while matching
2813 With --debug, this command shows warning messages while matching
2807 against ``merge-patterns`` and so on, too. It is recommended to
2814 against ``merge-patterns`` and so on, too. It is recommended to
2808 use this option with explicit file patterns and/or -I/-X options,
2815 use this option with explicit file patterns and/or -I/-X options,
2809 because this option increases amount of output per file according
2816 because this option increases amount of output per file according
2810 to configurations in hgrc.
2817 to configurations in hgrc.
2811
2818
2812 With -v/--verbose, this command shows configurations below at
2819 With -v/--verbose, this command shows configurations below at
2813 first (only if specified).
2820 first (only if specified).
2814
2821
2815 - ``--tool`` option
2822 - ``--tool`` option
2816 - ``HGMERGE`` environment variable
2823 - ``HGMERGE`` environment variable
2817 - configuration of ``ui.merge``
2824 - configuration of ``ui.merge``
2818
2825
2819 If merge tool is chosen before matching against
2826 If merge tool is chosen before matching against
2820 ``merge-patterns``, this command can't show any helpful
2827 ``merge-patterns``, this command can't show any helpful
2821 information, even with --debug. In such case, information above is
2828 information, even with --debug. In such case, information above is
2822 useful to know why a merge tool is chosen.
2829 useful to know why a merge tool is chosen.
2823 """
2830 """
2824 opts = pycompat.byteskwargs(opts)
2831 opts = pycompat.byteskwargs(opts)
2825 overrides = {}
2832 overrides = {}
2826 if opts[b'tool']:
2833 if opts[b'tool']:
2827 overrides[(b'ui', b'forcemerge')] = opts[b'tool']
2834 overrides[(b'ui', b'forcemerge')] = opts[b'tool']
2828 ui.notenoi18n(b'with --tool %r\n' % (pycompat.bytestr(opts[b'tool'])))
2835 ui.notenoi18n(b'with --tool %r\n' % (pycompat.bytestr(opts[b'tool'])))
2829
2836
2830 with ui.configoverride(overrides, b'debugmergepatterns'):
2837 with ui.configoverride(overrides, b'debugmergepatterns'):
2831 hgmerge = encoding.environ.get(b"HGMERGE")
2838 hgmerge = encoding.environ.get(b"HGMERGE")
2832 if hgmerge is not None:
2839 if hgmerge is not None:
2833 ui.notenoi18n(b'with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
2840 ui.notenoi18n(b'with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
2834 uimerge = ui.config(b"ui", b"merge")
2841 uimerge = ui.config(b"ui", b"merge")
2835 if uimerge:
2842 if uimerge:
2836 ui.notenoi18n(b'with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
2843 ui.notenoi18n(b'with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
2837
2844
2838 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2845 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2839 m = scmutil.match(ctx, pats, opts)
2846 m = scmutil.match(ctx, pats, opts)
2840 changedelete = opts[b'changedelete']
2847 changedelete = opts[b'changedelete']
2841 for path in ctx.walk(m):
2848 for path in ctx.walk(m):
2842 fctx = ctx[path]
2849 fctx = ctx[path]
2843 with ui.silent(
2850 with ui.silent(
2844 error=True
2851 error=True
2845 ) if not ui.debugflag else util.nullcontextmanager():
2852 ) if not ui.debugflag else util.nullcontextmanager():
2846 tool, toolpath = filemerge._picktool(
2853 tool, toolpath = filemerge._picktool(
2847 repo,
2854 repo,
2848 ui,
2855 ui,
2849 path,
2856 path,
2850 fctx.isbinary(),
2857 fctx.isbinary(),
2851 b'l' in fctx.flags(),
2858 b'l' in fctx.flags(),
2852 changedelete,
2859 changedelete,
2853 )
2860 )
2854 ui.write(b'%s = %s\n' % (path, tool))
2861 ui.write(b'%s = %s\n' % (path, tool))
2855
2862
2856
2863
2857 @command(b'debugpushkey', [], _(b'REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2864 @command(b'debugpushkey', [], _(b'REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2858 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2865 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2859 """access the pushkey key/value protocol
2866 """access the pushkey key/value protocol
2860
2867
2861 With two args, list the keys in the given namespace.
2868 With two args, list the keys in the given namespace.
2862
2869
2863 With five args, set a key to new if it currently is set to old.
2870 With five args, set a key to new if it currently is set to old.
2864 Reports success or failure.
2871 Reports success or failure.
2865 """
2872 """
2866
2873
2867 target = hg.peer(ui, {}, repopath)
2874 target = hg.peer(ui, {}, repopath)
2868 try:
2875 try:
2869 if keyinfo:
2876 if keyinfo:
2870 key, old, new = keyinfo
2877 key, old, new = keyinfo
2871 with target.commandexecutor() as e:
2878 with target.commandexecutor() as e:
2872 r = e.callcommand(
2879 r = e.callcommand(
2873 b'pushkey',
2880 b'pushkey',
2874 {
2881 {
2875 b'namespace': namespace,
2882 b'namespace': namespace,
2876 b'key': key,
2883 b'key': key,
2877 b'old': old,
2884 b'old': old,
2878 b'new': new,
2885 b'new': new,
2879 },
2886 },
2880 ).result()
2887 ).result()
2881
2888
2882 ui.status(pycompat.bytestr(r) + b'\n')
2889 ui.status(pycompat.bytestr(r) + b'\n')
2883 return not r
2890 return not r
2884 else:
2891 else:
2885 for k, v in sorted(pycompat.iteritems(target.listkeys(namespace))):
2892 for k, v in sorted(pycompat.iteritems(target.listkeys(namespace))):
2886 ui.write(
2893 ui.write(
2887 b"%s\t%s\n"
2894 b"%s\t%s\n"
2888 % (stringutil.escapestr(k), stringutil.escapestr(v))
2895 % (stringutil.escapestr(k), stringutil.escapestr(v))
2889 )
2896 )
2890 finally:
2897 finally:
2891 target.close()
2898 target.close()
2892
2899
2893
2900
2894 @command(b'debugpvec', [], _(b'A B'))
2901 @command(b'debugpvec', [], _(b'A B'))
2895 def debugpvec(ui, repo, a, b=None):
2902 def debugpvec(ui, repo, a, b=None):
2896 ca = scmutil.revsingle(repo, a)
2903 ca = scmutil.revsingle(repo, a)
2897 cb = scmutil.revsingle(repo, b)
2904 cb = scmutil.revsingle(repo, b)
2898 pa = pvec.ctxpvec(ca)
2905 pa = pvec.ctxpvec(ca)
2899 pb = pvec.ctxpvec(cb)
2906 pb = pvec.ctxpvec(cb)
2900 if pa == pb:
2907 if pa == pb:
2901 rel = b"="
2908 rel = b"="
2902 elif pa > pb:
2909 elif pa > pb:
2903 rel = b">"
2910 rel = b">"
2904 elif pa < pb:
2911 elif pa < pb:
2905 rel = b"<"
2912 rel = b"<"
2906 elif pa | pb:
2913 elif pa | pb:
2907 rel = b"|"
2914 rel = b"|"
2908 ui.write(_(b"a: %s\n") % pa)
2915 ui.write(_(b"a: %s\n") % pa)
2909 ui.write(_(b"b: %s\n") % pb)
2916 ui.write(_(b"b: %s\n") % pb)
2910 ui.write(_(b"depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2917 ui.write(_(b"depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2911 ui.write(
2918 ui.write(
2912 _(b"delta: %d hdist: %d distance: %d relation: %s\n")
2919 _(b"delta: %d hdist: %d distance: %d relation: %s\n")
2913 % (
2920 % (
2914 abs(pa._depth - pb._depth),
2921 abs(pa._depth - pb._depth),
2915 pvec._hamming(pa._vec, pb._vec),
2922 pvec._hamming(pa._vec, pb._vec),
2916 pa.distance(pb),
2923 pa.distance(pb),
2917 rel,
2924 rel,
2918 )
2925 )
2919 )
2926 )
2920
2927
2921
2928
2922 @command(
2929 @command(
2923 b'debugrebuilddirstate|debugrebuildstate',
2930 b'debugrebuilddirstate|debugrebuildstate',
2924 [
2931 [
2925 (b'r', b'rev', b'', _(b'revision to rebuild to'), _(b'REV')),
2932 (b'r', b'rev', b'', _(b'revision to rebuild to'), _(b'REV')),
2926 (
2933 (
2927 b'',
2934 b'',
2928 b'minimal',
2935 b'minimal',
2929 None,
2936 None,
2930 _(
2937 _(
2931 b'only rebuild files that are inconsistent with '
2938 b'only rebuild files that are inconsistent with '
2932 b'the working copy parent'
2939 b'the working copy parent'
2933 ),
2940 ),
2934 ),
2941 ),
2935 ],
2942 ],
2936 _(b'[-r REV]'),
2943 _(b'[-r REV]'),
2937 )
2944 )
2938 def debugrebuilddirstate(ui, repo, rev, **opts):
2945 def debugrebuilddirstate(ui, repo, rev, **opts):
2939 """rebuild the dirstate as it would look like for the given revision
2946 """rebuild the dirstate as it would look like for the given revision
2940
2947
2941 If no revision is specified the first current parent will be used.
2948 If no revision is specified the first current parent will be used.
2942
2949
2943 The dirstate will be set to the files of the given revision.
2950 The dirstate will be set to the files of the given revision.
2944 The actual working directory content or existing dirstate
2951 The actual working directory content or existing dirstate
2945 information such as adds or removes is not considered.
2952 information such as adds or removes is not considered.
2946
2953
2947 ``minimal`` will only rebuild the dirstate status for files that claim to be
2954 ``minimal`` will only rebuild the dirstate status for files that claim to be
2948 tracked but are not in the parent manifest, or that exist in the parent
2955 tracked but are not in the parent manifest, or that exist in the parent
2949 manifest but are not in the dirstate. It will not change adds, removes, or
2956 manifest but are not in the dirstate. It will not change adds, removes, or
2950 modified files that are in the working copy parent.
2957 modified files that are in the working copy parent.
2951
2958
2952 One use of this command is to make the next :hg:`status` invocation
2959 One use of this command is to make the next :hg:`status` invocation
2953 check the actual file content.
2960 check the actual file content.
2954 """
2961 """
2955 ctx = scmutil.revsingle(repo, rev)
2962 ctx = scmutil.revsingle(repo, rev)
2956 with repo.wlock():
2963 with repo.wlock():
2957 dirstate = repo.dirstate
2964 dirstate = repo.dirstate
2958 changedfiles = None
2965 changedfiles = None
2959 # See command doc for what minimal does.
2966 # See command doc for what minimal does.
2960 if opts.get('minimal'):
2967 if opts.get('minimal'):
2961 manifestfiles = set(ctx.manifest().keys())
2968 manifestfiles = set(ctx.manifest().keys())
2962 dirstatefiles = set(dirstate)
2969 dirstatefiles = set(dirstate)
2963 manifestonly = manifestfiles - dirstatefiles
2970 manifestonly = manifestfiles - dirstatefiles
2964 dsonly = dirstatefiles - manifestfiles
2971 dsonly = dirstatefiles - manifestfiles
2965 dsnotadded = {f for f in dsonly if not dirstate.get_entry(f).added}
2972 dsnotadded = {f for f in dsonly if not dirstate.get_entry(f).added}
2966 changedfiles = manifestonly | dsnotadded
2973 changedfiles = manifestonly | dsnotadded
2967
2974
2968 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2975 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
2969
2976
2970
2977
2971 @command(
2978 @command(
2972 b'debugrebuildfncache',
2979 b'debugrebuildfncache',
2973 [
2980 [
2974 (
2981 (
2975 b'',
2982 b'',
2976 b'only-data',
2983 b'only-data',
2977 False,
2984 False,
2978 _(b'only look for wrong .d files (much faster)'),
2985 _(b'only look for wrong .d files (much faster)'),
2979 )
2986 )
2980 ],
2987 ],
2981 b'',
2988 b'',
2982 )
2989 )
2983 def debugrebuildfncache(ui, repo, **opts):
2990 def debugrebuildfncache(ui, repo, **opts):
2984 """rebuild the fncache file"""
2991 """rebuild the fncache file"""
2985 opts = pycompat.byteskwargs(opts)
2992 opts = pycompat.byteskwargs(opts)
2986 repair.rebuildfncache(ui, repo, opts.get(b"only_data"))
2993 repair.rebuildfncache(ui, repo, opts.get(b"only_data"))
2987
2994
2988
2995
2989 @command(
2996 @command(
2990 b'debugrename',
2997 b'debugrename',
2991 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2998 [(b'r', b'rev', b'', _(b'revision to debug'), _(b'REV'))],
2992 _(b'[-r REV] [FILE]...'),
2999 _(b'[-r REV] [FILE]...'),
2993 )
3000 )
2994 def debugrename(ui, repo, *pats, **opts):
3001 def debugrename(ui, repo, *pats, **opts):
2995 """dump rename information"""
3002 """dump rename information"""
2996
3003
2997 opts = pycompat.byteskwargs(opts)
3004 opts = pycompat.byteskwargs(opts)
2998 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
3005 ctx = scmutil.revsingle(repo, opts.get(b'rev'))
2999 m = scmutil.match(ctx, pats, opts)
3006 m = scmutil.match(ctx, pats, opts)
3000 for abs in ctx.walk(m):
3007 for abs in ctx.walk(m):
3001 fctx = ctx[abs]
3008 fctx = ctx[abs]
3002 o = fctx.filelog().renamed(fctx.filenode())
3009 o = fctx.filelog().renamed(fctx.filenode())
3003 rel = repo.pathto(abs)
3010 rel = repo.pathto(abs)
3004 if o:
3011 if o:
3005 ui.write(_(b"%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3012 ui.write(_(b"%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3006 else:
3013 else:
3007 ui.write(_(b"%s not renamed\n") % rel)
3014 ui.write(_(b"%s not renamed\n") % rel)
3008
3015
3009
3016
3010 @command(b'debugrequires|debugrequirements', [], b'')
3017 @command(b'debugrequires|debugrequirements', [], b'')
3011 def debugrequirements(ui, repo):
3018 def debugrequirements(ui, repo):
3012 """print the current repo requirements"""
3019 """print the current repo requirements"""
3013 for r in sorted(repo.requirements):
3020 for r in sorted(repo.requirements):
3014 ui.write(b"%s\n" % r)
3021 ui.write(b"%s\n" % r)
3015
3022
3016
3023
3017 @command(
3024 @command(
3018 b'debugrevlog',
3025 b'debugrevlog',
3019 cmdutil.debugrevlogopts + [(b'd', b'dump', False, _(b'dump index data'))],
3026 cmdutil.debugrevlogopts + [(b'd', b'dump', False, _(b'dump index data'))],
3020 _(b'-c|-m|FILE'),
3027 _(b'-c|-m|FILE'),
3021 optionalrepo=True,
3028 optionalrepo=True,
3022 )
3029 )
3023 def debugrevlog(ui, repo, file_=None, **opts):
3030 def debugrevlog(ui, repo, file_=None, **opts):
3024 """show data and statistics about a revlog"""
3031 """show data and statistics about a revlog"""
3025 opts = pycompat.byteskwargs(opts)
3032 opts = pycompat.byteskwargs(opts)
3026 r = cmdutil.openrevlog(repo, b'debugrevlog', file_, opts)
3033 r = cmdutil.openrevlog(repo, b'debugrevlog', file_, opts)
3027
3034
3028 if opts.get(b"dump"):
3035 if opts.get(b"dump"):
3029 numrevs = len(r)
3036 numrevs = len(r)
3030 ui.write(
3037 ui.write(
3031 (
3038 (
3032 b"# rev p1rev p2rev start end deltastart base p1 p2"
3039 b"# rev p1rev p2rev start end deltastart base p1 p2"
3033 b" rawsize totalsize compression heads chainlen\n"
3040 b" rawsize totalsize compression heads chainlen\n"
3034 )
3041 )
3035 )
3042 )
3036 ts = 0
3043 ts = 0
3037 heads = set()
3044 heads = set()
3038
3045
3039 for rev in pycompat.xrange(numrevs):
3046 for rev in pycompat.xrange(numrevs):
3040 dbase = r.deltaparent(rev)
3047 dbase = r.deltaparent(rev)
3041 if dbase == -1:
3048 if dbase == -1:
3042 dbase = rev
3049 dbase = rev
3043 cbase = r.chainbase(rev)
3050 cbase = r.chainbase(rev)
3044 clen = r.chainlen(rev)
3051 clen = r.chainlen(rev)
3045 p1, p2 = r.parentrevs(rev)
3052 p1, p2 = r.parentrevs(rev)
3046 rs = r.rawsize(rev)
3053 rs = r.rawsize(rev)
3047 ts = ts + rs
3054 ts = ts + rs
3048 heads -= set(r.parentrevs(rev))
3055 heads -= set(r.parentrevs(rev))
3049 heads.add(rev)
3056 heads.add(rev)
3050 try:
3057 try:
3051 compression = ts / r.end(rev)
3058 compression = ts / r.end(rev)
3052 except ZeroDivisionError:
3059 except ZeroDivisionError:
3053 compression = 0
3060 compression = 0
3054 ui.write(
3061 ui.write(
3055 b"%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3062 b"%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3056 b"%11d %5d %8d\n"
3063 b"%11d %5d %8d\n"
3057 % (
3064 % (
3058 rev,
3065 rev,
3059 p1,
3066 p1,
3060 p2,
3067 p2,
3061 r.start(rev),
3068 r.start(rev),
3062 r.end(rev),
3069 r.end(rev),
3063 r.start(dbase),
3070 r.start(dbase),
3064 r.start(cbase),
3071 r.start(cbase),
3065 r.start(p1),
3072 r.start(p1),
3066 r.start(p2),
3073 r.start(p2),
3067 rs,
3074 rs,
3068 ts,
3075 ts,
3069 compression,
3076 compression,
3070 len(heads),
3077 len(heads),
3071 clen,
3078 clen,
3072 )
3079 )
3073 )
3080 )
3074 return 0
3081 return 0
3075
3082
3076 format = r._format_version
3083 format = r._format_version
3077 v = r._format_flags
3084 v = r._format_flags
3078 flags = []
3085 flags = []
3079 gdelta = False
3086 gdelta = False
3080 if v & revlog.FLAG_INLINE_DATA:
3087 if v & revlog.FLAG_INLINE_DATA:
3081 flags.append(b'inline')
3088 flags.append(b'inline')
3082 if v & revlog.FLAG_GENERALDELTA:
3089 if v & revlog.FLAG_GENERALDELTA:
3083 gdelta = True
3090 gdelta = True
3084 flags.append(b'generaldelta')
3091 flags.append(b'generaldelta')
3085 if not flags:
3092 if not flags:
3086 flags = [b'(none)']
3093 flags = [b'(none)']
3087
3094
3088 ### tracks merge vs single parent
3095 ### tracks merge vs single parent
3089 nummerges = 0
3096 nummerges = 0
3090
3097
3091 ### tracks ways the "delta" are build
3098 ### tracks ways the "delta" are build
3092 # nodelta
3099 # nodelta
3093 numempty = 0
3100 numempty = 0
3094 numemptytext = 0
3101 numemptytext = 0
3095 numemptydelta = 0
3102 numemptydelta = 0
3096 # full file content
3103 # full file content
3097 numfull = 0
3104 numfull = 0
3098 # intermediate snapshot against a prior snapshot
3105 # intermediate snapshot against a prior snapshot
3099 numsemi = 0
3106 numsemi = 0
3100 # snapshot count per depth
3107 # snapshot count per depth
3101 numsnapdepth = collections.defaultdict(lambda: 0)
3108 numsnapdepth = collections.defaultdict(lambda: 0)
3102 # delta against previous revision
3109 # delta against previous revision
3103 numprev = 0
3110 numprev = 0
3104 # delta against first or second parent (not prev)
3111 # delta against first or second parent (not prev)
3105 nump1 = 0
3112 nump1 = 0
3106 nump2 = 0
3113 nump2 = 0
3107 # delta against neither prev nor parents
3114 # delta against neither prev nor parents
3108 numother = 0
3115 numother = 0
3109 # delta against prev that are also first or second parent
3116 # delta against prev that are also first or second parent
3110 # (details of `numprev`)
3117 # (details of `numprev`)
3111 nump1prev = 0
3118 nump1prev = 0
3112 nump2prev = 0
3119 nump2prev = 0
3113
3120
3114 # data about delta chain of each revs
3121 # data about delta chain of each revs
3115 chainlengths = []
3122 chainlengths = []
3116 chainbases = []
3123 chainbases = []
3117 chainspans = []
3124 chainspans = []
3118
3125
3119 # data about each revision
3126 # data about each revision
3120 datasize = [None, 0, 0]
3127 datasize = [None, 0, 0]
3121 fullsize = [None, 0, 0]
3128 fullsize = [None, 0, 0]
3122 semisize = [None, 0, 0]
3129 semisize = [None, 0, 0]
3123 # snapshot count per depth
3130 # snapshot count per depth
3124 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
3131 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
3125 deltasize = [None, 0, 0]
3132 deltasize = [None, 0, 0]
3126 chunktypecounts = {}
3133 chunktypecounts = {}
3127 chunktypesizes = {}
3134 chunktypesizes = {}
3128
3135
3129 def addsize(size, l):
3136 def addsize(size, l):
3130 if l[0] is None or size < l[0]:
3137 if l[0] is None or size < l[0]:
3131 l[0] = size
3138 l[0] = size
3132 if size > l[1]:
3139 if size > l[1]:
3133 l[1] = size
3140 l[1] = size
3134 l[2] += size
3141 l[2] += size
3135
3142
3136 numrevs = len(r)
3143 numrevs = len(r)
3137 for rev in pycompat.xrange(numrevs):
3144 for rev in pycompat.xrange(numrevs):
3138 p1, p2 = r.parentrevs(rev)
3145 p1, p2 = r.parentrevs(rev)
3139 delta = r.deltaparent(rev)
3146 delta = r.deltaparent(rev)
3140 if format > 0:
3147 if format > 0:
3141 addsize(r.rawsize(rev), datasize)
3148 addsize(r.rawsize(rev), datasize)
3142 if p2 != nullrev:
3149 if p2 != nullrev:
3143 nummerges += 1
3150 nummerges += 1
3144 size = r.length(rev)
3151 size = r.length(rev)
3145 if delta == nullrev:
3152 if delta == nullrev:
3146 chainlengths.append(0)
3153 chainlengths.append(0)
3147 chainbases.append(r.start(rev))
3154 chainbases.append(r.start(rev))
3148 chainspans.append(size)
3155 chainspans.append(size)
3149 if size == 0:
3156 if size == 0:
3150 numempty += 1
3157 numempty += 1
3151 numemptytext += 1
3158 numemptytext += 1
3152 else:
3159 else:
3153 numfull += 1
3160 numfull += 1
3154 numsnapdepth[0] += 1
3161 numsnapdepth[0] += 1
3155 addsize(size, fullsize)
3162 addsize(size, fullsize)
3156 addsize(size, snapsizedepth[0])
3163 addsize(size, snapsizedepth[0])
3157 else:
3164 else:
3158 chainlengths.append(chainlengths[delta] + 1)
3165 chainlengths.append(chainlengths[delta] + 1)
3159 baseaddr = chainbases[delta]
3166 baseaddr = chainbases[delta]
3160 revaddr = r.start(rev)
3167 revaddr = r.start(rev)
3161 chainbases.append(baseaddr)
3168 chainbases.append(baseaddr)
3162 chainspans.append((revaddr - baseaddr) + size)
3169 chainspans.append((revaddr - baseaddr) + size)
3163 if size == 0:
3170 if size == 0:
3164 numempty += 1
3171 numempty += 1
3165 numemptydelta += 1
3172 numemptydelta += 1
3166 elif r.issnapshot(rev):
3173 elif r.issnapshot(rev):
3167 addsize(size, semisize)
3174 addsize(size, semisize)
3168 numsemi += 1
3175 numsemi += 1
3169 depth = r.snapshotdepth(rev)
3176 depth = r.snapshotdepth(rev)
3170 numsnapdepth[depth] += 1
3177 numsnapdepth[depth] += 1
3171 addsize(size, snapsizedepth[depth])
3178 addsize(size, snapsizedepth[depth])
3172 else:
3179 else:
3173 addsize(size, deltasize)
3180 addsize(size, deltasize)
3174 if delta == rev - 1:
3181 if delta == rev - 1:
3175 numprev += 1
3182 numprev += 1
3176 if delta == p1:
3183 if delta == p1:
3177 nump1prev += 1
3184 nump1prev += 1
3178 elif delta == p2:
3185 elif delta == p2:
3179 nump2prev += 1
3186 nump2prev += 1
3180 elif delta == p1:
3187 elif delta == p1:
3181 nump1 += 1
3188 nump1 += 1
3182 elif delta == p2:
3189 elif delta == p2:
3183 nump2 += 1
3190 nump2 += 1
3184 elif delta != nullrev:
3191 elif delta != nullrev:
3185 numother += 1
3192 numother += 1
3186
3193
3187 # Obtain data on the raw chunks in the revlog.
3194 # Obtain data on the raw chunks in the revlog.
3188 if util.safehasattr(r, b'_getsegmentforrevs'):
3195 if util.safehasattr(r, b'_getsegmentforrevs'):
3189 segment = r._getsegmentforrevs(rev, rev)[1]
3196 segment = r._getsegmentforrevs(rev, rev)[1]
3190 else:
3197 else:
3191 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
3198 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
3192 if segment:
3199 if segment:
3193 chunktype = bytes(segment[0:1])
3200 chunktype = bytes(segment[0:1])
3194 else:
3201 else:
3195 chunktype = b'empty'
3202 chunktype = b'empty'
3196
3203
3197 if chunktype not in chunktypecounts:
3204 if chunktype not in chunktypecounts:
3198 chunktypecounts[chunktype] = 0
3205 chunktypecounts[chunktype] = 0
3199 chunktypesizes[chunktype] = 0
3206 chunktypesizes[chunktype] = 0
3200
3207
3201 chunktypecounts[chunktype] += 1
3208 chunktypecounts[chunktype] += 1
3202 chunktypesizes[chunktype] += size
3209 chunktypesizes[chunktype] += size
3203
3210
3204 # Adjust size min value for empty cases
3211 # Adjust size min value for empty cases
3205 for size in (datasize, fullsize, semisize, deltasize):
3212 for size in (datasize, fullsize, semisize, deltasize):
3206 if size[0] is None:
3213 if size[0] is None:
3207 size[0] = 0
3214 size[0] = 0
3208
3215
3209 numdeltas = numrevs - numfull - numempty - numsemi
3216 numdeltas = numrevs - numfull - numempty - numsemi
3210 numoprev = numprev - nump1prev - nump2prev
3217 numoprev = numprev - nump1prev - nump2prev
3211 totalrawsize = datasize[2]
3218 totalrawsize = datasize[2]
3212 datasize[2] /= numrevs
3219 datasize[2] /= numrevs
3213 fulltotal = fullsize[2]
3220 fulltotal = fullsize[2]
3214 if numfull == 0:
3221 if numfull == 0:
3215 fullsize[2] = 0
3222 fullsize[2] = 0
3216 else:
3223 else:
3217 fullsize[2] /= numfull
3224 fullsize[2] /= numfull
3218 semitotal = semisize[2]
3225 semitotal = semisize[2]
3219 snaptotal = {}
3226 snaptotal = {}
3220 if numsemi > 0:
3227 if numsemi > 0:
3221 semisize[2] /= numsemi
3228 semisize[2] /= numsemi
3222 for depth in snapsizedepth:
3229 for depth in snapsizedepth:
3223 snaptotal[depth] = snapsizedepth[depth][2]
3230 snaptotal[depth] = snapsizedepth[depth][2]
3224 snapsizedepth[depth][2] /= numsnapdepth[depth]
3231 snapsizedepth[depth][2] /= numsnapdepth[depth]
3225
3232
3226 deltatotal = deltasize[2]
3233 deltatotal = deltasize[2]
3227 if numdeltas > 0:
3234 if numdeltas > 0:
3228 deltasize[2] /= numdeltas
3235 deltasize[2] /= numdeltas
3229 totalsize = fulltotal + semitotal + deltatotal
3236 totalsize = fulltotal + semitotal + deltatotal
3230 avgchainlen = sum(chainlengths) / numrevs
3237 avgchainlen = sum(chainlengths) / numrevs
3231 maxchainlen = max(chainlengths)
3238 maxchainlen = max(chainlengths)
3232 maxchainspan = max(chainspans)
3239 maxchainspan = max(chainspans)
3233 compratio = 1
3240 compratio = 1
3234 if totalsize:
3241 if totalsize:
3235 compratio = totalrawsize / totalsize
3242 compratio = totalrawsize / totalsize
3236
3243
3237 basedfmtstr = b'%%%dd\n'
3244 basedfmtstr = b'%%%dd\n'
3238 basepcfmtstr = b'%%%dd %s(%%5.2f%%%%)\n'
3245 basepcfmtstr = b'%%%dd %s(%%5.2f%%%%)\n'
3239
3246
3240 def dfmtstr(max):
3247 def dfmtstr(max):
3241 return basedfmtstr % len(str(max))
3248 return basedfmtstr % len(str(max))
3242
3249
3243 def pcfmtstr(max, padding=0):
3250 def pcfmtstr(max, padding=0):
3244 return basepcfmtstr % (len(str(max)), b' ' * padding)
3251 return basepcfmtstr % (len(str(max)), b' ' * padding)
3245
3252
3246 def pcfmt(value, total):
3253 def pcfmt(value, total):
3247 if total:
3254 if total:
3248 return (value, 100 * float(value) / total)
3255 return (value, 100 * float(value) / total)
3249 else:
3256 else:
3250 return value, 100.0
3257 return value, 100.0
3251
3258
3252 ui.writenoi18n(b'format : %d\n' % format)
3259 ui.writenoi18n(b'format : %d\n' % format)
3253 ui.writenoi18n(b'flags : %s\n' % b', '.join(flags))
3260 ui.writenoi18n(b'flags : %s\n' % b', '.join(flags))
3254
3261
3255 ui.write(b'\n')
3262 ui.write(b'\n')
3256 fmt = pcfmtstr(totalsize)
3263 fmt = pcfmtstr(totalsize)
3257 fmt2 = dfmtstr(totalsize)
3264 fmt2 = dfmtstr(totalsize)
3258 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3265 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3259 ui.writenoi18n(b' merges : ' + fmt % pcfmt(nummerges, numrevs))
3266 ui.writenoi18n(b' merges : ' + fmt % pcfmt(nummerges, numrevs))
3260 ui.writenoi18n(
3267 ui.writenoi18n(
3261 b' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)
3268 b' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)
3262 )
3269 )
3263 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3270 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
3264 ui.writenoi18n(b' empty : ' + fmt % pcfmt(numempty, numrevs))
3271 ui.writenoi18n(b' empty : ' + fmt % pcfmt(numempty, numrevs))
3265 ui.writenoi18n(
3272 ui.writenoi18n(
3266 b' text : '
3273 b' text : '
3267 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
3274 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
3268 )
3275 )
3269 ui.writenoi18n(
3276 ui.writenoi18n(
3270 b' delta : '
3277 b' delta : '
3271 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
3278 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
3272 )
3279 )
3273 ui.writenoi18n(
3280 ui.writenoi18n(
3274 b' snapshot : ' + fmt % pcfmt(numfull + numsemi, numrevs)
3281 b' snapshot : ' + fmt % pcfmt(numfull + numsemi, numrevs)
3275 )
3282 )
3276 for depth in sorted(numsnapdepth):
3283 for depth in sorted(numsnapdepth):
3277 ui.write(
3284 ui.write(
3278 (b' lvl-%-3d : ' % depth)
3285 (b' lvl-%-3d : ' % depth)
3279 + fmt % pcfmt(numsnapdepth[depth], numrevs)
3286 + fmt % pcfmt(numsnapdepth[depth], numrevs)
3280 )
3287 )
3281 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
3288 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
3282 ui.writenoi18n(b'revision size : ' + fmt2 % totalsize)
3289 ui.writenoi18n(b'revision size : ' + fmt2 % totalsize)
3283 ui.writenoi18n(
3290 ui.writenoi18n(
3284 b' snapshot : ' + fmt % pcfmt(fulltotal + semitotal, totalsize)
3291 b' snapshot : ' + fmt % pcfmt(fulltotal + semitotal, totalsize)
3285 )
3292 )
3286 for depth in sorted(numsnapdepth):
3293 for depth in sorted(numsnapdepth):
3287 ui.write(
3294 ui.write(
3288 (b' lvl-%-3d : ' % depth)
3295 (b' lvl-%-3d : ' % depth)
3289 + fmt % pcfmt(snaptotal[depth], totalsize)
3296 + fmt % pcfmt(snaptotal[depth], totalsize)
3290 )
3297 )
3291 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
3298 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
3292
3299
3293 def fmtchunktype(chunktype):
3300 def fmtchunktype(chunktype):
3294 if chunktype == b'empty':
3301 if chunktype == b'empty':
3295 return b' %s : ' % chunktype
3302 return b' %s : ' % chunktype
3296 elif chunktype in pycompat.bytestr(string.ascii_letters):
3303 elif chunktype in pycompat.bytestr(string.ascii_letters):
3297 return b' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3304 return b' 0x%s (%s) : ' % (hex(chunktype), chunktype)
3298 else:
3305 else:
3299 return b' 0x%s : ' % hex(chunktype)
3306 return b' 0x%s : ' % hex(chunktype)
3300
3307
3301 ui.write(b'\n')
3308 ui.write(b'\n')
3302 ui.writenoi18n(b'chunks : ' + fmt2 % numrevs)
3309 ui.writenoi18n(b'chunks : ' + fmt2 % numrevs)
3303 for chunktype in sorted(chunktypecounts):
3310 for chunktype in sorted(chunktypecounts):
3304 ui.write(fmtchunktype(chunktype))
3311 ui.write(fmtchunktype(chunktype))
3305 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3312 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
3306 ui.writenoi18n(b'chunks size : ' + fmt2 % totalsize)
3313 ui.writenoi18n(b'chunks size : ' + fmt2 % totalsize)
3307 for chunktype in sorted(chunktypecounts):
3314 for chunktype in sorted(chunktypecounts):
3308 ui.write(fmtchunktype(chunktype))
3315 ui.write(fmtchunktype(chunktype))
3309 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3316 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
3310
3317
3311 ui.write(b'\n')
3318 ui.write(b'\n')
3312 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
3319 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
3313 ui.writenoi18n(b'avg chain length : ' + fmt % avgchainlen)
3320 ui.writenoi18n(b'avg chain length : ' + fmt % avgchainlen)
3314 ui.writenoi18n(b'max chain length : ' + fmt % maxchainlen)
3321 ui.writenoi18n(b'max chain length : ' + fmt % maxchainlen)
3315 ui.writenoi18n(b'max chain reach : ' + fmt % maxchainspan)
3322 ui.writenoi18n(b'max chain reach : ' + fmt % maxchainspan)
3316 ui.writenoi18n(b'compression ratio : ' + fmt % compratio)
3323 ui.writenoi18n(b'compression ratio : ' + fmt % compratio)
3317
3324
3318 if format > 0:
3325 if format > 0:
3319 ui.write(b'\n')
3326 ui.write(b'\n')
3320 ui.writenoi18n(
3327 ui.writenoi18n(
3321 b'uncompressed data size (min/max/avg) : %d / %d / %d\n'
3328 b'uncompressed data size (min/max/avg) : %d / %d / %d\n'
3322 % tuple(datasize)
3329 % tuple(datasize)
3323 )
3330 )
3324 ui.writenoi18n(
3331 ui.writenoi18n(
3325 b'full revision size (min/max/avg) : %d / %d / %d\n'
3332 b'full revision size (min/max/avg) : %d / %d / %d\n'
3326 % tuple(fullsize)
3333 % tuple(fullsize)
3327 )
3334 )
3328 ui.writenoi18n(
3335 ui.writenoi18n(
3329 b'inter-snapshot size (min/max/avg) : %d / %d / %d\n'
3336 b'inter-snapshot size (min/max/avg) : %d / %d / %d\n'
3330 % tuple(semisize)
3337 % tuple(semisize)
3331 )
3338 )
3332 for depth in sorted(snapsizedepth):
3339 for depth in sorted(snapsizedepth):
3333 if depth == 0:
3340 if depth == 0:
3334 continue
3341 continue
3335 ui.writenoi18n(
3342 ui.writenoi18n(
3336 b' level-%-3d (min/max/avg) : %d / %d / %d\n'
3343 b' level-%-3d (min/max/avg) : %d / %d / %d\n'
3337 % ((depth,) + tuple(snapsizedepth[depth]))
3344 % ((depth,) + tuple(snapsizedepth[depth]))
3338 )
3345 )
3339 ui.writenoi18n(
3346 ui.writenoi18n(
3340 b'delta size (min/max/avg) : %d / %d / %d\n'
3347 b'delta size (min/max/avg) : %d / %d / %d\n'
3341 % tuple(deltasize)
3348 % tuple(deltasize)
3342 )
3349 )
3343
3350
3344 if numdeltas > 0:
3351 if numdeltas > 0:
3345 ui.write(b'\n')
3352 ui.write(b'\n')
3346 fmt = pcfmtstr(numdeltas)
3353 fmt = pcfmtstr(numdeltas)
3347 fmt2 = pcfmtstr(numdeltas, 4)
3354 fmt2 = pcfmtstr(numdeltas, 4)
3348 ui.writenoi18n(
3355 ui.writenoi18n(
3349 b'deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)
3356 b'deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)
3350 )
3357 )
3351 if numprev > 0:
3358 if numprev > 0:
3352 ui.writenoi18n(
3359 ui.writenoi18n(
3353 b' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev)
3360 b' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev)
3354 )
3361 )
3355 ui.writenoi18n(
3362 ui.writenoi18n(
3356 b' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev)
3363 b' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev)
3357 )
3364 )
3358 ui.writenoi18n(
3365 ui.writenoi18n(
3359 b' other : ' + fmt2 % pcfmt(numoprev, numprev)
3366 b' other : ' + fmt2 % pcfmt(numoprev, numprev)
3360 )
3367 )
3361 if gdelta:
3368 if gdelta:
3362 ui.writenoi18n(
3369 ui.writenoi18n(
3363 b'deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)
3370 b'deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)
3364 )
3371 )
3365 ui.writenoi18n(
3372 ui.writenoi18n(
3366 b'deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)
3373 b'deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)
3367 )
3374 )
3368 ui.writenoi18n(
3375 ui.writenoi18n(
3369 b'deltas against other : ' + fmt % pcfmt(numother, numdeltas)
3376 b'deltas against other : ' + fmt % pcfmt(numother, numdeltas)
3370 )
3377 )
3371
3378
3372
3379
3373 @command(
3380 @command(
3374 b'debugrevlogindex',
3381 b'debugrevlogindex',
3375 cmdutil.debugrevlogopts
3382 cmdutil.debugrevlogopts
3376 + [(b'f', b'format', 0, _(b'revlog format'), _(b'FORMAT'))],
3383 + [(b'f', b'format', 0, _(b'revlog format'), _(b'FORMAT'))],
3377 _(b'[-f FORMAT] -c|-m|FILE'),
3384 _(b'[-f FORMAT] -c|-m|FILE'),
3378 optionalrepo=True,
3385 optionalrepo=True,
3379 )
3386 )
3380 def debugrevlogindex(ui, repo, file_=None, **opts):
3387 def debugrevlogindex(ui, repo, file_=None, **opts):
3381 """dump the contents of a revlog index"""
3388 """dump the contents of a revlog index"""
3382 opts = pycompat.byteskwargs(opts)
3389 opts = pycompat.byteskwargs(opts)
3383 r = cmdutil.openrevlog(repo, b'debugrevlogindex', file_, opts)
3390 r = cmdutil.openrevlog(repo, b'debugrevlogindex', file_, opts)
3384 format = opts.get(b'format', 0)
3391 format = opts.get(b'format', 0)
3385 if format not in (0, 1):
3392 if format not in (0, 1):
3386 raise error.Abort(_(b"unknown format %d") % format)
3393 raise error.Abort(_(b"unknown format %d") % format)
3387
3394
3388 if ui.debugflag:
3395 if ui.debugflag:
3389 shortfn = hex
3396 shortfn = hex
3390 else:
3397 else:
3391 shortfn = short
3398 shortfn = short
3392
3399
3393 # There might not be anything in r, so have a sane default
3400 # There might not be anything in r, so have a sane default
3394 idlen = 12
3401 idlen = 12
3395 for i in r:
3402 for i in r:
3396 idlen = len(shortfn(r.node(i)))
3403 idlen = len(shortfn(r.node(i)))
3397 break
3404 break
3398
3405
3399 if format == 0:
3406 if format == 0:
3400 if ui.verbose:
3407 if ui.verbose:
3401 ui.writenoi18n(
3408 ui.writenoi18n(
3402 b" rev offset length linkrev %s %s p2\n"
3409 b" rev offset length linkrev %s %s p2\n"
3403 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3410 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3404 )
3411 )
3405 else:
3412 else:
3406 ui.writenoi18n(
3413 ui.writenoi18n(
3407 b" rev linkrev %s %s p2\n"
3414 b" rev linkrev %s %s p2\n"
3408 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3415 % (b"nodeid".ljust(idlen), b"p1".ljust(idlen))
3409 )
3416 )
3410 elif format == 1:
3417 elif format == 1:
3411 if ui.verbose:
3418 if ui.verbose:
3412 ui.writenoi18n(
3419 ui.writenoi18n(
3413 (
3420 (
3414 b" rev flag offset length size link p1"
3421 b" rev flag offset length size link p1"
3415 b" p2 %s\n"
3422 b" p2 %s\n"
3416 )
3423 )
3417 % b"nodeid".rjust(idlen)
3424 % b"nodeid".rjust(idlen)
3418 )
3425 )
3419 else:
3426 else:
3420 ui.writenoi18n(
3427 ui.writenoi18n(
3421 b" rev flag size link p1 p2 %s\n"
3428 b" rev flag size link p1 p2 %s\n"
3422 % b"nodeid".rjust(idlen)
3429 % b"nodeid".rjust(idlen)
3423 )
3430 )
3424
3431
3425 for i in r:
3432 for i in r:
3426 node = r.node(i)
3433 node = r.node(i)
3427 if format == 0:
3434 if format == 0:
3428 try:
3435 try:
3429 pp = r.parents(node)
3436 pp = r.parents(node)
3430 except Exception:
3437 except Exception:
3431 pp = [repo.nullid, repo.nullid]
3438 pp = [repo.nullid, repo.nullid]
3432 if ui.verbose:
3439 if ui.verbose:
3433 ui.write(
3440 ui.write(
3434 b"% 6d % 9d % 7d % 7d %s %s %s\n"
3441 b"% 6d % 9d % 7d % 7d %s %s %s\n"
3435 % (
3442 % (
3436 i,
3443 i,
3437 r.start(i),
3444 r.start(i),
3438 r.length(i),
3445 r.length(i),
3439 r.linkrev(i),
3446 r.linkrev(i),
3440 shortfn(node),
3447 shortfn(node),
3441 shortfn(pp[0]),
3448 shortfn(pp[0]),
3442 shortfn(pp[1]),
3449 shortfn(pp[1]),
3443 )
3450 )
3444 )
3451 )
3445 else:
3452 else:
3446 ui.write(
3453 ui.write(
3447 b"% 6d % 7d %s %s %s\n"
3454 b"% 6d % 7d %s %s %s\n"
3448 % (
3455 % (
3449 i,
3456 i,
3450 r.linkrev(i),
3457 r.linkrev(i),
3451 shortfn(node),
3458 shortfn(node),
3452 shortfn(pp[0]),
3459 shortfn(pp[0]),
3453 shortfn(pp[1]),
3460 shortfn(pp[1]),
3454 )
3461 )
3455 )
3462 )
3456 elif format == 1:
3463 elif format == 1:
3457 pr = r.parentrevs(i)
3464 pr = r.parentrevs(i)
3458 if ui.verbose:
3465 if ui.verbose:
3459 ui.write(
3466 ui.write(
3460 b"% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
3467 b"% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
3461 % (
3468 % (
3462 i,
3469 i,
3463 r.flags(i),
3470 r.flags(i),
3464 r.start(i),
3471 r.start(i),
3465 r.length(i),
3472 r.length(i),
3466 r.rawsize(i),
3473 r.rawsize(i),
3467 r.linkrev(i),
3474 r.linkrev(i),
3468 pr[0],
3475 pr[0],
3469 pr[1],
3476 pr[1],
3470 shortfn(node),
3477 shortfn(node),
3471 )
3478 )
3472 )
3479 )
3473 else:
3480 else:
3474 ui.write(
3481 ui.write(
3475 b"% 6d %04x % 8d % 6d % 6d % 6d %s\n"
3482 b"% 6d %04x % 8d % 6d % 6d % 6d %s\n"
3476 % (
3483 % (
3477 i,
3484 i,
3478 r.flags(i),
3485 r.flags(i),
3479 r.rawsize(i),
3486 r.rawsize(i),
3480 r.linkrev(i),
3487 r.linkrev(i),
3481 pr[0],
3488 pr[0],
3482 pr[1],
3489 pr[1],
3483 shortfn(node),
3490 shortfn(node),
3484 )
3491 )
3485 )
3492 )
3486
3493
3487
3494
3488 @command(
3495 @command(
3489 b'debugrevspec',
3496 b'debugrevspec',
3490 [
3497 [
3491 (
3498 (
3492 b'',
3499 b'',
3493 b'optimize',
3500 b'optimize',
3494 None,
3501 None,
3495 _(b'print parsed tree after optimizing (DEPRECATED)'),
3502 _(b'print parsed tree after optimizing (DEPRECATED)'),
3496 ),
3503 ),
3497 (
3504 (
3498 b'',
3505 b'',
3499 b'show-revs',
3506 b'show-revs',
3500 True,
3507 True,
3501 _(b'print list of result revisions (default)'),
3508 _(b'print list of result revisions (default)'),
3502 ),
3509 ),
3503 (
3510 (
3504 b's',
3511 b's',
3505 b'show-set',
3512 b'show-set',
3506 None,
3513 None,
3507 _(b'print internal representation of result set'),
3514 _(b'print internal representation of result set'),
3508 ),
3515 ),
3509 (
3516 (
3510 b'p',
3517 b'p',
3511 b'show-stage',
3518 b'show-stage',
3512 [],
3519 [],
3513 _(b'print parsed tree at the given stage'),
3520 _(b'print parsed tree at the given stage'),
3514 _(b'NAME'),
3521 _(b'NAME'),
3515 ),
3522 ),
3516 (b'', b'no-optimized', False, _(b'evaluate tree without optimization')),
3523 (b'', b'no-optimized', False, _(b'evaluate tree without optimization')),
3517 (b'', b'verify-optimized', False, _(b'verify optimized result')),
3524 (b'', b'verify-optimized', False, _(b'verify optimized result')),
3518 ],
3525 ],
3519 b'REVSPEC',
3526 b'REVSPEC',
3520 )
3527 )
3521 def debugrevspec(ui, repo, expr, **opts):
3528 def debugrevspec(ui, repo, expr, **opts):
3522 """parse and apply a revision specification
3529 """parse and apply a revision specification
3523
3530
3524 Use -p/--show-stage option to print the parsed tree at the given stages.
3531 Use -p/--show-stage option to print the parsed tree at the given stages.
3525 Use -p all to print tree at every stage.
3532 Use -p all to print tree at every stage.
3526
3533
3527 Use --no-show-revs option with -s or -p to print only the set
3534 Use --no-show-revs option with -s or -p to print only the set
3528 representation or the parsed tree respectively.
3535 representation or the parsed tree respectively.
3529
3536
3530 Use --verify-optimized to compare the optimized result with the unoptimized
3537 Use --verify-optimized to compare the optimized result with the unoptimized
3531 one. Returns 1 if the optimized result differs.
3538 one. Returns 1 if the optimized result differs.
3532 """
3539 """
3533 opts = pycompat.byteskwargs(opts)
3540 opts = pycompat.byteskwargs(opts)
3534 aliases = ui.configitems(b'revsetalias')
3541 aliases = ui.configitems(b'revsetalias')
3535 stages = [
3542 stages = [
3536 (b'parsed', lambda tree: tree),
3543 (b'parsed', lambda tree: tree),
3537 (
3544 (
3538 b'expanded',
3545 b'expanded',
3539 lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
3546 lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
3540 ),
3547 ),
3541 (b'concatenated', revsetlang.foldconcat),
3548 (b'concatenated', revsetlang.foldconcat),
3542 (b'analyzed', revsetlang.analyze),
3549 (b'analyzed', revsetlang.analyze),
3543 (b'optimized', revsetlang.optimize),
3550 (b'optimized', revsetlang.optimize),
3544 ]
3551 ]
3545 if opts[b'no_optimized']:
3552 if opts[b'no_optimized']:
3546 stages = stages[:-1]
3553 stages = stages[:-1]
3547 if opts[b'verify_optimized'] and opts[b'no_optimized']:
3554 if opts[b'verify_optimized'] and opts[b'no_optimized']:
3548 raise error.Abort(
3555 raise error.Abort(
3549 _(b'cannot use --verify-optimized with --no-optimized')
3556 _(b'cannot use --verify-optimized with --no-optimized')
3550 )
3557 )
3551 stagenames = {n for n, f in stages}
3558 stagenames = {n for n, f in stages}
3552
3559
3553 showalways = set()
3560 showalways = set()
3554 showchanged = set()
3561 showchanged = set()
3555 if ui.verbose and not opts[b'show_stage']:
3562 if ui.verbose and not opts[b'show_stage']:
3556 # show parsed tree by --verbose (deprecated)
3563 # show parsed tree by --verbose (deprecated)
3557 showalways.add(b'parsed')
3564 showalways.add(b'parsed')
3558 showchanged.update([b'expanded', b'concatenated'])
3565 showchanged.update([b'expanded', b'concatenated'])
3559 if opts[b'optimize']:
3566 if opts[b'optimize']:
3560 showalways.add(b'optimized')
3567 showalways.add(b'optimized')
3561 if opts[b'show_stage'] and opts[b'optimize']:
3568 if opts[b'show_stage'] and opts[b'optimize']:
3562 raise error.Abort(_(b'cannot use --optimize with --show-stage'))
3569 raise error.Abort(_(b'cannot use --optimize with --show-stage'))
3563 if opts[b'show_stage'] == [b'all']:
3570 if opts[b'show_stage'] == [b'all']:
3564 showalways.update(stagenames)
3571 showalways.update(stagenames)
3565 else:
3572 else:
3566 for n in opts[b'show_stage']:
3573 for n in opts[b'show_stage']:
3567 if n not in stagenames:
3574 if n not in stagenames:
3568 raise error.Abort(_(b'invalid stage name: %s') % n)
3575 raise error.Abort(_(b'invalid stage name: %s') % n)
3569 showalways.update(opts[b'show_stage'])
3576 showalways.update(opts[b'show_stage'])
3570
3577
3571 treebystage = {}
3578 treebystage = {}
3572 printedtree = None
3579 printedtree = None
3573 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
3580 tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
3574 for n, f in stages:
3581 for n, f in stages:
3575 treebystage[n] = tree = f(tree)
3582 treebystage[n] = tree = f(tree)
3576 if n in showalways or (n in showchanged and tree != printedtree):
3583 if n in showalways or (n in showchanged and tree != printedtree):
3577 if opts[b'show_stage'] or n != b'parsed':
3584 if opts[b'show_stage'] or n != b'parsed':
3578 ui.write(b"* %s:\n" % n)
3585 ui.write(b"* %s:\n" % n)
3579 ui.write(revsetlang.prettyformat(tree), b"\n")
3586 ui.write(revsetlang.prettyformat(tree), b"\n")
3580 printedtree = tree
3587 printedtree = tree
3581
3588
3582 if opts[b'verify_optimized']:
3589 if opts[b'verify_optimized']:
3583 arevs = revset.makematcher(treebystage[b'analyzed'])(repo)
3590 arevs = revset.makematcher(treebystage[b'analyzed'])(repo)
3584 brevs = revset.makematcher(treebystage[b'optimized'])(repo)
3591 brevs = revset.makematcher(treebystage[b'optimized'])(repo)
3585 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3592 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3586 ui.writenoi18n(
3593 ui.writenoi18n(
3587 b"* analyzed set:\n", stringutil.prettyrepr(arevs), b"\n"
3594 b"* analyzed set:\n", stringutil.prettyrepr(arevs), b"\n"
3588 )
3595 )
3589 ui.writenoi18n(
3596 ui.writenoi18n(
3590 b"* optimized set:\n", stringutil.prettyrepr(brevs), b"\n"
3597 b"* optimized set:\n", stringutil.prettyrepr(brevs), b"\n"
3591 )
3598 )
3592 arevs = list(arevs)
3599 arevs = list(arevs)
3593 brevs = list(brevs)
3600 brevs = list(brevs)
3594 if arevs == brevs:
3601 if arevs == brevs:
3595 return 0
3602 return 0
3596 ui.writenoi18n(b'--- analyzed\n', label=b'diff.file_a')
3603 ui.writenoi18n(b'--- analyzed\n', label=b'diff.file_a')
3597 ui.writenoi18n(b'+++ optimized\n', label=b'diff.file_b')
3604 ui.writenoi18n(b'+++ optimized\n', label=b'diff.file_b')
3598 sm = difflib.SequenceMatcher(None, arevs, brevs)
3605 sm = difflib.SequenceMatcher(None, arevs, brevs)
3599 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3606 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3600 if tag in ('delete', 'replace'):
3607 if tag in ('delete', 'replace'):
3601 for c in arevs[alo:ahi]:
3608 for c in arevs[alo:ahi]:
3602 ui.write(b'-%d\n' % c, label=b'diff.deleted')
3609 ui.write(b'-%d\n' % c, label=b'diff.deleted')
3603 if tag in ('insert', 'replace'):
3610 if tag in ('insert', 'replace'):
3604 for c in brevs[blo:bhi]:
3611 for c in brevs[blo:bhi]:
3605 ui.write(b'+%d\n' % c, label=b'diff.inserted')
3612 ui.write(b'+%d\n' % c, label=b'diff.inserted')
3606 if tag == 'equal':
3613 if tag == 'equal':
3607 for c in arevs[alo:ahi]:
3614 for c in arevs[alo:ahi]:
3608 ui.write(b' %d\n' % c)
3615 ui.write(b' %d\n' % c)
3609 return 1
3616 return 1
3610
3617
3611 func = revset.makematcher(tree)
3618 func = revset.makematcher(tree)
3612 revs = func(repo)
3619 revs = func(repo)
3613 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3620 if opts[b'show_set'] or (opts[b'show_set'] is None and ui.verbose):
3614 ui.writenoi18n(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
3621 ui.writenoi18n(b"* set:\n", stringutil.prettyrepr(revs), b"\n")
3615 if not opts[b'show_revs']:
3622 if not opts[b'show_revs']:
3616 return
3623 return
3617 for c in revs:
3624 for c in revs:
3618 ui.write(b"%d\n" % c)
3625 ui.write(b"%d\n" % c)
3619
3626
3620
3627
3621 @command(
3628 @command(
3622 b'debugserve',
3629 b'debugserve',
3623 [
3630 [
3624 (
3631 (
3625 b'',
3632 b'',
3626 b'sshstdio',
3633 b'sshstdio',
3627 False,
3634 False,
3628 _(b'run an SSH server bound to process handles'),
3635 _(b'run an SSH server bound to process handles'),
3629 ),
3636 ),
3630 (b'', b'logiofd', b'', _(b'file descriptor to log server I/O to')),
3637 (b'', b'logiofd', b'', _(b'file descriptor to log server I/O to')),
3631 (b'', b'logiofile', b'', _(b'file to log server I/O to')),
3638 (b'', b'logiofile', b'', _(b'file to log server I/O to')),
3632 ],
3639 ],
3633 b'',
3640 b'',
3634 )
3641 )
3635 def debugserve(ui, repo, **opts):
3642 def debugserve(ui, repo, **opts):
3636 """run a server with advanced settings
3643 """run a server with advanced settings
3637
3644
3638 This command is similar to :hg:`serve`. It exists partially as a
3645 This command is similar to :hg:`serve`. It exists partially as a
3639 workaround to the fact that ``hg serve --stdio`` must have specific
3646 workaround to the fact that ``hg serve --stdio`` must have specific
3640 arguments for security reasons.
3647 arguments for security reasons.
3641 """
3648 """
3642 opts = pycompat.byteskwargs(opts)
3649 opts = pycompat.byteskwargs(opts)
3643
3650
3644 if not opts[b'sshstdio']:
3651 if not opts[b'sshstdio']:
3645 raise error.Abort(_(b'only --sshstdio is currently supported'))
3652 raise error.Abort(_(b'only --sshstdio is currently supported'))
3646
3653
3647 logfh = None
3654 logfh = None
3648
3655
3649 if opts[b'logiofd'] and opts[b'logiofile']:
3656 if opts[b'logiofd'] and opts[b'logiofile']:
3650 raise error.Abort(_(b'cannot use both --logiofd and --logiofile'))
3657 raise error.Abort(_(b'cannot use both --logiofd and --logiofile'))
3651
3658
3652 if opts[b'logiofd']:
3659 if opts[b'logiofd']:
3653 # Ideally we would be line buffered. But line buffering in binary
3660 # Ideally we would be line buffered. But line buffering in binary
3654 # mode isn't supported and emits a warning in Python 3.8+. Disabling
3661 # mode isn't supported and emits a warning in Python 3.8+. Disabling
3655 # buffering could have performance impacts. But since this isn't
3662 # buffering could have performance impacts. But since this isn't
3656 # performance critical code, it should be fine.
3663 # performance critical code, it should be fine.
3657 try:
3664 try:
3658 logfh = os.fdopen(int(opts[b'logiofd']), 'ab', 0)
3665 logfh = os.fdopen(int(opts[b'logiofd']), 'ab', 0)
3659 except OSError as e:
3666 except OSError as e:
3660 if e.errno != errno.ESPIPE:
3667 if e.errno != errno.ESPIPE:
3661 raise
3668 raise
3662 # can't seek a pipe, so `ab` mode fails on py3
3669 # can't seek a pipe, so `ab` mode fails on py3
3663 logfh = os.fdopen(int(opts[b'logiofd']), 'wb', 0)
3670 logfh = os.fdopen(int(opts[b'logiofd']), 'wb', 0)
3664 elif opts[b'logiofile']:
3671 elif opts[b'logiofile']:
3665 logfh = open(opts[b'logiofile'], b'ab', 0)
3672 logfh = open(opts[b'logiofile'], b'ab', 0)
3666
3673
3667 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
3674 s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
3668 s.serve_forever()
3675 s.serve_forever()
3669
3676
3670
3677
3671 @command(b'debugsetparents', [], _(b'REV1 [REV2]'))
3678 @command(b'debugsetparents', [], _(b'REV1 [REV2]'))
3672 def debugsetparents(ui, repo, rev1, rev2=None):
3679 def debugsetparents(ui, repo, rev1, rev2=None):
3673 """manually set the parents of the current working directory (DANGEROUS)
3680 """manually set the parents of the current working directory (DANGEROUS)
3674
3681
3675 This command is not what you are looking for and should not be used. Using
3682 This command is not what you are looking for and should not be used. Using
3676 this command will most certainly results in slight corruption of the file
3683 this command will most certainly results in slight corruption of the file
3677 level histories withing your repository. DO NOT USE THIS COMMAND.
3684 level histories withing your repository. DO NOT USE THIS COMMAND.
3678
3685
3679 The command update the p1 and p2 field in the dirstate, and not touching
3686 The command update the p1 and p2 field in the dirstate, and not touching
3680 anything else. This useful for writing repository conversion tools, but
3687 anything else. This useful for writing repository conversion tools, but
3681 should be used with extreme care. For example, neither the working
3688 should be used with extreme care. For example, neither the working
3682 directory nor the dirstate is updated, so file status may be incorrect
3689 directory nor the dirstate is updated, so file status may be incorrect
3683 after running this command. Only used if you are one of the few people that
3690 after running this command. Only used if you are one of the few people that
3684 deeply unstand both conversion tools and file level histories. If you are
3691 deeply unstand both conversion tools and file level histories. If you are
3685 reading this help, you are not one of this people (most of them sailed west
3692 reading this help, you are not one of this people (most of them sailed west
3686 from Mithlond anyway.
3693 from Mithlond anyway.
3687
3694
3688 So one last time DO NOT USE THIS COMMAND.
3695 So one last time DO NOT USE THIS COMMAND.
3689
3696
3690 Returns 0 on success.
3697 Returns 0 on success.
3691 """
3698 """
3692
3699
3693 node1 = scmutil.revsingle(repo, rev1).node()
3700 node1 = scmutil.revsingle(repo, rev1).node()
3694 node2 = scmutil.revsingle(repo, rev2, b'null').node()
3701 node2 = scmutil.revsingle(repo, rev2, b'null').node()
3695
3702
3696 with repo.wlock():
3703 with repo.wlock():
3697 repo.setparents(node1, node2)
3704 repo.setparents(node1, node2)
3698
3705
3699
3706
3700 @command(b'debugsidedata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
3707 @command(b'debugsidedata', cmdutil.debugrevlogopts, _(b'-c|-m|FILE REV'))
3701 def debugsidedata(ui, repo, file_, rev=None, **opts):
3708 def debugsidedata(ui, repo, file_, rev=None, **opts):
3702 """dump the side data for a cl/manifest/file revision
3709 """dump the side data for a cl/manifest/file revision
3703
3710
3704 Use --verbose to dump the sidedata content."""
3711 Use --verbose to dump the sidedata content."""
3705 opts = pycompat.byteskwargs(opts)
3712 opts = pycompat.byteskwargs(opts)
3706 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
3713 if opts.get(b'changelog') or opts.get(b'manifest') or opts.get(b'dir'):
3707 if rev is not None:
3714 if rev is not None:
3708 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3715 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3709 file_, rev = None, file_
3716 file_, rev = None, file_
3710 elif rev is None:
3717 elif rev is None:
3711 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3718 raise error.CommandError(b'debugdata', _(b'invalid arguments'))
3712 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
3719 r = cmdutil.openstorage(repo, b'debugdata', file_, opts)
3713 r = getattr(r, '_revlog', r)
3720 r = getattr(r, '_revlog', r)
3714 try:
3721 try:
3715 sidedata = r.sidedata(r.lookup(rev))
3722 sidedata = r.sidedata(r.lookup(rev))
3716 except KeyError:
3723 except KeyError:
3717 raise error.Abort(_(b'invalid revision identifier %s') % rev)
3724 raise error.Abort(_(b'invalid revision identifier %s') % rev)
3718 if sidedata:
3725 if sidedata:
3719 sidedata = list(sidedata.items())
3726 sidedata = list(sidedata.items())
3720 sidedata.sort()
3727 sidedata.sort()
3721 ui.writenoi18n(b'%d sidedata entries\n' % len(sidedata))
3728 ui.writenoi18n(b'%d sidedata entries\n' % len(sidedata))
3722 for key, value in sidedata:
3729 for key, value in sidedata:
3723 ui.writenoi18n(b' entry-%04o size %d\n' % (key, len(value)))
3730 ui.writenoi18n(b' entry-%04o size %d\n' % (key, len(value)))
3724 if ui.verbose:
3731 if ui.verbose:
3725 ui.writenoi18n(b' %s\n' % stringutil.pprint(value))
3732 ui.writenoi18n(b' %s\n' % stringutil.pprint(value))
3726
3733
3727
3734
3728 @command(b'debugssl', [], b'[SOURCE]', optionalrepo=True)
3735 @command(b'debugssl', [], b'[SOURCE]', optionalrepo=True)
3729 def debugssl(ui, repo, source=None, **opts):
3736 def debugssl(ui, repo, source=None, **opts):
3730 """test a secure connection to a server
3737 """test a secure connection to a server
3731
3738
3732 This builds the certificate chain for the server on Windows, installing the
3739 This builds the certificate chain for the server on Windows, installing the
3733 missing intermediates and trusted root via Windows Update if necessary. It
3740 missing intermediates and trusted root via Windows Update if necessary. It
3734 does nothing on other platforms.
3741 does nothing on other platforms.
3735
3742
3736 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
3743 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
3737 that server is used. See :hg:`help urls` for more information.
3744 that server is used. See :hg:`help urls` for more information.
3738
3745
3739 If the update succeeds, retry the original operation. Otherwise, the cause
3746 If the update succeeds, retry the original operation. Otherwise, the cause
3740 of the SSL error is likely another issue.
3747 of the SSL error is likely another issue.
3741 """
3748 """
3742 if not pycompat.iswindows:
3749 if not pycompat.iswindows:
3743 raise error.Abort(
3750 raise error.Abort(
3744 _(b'certificate chain building is only possible on Windows')
3751 _(b'certificate chain building is only possible on Windows')
3745 )
3752 )
3746
3753
3747 if not source:
3754 if not source:
3748 if not repo:
3755 if not repo:
3749 raise error.Abort(
3756 raise error.Abort(
3750 _(
3757 _(
3751 b"there is no Mercurial repository here, and no "
3758 b"there is no Mercurial repository here, and no "
3752 b"server specified"
3759 b"server specified"
3753 )
3760 )
3754 )
3761 )
3755 source = b"default"
3762 source = b"default"
3756
3763
3757 source, branches = urlutil.get_unique_pull_path(
3764 source, branches = urlutil.get_unique_pull_path(
3758 b'debugssl', repo, ui, source
3765 b'debugssl', repo, ui, source
3759 )
3766 )
3760 url = urlutil.url(source)
3767 url = urlutil.url(source)
3761
3768
3762 defaultport = {b'https': 443, b'ssh': 22}
3769 defaultport = {b'https': 443, b'ssh': 22}
3763 if url.scheme in defaultport:
3770 if url.scheme in defaultport:
3764 try:
3771 try:
3765 addr = (url.host, int(url.port or defaultport[url.scheme]))
3772 addr = (url.host, int(url.port or defaultport[url.scheme]))
3766 except ValueError:
3773 except ValueError:
3767 raise error.Abort(_(b"malformed port number in URL"))
3774 raise error.Abort(_(b"malformed port number in URL"))
3768 else:
3775 else:
3769 raise error.Abort(_(b"only https and ssh connections are supported"))
3776 raise error.Abort(_(b"only https and ssh connections are supported"))
3770
3777
3771 from . import win32
3778 from . import win32
3772
3779
3773 s = ssl.wrap_socket(
3780 s = ssl.wrap_socket(
3774 socket.socket(),
3781 socket.socket(),
3775 ssl_version=ssl.PROTOCOL_TLS,
3782 ssl_version=ssl.PROTOCOL_TLS,
3776 cert_reqs=ssl.CERT_NONE,
3783 cert_reqs=ssl.CERT_NONE,
3777 ca_certs=None,
3784 ca_certs=None,
3778 )
3785 )
3779
3786
3780 try:
3787 try:
3781 s.connect(addr)
3788 s.connect(addr)
3782 cert = s.getpeercert(True)
3789 cert = s.getpeercert(True)
3783
3790
3784 ui.status(_(b'checking the certificate chain for %s\n') % url.host)
3791 ui.status(_(b'checking the certificate chain for %s\n') % url.host)
3785
3792
3786 complete = win32.checkcertificatechain(cert, build=False)
3793 complete = win32.checkcertificatechain(cert, build=False)
3787
3794
3788 if not complete:
3795 if not complete:
3789 ui.status(_(b'certificate chain is incomplete, updating... '))
3796 ui.status(_(b'certificate chain is incomplete, updating... '))
3790
3797
3791 if not win32.checkcertificatechain(cert):
3798 if not win32.checkcertificatechain(cert):
3792 ui.status(_(b'failed.\n'))
3799 ui.status(_(b'failed.\n'))
3793 else:
3800 else:
3794 ui.status(_(b'done.\n'))
3801 ui.status(_(b'done.\n'))
3795 else:
3802 else:
3796 ui.status(_(b'full certificate chain is available\n'))
3803 ui.status(_(b'full certificate chain is available\n'))
3797 finally:
3804 finally:
3798 s.close()
3805 s.close()
3799
3806
3800
3807
3801 @command(
3808 @command(
3802 b"debugbackupbundle",
3809 b"debugbackupbundle",
3803 [
3810 [
3804 (
3811 (
3805 b"",
3812 b"",
3806 b"recover",
3813 b"recover",
3807 b"",
3814 b"",
3808 b"brings the specified changeset back into the repository",
3815 b"brings the specified changeset back into the repository",
3809 )
3816 )
3810 ]
3817 ]
3811 + cmdutil.logopts,
3818 + cmdutil.logopts,
3812 _(b"hg debugbackupbundle [--recover HASH]"),
3819 _(b"hg debugbackupbundle [--recover HASH]"),
3813 )
3820 )
3814 def debugbackupbundle(ui, repo, *pats, **opts):
3821 def debugbackupbundle(ui, repo, *pats, **opts):
3815 """lists the changesets available in backup bundles
3822 """lists the changesets available in backup bundles
3816
3823
3817 Without any arguments, this command prints a list of the changesets in each
3824 Without any arguments, this command prints a list of the changesets in each
3818 backup bundle.
3825 backup bundle.
3819
3826
3820 --recover takes a changeset hash and unbundles the first bundle that
3827 --recover takes a changeset hash and unbundles the first bundle that
3821 contains that hash, which puts that changeset back in your repository.
3828 contains that hash, which puts that changeset back in your repository.
3822
3829
3823 --verbose will print the entire commit message and the bundle path for that
3830 --verbose will print the entire commit message and the bundle path for that
3824 backup.
3831 backup.
3825 """
3832 """
3826 backups = list(
3833 backups = list(
3827 filter(
3834 filter(
3828 os.path.isfile, glob.glob(repo.vfs.join(b"strip-backup") + b"/*.hg")
3835 os.path.isfile, glob.glob(repo.vfs.join(b"strip-backup") + b"/*.hg")
3829 )
3836 )
3830 )
3837 )
3831 backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
3838 backups.sort(key=lambda x: os.path.getmtime(x), reverse=True)
3832
3839
3833 opts = pycompat.byteskwargs(opts)
3840 opts = pycompat.byteskwargs(opts)
3834 opts[b"bundle"] = b""
3841 opts[b"bundle"] = b""
3835 opts[b"force"] = None
3842 opts[b"force"] = None
3836 limit = logcmdutil.getlimit(opts)
3843 limit = logcmdutil.getlimit(opts)
3837
3844
3838 def display(other, chlist, displayer):
3845 def display(other, chlist, displayer):
3839 if opts.get(b"newest_first"):
3846 if opts.get(b"newest_first"):
3840 chlist.reverse()
3847 chlist.reverse()
3841 count = 0
3848 count = 0
3842 for n in chlist:
3849 for n in chlist:
3843 if limit is not None and count >= limit:
3850 if limit is not None and count >= limit:
3844 break
3851 break
3845 parents = [
3852 parents = [
3846 True for p in other.changelog.parents(n) if p != repo.nullid
3853 True for p in other.changelog.parents(n) if p != repo.nullid
3847 ]
3854 ]
3848 if opts.get(b"no_merges") and len(parents) == 2:
3855 if opts.get(b"no_merges") and len(parents) == 2:
3849 continue
3856 continue
3850 count += 1
3857 count += 1
3851 displayer.show(other[n])
3858 displayer.show(other[n])
3852
3859
3853 recovernode = opts.get(b"recover")
3860 recovernode = opts.get(b"recover")
3854 if recovernode:
3861 if recovernode:
3855 if scmutil.isrevsymbol(repo, recovernode):
3862 if scmutil.isrevsymbol(repo, recovernode):
3856 ui.warn(_(b"%s already exists in the repo\n") % recovernode)
3863 ui.warn(_(b"%s already exists in the repo\n") % recovernode)
3857 return
3864 return
3858 elif backups:
3865 elif backups:
3859 msg = _(
3866 msg = _(
3860 b"Recover changesets using: hg debugbackupbundle --recover "
3867 b"Recover changesets using: hg debugbackupbundle --recover "
3861 b"<changeset hash>\n\nAvailable backup changesets:"
3868 b"<changeset hash>\n\nAvailable backup changesets:"
3862 )
3869 )
3863 ui.status(msg, label=b"status.removed")
3870 ui.status(msg, label=b"status.removed")
3864 else:
3871 else:
3865 ui.status(_(b"no backup changesets found\n"))
3872 ui.status(_(b"no backup changesets found\n"))
3866 return
3873 return
3867
3874
3868 for backup in backups:
3875 for backup in backups:
3869 # Much of this is copied from the hg incoming logic
3876 # Much of this is copied from the hg incoming logic
3870 source = os.path.relpath(backup, encoding.getcwd())
3877 source = os.path.relpath(backup, encoding.getcwd())
3871 source, branches = urlutil.get_unique_pull_path(
3878 source, branches = urlutil.get_unique_pull_path(
3872 b'debugbackupbundle',
3879 b'debugbackupbundle',
3873 repo,
3880 repo,
3874 ui,
3881 ui,
3875 source,
3882 source,
3876 default_branches=opts.get(b'branch'),
3883 default_branches=opts.get(b'branch'),
3877 )
3884 )
3878 try:
3885 try:
3879 other = hg.peer(repo, opts, source)
3886 other = hg.peer(repo, opts, source)
3880 except error.LookupError as ex:
3887 except error.LookupError as ex:
3881 msg = _(b"\nwarning: unable to open bundle %s") % source
3888 msg = _(b"\nwarning: unable to open bundle %s") % source
3882 hint = _(b"\n(missing parent rev %s)\n") % short(ex.name)
3889 hint = _(b"\n(missing parent rev %s)\n") % short(ex.name)
3883 ui.warn(msg, hint=hint)
3890 ui.warn(msg, hint=hint)
3884 continue
3891 continue
3885 revs, checkout = hg.addbranchrevs(
3892 revs, checkout = hg.addbranchrevs(
3886 repo, other, branches, opts.get(b"rev")
3893 repo, other, branches, opts.get(b"rev")
3887 )
3894 )
3888
3895
3889 if revs:
3896 if revs:
3890 revs = [other.lookup(rev) for rev in revs]
3897 revs = [other.lookup(rev) for rev in revs]
3891
3898
3892 with ui.silent():
3899 with ui.silent():
3893 try:
3900 try:
3894 other, chlist, cleanupfn = bundlerepo.getremotechanges(
3901 other, chlist, cleanupfn = bundlerepo.getremotechanges(
3895 ui, repo, other, revs, opts[b"bundle"], opts[b"force"]
3902 ui, repo, other, revs, opts[b"bundle"], opts[b"force"]
3896 )
3903 )
3897 except error.LookupError:
3904 except error.LookupError:
3898 continue
3905 continue
3899
3906
3900 try:
3907 try:
3901 if not chlist:
3908 if not chlist:
3902 continue
3909 continue
3903 if recovernode:
3910 if recovernode:
3904 with repo.lock(), repo.transaction(b"unbundle") as tr:
3911 with repo.lock(), repo.transaction(b"unbundle") as tr:
3905 if scmutil.isrevsymbol(other, recovernode):
3912 if scmutil.isrevsymbol(other, recovernode):
3906 ui.status(_(b"Unbundling %s\n") % (recovernode))
3913 ui.status(_(b"Unbundling %s\n") % (recovernode))
3907 f = hg.openpath(ui, source)
3914 f = hg.openpath(ui, source)
3908 gen = exchange.readbundle(ui, f, source)
3915 gen = exchange.readbundle(ui, f, source)
3909 if isinstance(gen, bundle2.unbundle20):
3916 if isinstance(gen, bundle2.unbundle20):
3910 bundle2.applybundle(
3917 bundle2.applybundle(
3911 repo,
3918 repo,
3912 gen,
3919 gen,
3913 tr,
3920 tr,
3914 source=b"unbundle",
3921 source=b"unbundle",
3915 url=b"bundle:" + source,
3922 url=b"bundle:" + source,
3916 )
3923 )
3917 else:
3924 else:
3918 gen.apply(repo, b"unbundle", b"bundle:" + source)
3925 gen.apply(repo, b"unbundle", b"bundle:" + source)
3919 break
3926 break
3920 else:
3927 else:
3921 backupdate = encoding.strtolocal(
3928 backupdate = encoding.strtolocal(
3922 time.strftime(
3929 time.strftime(
3923 "%a %H:%M, %Y-%m-%d",
3930 "%a %H:%M, %Y-%m-%d",
3924 time.localtime(os.path.getmtime(source)),
3931 time.localtime(os.path.getmtime(source)),
3925 )
3932 )
3926 )
3933 )
3927 ui.status(b"\n%s\n" % (backupdate.ljust(50)))
3934 ui.status(b"\n%s\n" % (backupdate.ljust(50)))
3928 if ui.verbose:
3935 if ui.verbose:
3929 ui.status(b"%s%s\n" % (b"bundle:".ljust(13), source))
3936 ui.status(b"%s%s\n" % (b"bundle:".ljust(13), source))
3930 else:
3937 else:
3931 opts[
3938 opts[
3932 b"template"
3939 b"template"
3933 ] = b"{label('status.modified', node|short)} {desc|firstline}\n"
3940 ] = b"{label('status.modified', node|short)} {desc|firstline}\n"
3934 displayer = logcmdutil.changesetdisplayer(
3941 displayer = logcmdutil.changesetdisplayer(
3935 ui, other, opts, False
3942 ui, other, opts, False
3936 )
3943 )
3937 display(other, chlist, displayer)
3944 display(other, chlist, displayer)
3938 displayer.close()
3945 displayer.close()
3939 finally:
3946 finally:
3940 cleanupfn()
3947 cleanupfn()
3941
3948
3942
3949
3943 @command(
3950 @command(
3944 b'debugsub',
3951 b'debugsub',
3945 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))],
3952 [(b'r', b'rev', b'', _(b'revision to check'), _(b'REV'))],
3946 _(b'[-r REV] [REV]'),
3953 _(b'[-r REV] [REV]'),
3947 )
3954 )
3948 def debugsub(ui, repo, rev=None):
3955 def debugsub(ui, repo, rev=None):
3949 ctx = scmutil.revsingle(repo, rev, None)
3956 ctx = scmutil.revsingle(repo, rev, None)
3950 for k, v in sorted(ctx.substate.items()):
3957 for k, v in sorted(ctx.substate.items()):
3951 ui.writenoi18n(b'path %s\n' % k)
3958 ui.writenoi18n(b'path %s\n' % k)
3952 ui.writenoi18n(b' source %s\n' % v[0])
3959 ui.writenoi18n(b' source %s\n' % v[0])
3953 ui.writenoi18n(b' revision %s\n' % v[1])
3960 ui.writenoi18n(b' revision %s\n' % v[1])
3954
3961
3955
3962
3956 @command(b'debugshell', optionalrepo=True)
3963 @command(b'debugshell', optionalrepo=True)
3957 def debugshell(ui, repo):
3964 def debugshell(ui, repo):
3958 """run an interactive Python interpreter
3965 """run an interactive Python interpreter
3959
3966
3960 The local namespace is provided with a reference to the ui and
3967 The local namespace is provided with a reference to the ui and
3961 the repo instance (if available).
3968 the repo instance (if available).
3962 """
3969 """
3963 import code
3970 import code
3964
3971
3965 imported_objects = {
3972 imported_objects = {
3966 'ui': ui,
3973 'ui': ui,
3967 'repo': repo,
3974 'repo': repo,
3968 }
3975 }
3969
3976
3970 code.interact(local=imported_objects)
3977 code.interact(local=imported_objects)
3971
3978
3972
3979
3973 @command(
3980 @command(
3974 b'debugsuccessorssets',
3981 b'debugsuccessorssets',
3975 [(b'', b'closest', False, _(b'return closest successors sets only'))],
3982 [(b'', b'closest', False, _(b'return closest successors sets only'))],
3976 _(b'[REV]'),
3983 _(b'[REV]'),
3977 )
3984 )
3978 def debugsuccessorssets(ui, repo, *revs, **opts):
3985 def debugsuccessorssets(ui, repo, *revs, **opts):
3979 """show set of successors for revision
3986 """show set of successors for revision
3980
3987
3981 A successors set of changeset A is a consistent group of revisions that
3988 A successors set of changeset A is a consistent group of revisions that
3982 succeed A. It contains non-obsolete changesets only unless closests
3989 succeed A. It contains non-obsolete changesets only unless closests
3983 successors set is set.
3990 successors set is set.
3984
3991
3985 In most cases a changeset A has a single successors set containing a single
3992 In most cases a changeset A has a single successors set containing a single
3986 successor (changeset A replaced by A').
3993 successor (changeset A replaced by A').
3987
3994
3988 A changeset that is made obsolete with no successors are called "pruned".
3995 A changeset that is made obsolete with no successors are called "pruned".
3989 Such changesets have no successors sets at all.
3996 Such changesets have no successors sets at all.
3990
3997
3991 A changeset that has been "split" will have a successors set containing
3998 A changeset that has been "split" will have a successors set containing
3992 more than one successor.
3999 more than one successor.
3993
4000
3994 A changeset that has been rewritten in multiple different ways is called
4001 A changeset that has been rewritten in multiple different ways is called
3995 "divergent". Such changesets have multiple successor sets (each of which
4002 "divergent". Such changesets have multiple successor sets (each of which
3996 may also be split, i.e. have multiple successors).
4003 may also be split, i.e. have multiple successors).
3997
4004
3998 Results are displayed as follows::
4005 Results are displayed as follows::
3999
4006
4000 <rev1>
4007 <rev1>
4001 <successors-1A>
4008 <successors-1A>
4002 <rev2>
4009 <rev2>
4003 <successors-2A>
4010 <successors-2A>
4004 <successors-2B1> <successors-2B2> <successors-2B3>
4011 <successors-2B1> <successors-2B2> <successors-2B3>
4005
4012
4006 Here rev2 has two possible (i.e. divergent) successors sets. The first
4013 Here rev2 has two possible (i.e. divergent) successors sets. The first
4007 holds one element, whereas the second holds three (i.e. the changeset has
4014 holds one element, whereas the second holds three (i.e. the changeset has
4008 been split).
4015 been split).
4009 """
4016 """
4010 # passed to successorssets caching computation from one call to another
4017 # passed to successorssets caching computation from one call to another
4011 cache = {}
4018 cache = {}
4012 ctx2str = bytes
4019 ctx2str = bytes
4013 node2str = short
4020 node2str = short
4014 for rev in logcmdutil.revrange(repo, revs):
4021 for rev in logcmdutil.revrange(repo, revs):
4015 ctx = repo[rev]
4022 ctx = repo[rev]
4016 ui.write(b'%s\n' % ctx2str(ctx))
4023 ui.write(b'%s\n' % ctx2str(ctx))
4017 for succsset in obsutil.successorssets(
4024 for succsset in obsutil.successorssets(
4018 repo, ctx.node(), closest=opts['closest'], cache=cache
4025 repo, ctx.node(), closest=opts['closest'], cache=cache
4019 ):
4026 ):
4020 if succsset:
4027 if succsset:
4021 ui.write(b' ')
4028 ui.write(b' ')
4022 ui.write(node2str(succsset[0]))
4029 ui.write(node2str(succsset[0]))
4023 for node in succsset[1:]:
4030 for node in succsset[1:]:
4024 ui.write(b' ')
4031 ui.write(b' ')
4025 ui.write(node2str(node))
4032 ui.write(node2str(node))
4026 ui.write(b'\n')
4033 ui.write(b'\n')
4027
4034
4028
4035
4029 @command(b'debugtagscache', [])
4036 @command(b'debugtagscache', [])
4030 def debugtagscache(ui, repo):
4037 def debugtagscache(ui, repo):
4031 """display the contents of .hg/cache/hgtagsfnodes1"""
4038 """display the contents of .hg/cache/hgtagsfnodes1"""
4032 cache = tagsmod.hgtagsfnodescache(repo.unfiltered())
4039 cache = tagsmod.hgtagsfnodescache(repo.unfiltered())
4033 flog = repo.file(b'.hgtags')
4040 flog = repo.file(b'.hgtags')
4034 for r in repo:
4041 for r in repo:
4035 node = repo[r].node()
4042 node = repo[r].node()
4036 tagsnode = cache.getfnode(node, computemissing=False)
4043 tagsnode = cache.getfnode(node, computemissing=False)
4037 if tagsnode:
4044 if tagsnode:
4038 tagsnodedisplay = hex(tagsnode)
4045 tagsnodedisplay = hex(tagsnode)
4039 if not flog.hasnode(tagsnode):
4046 if not flog.hasnode(tagsnode):
4040 tagsnodedisplay += b' (unknown node)'
4047 tagsnodedisplay += b' (unknown node)'
4041 elif tagsnode is None:
4048 elif tagsnode is None:
4042 tagsnodedisplay = b'missing'
4049 tagsnodedisplay = b'missing'
4043 else:
4050 else:
4044 tagsnodedisplay = b'invalid'
4051 tagsnodedisplay = b'invalid'
4045
4052
4046 ui.write(b'%d %s %s\n' % (r, hex(node), tagsnodedisplay))
4053 ui.write(b'%d %s %s\n' % (r, hex(node), tagsnodedisplay))
4047
4054
4048
4055
4049 @command(
4056 @command(
4050 b'debugtemplate',
4057 b'debugtemplate',
4051 [
4058 [
4052 (b'r', b'rev', [], _(b'apply template on changesets'), _(b'REV')),
4059 (b'r', b'rev', [], _(b'apply template on changesets'), _(b'REV')),
4053 (b'D', b'define', [], _(b'define template keyword'), _(b'KEY=VALUE')),
4060 (b'D', b'define', [], _(b'define template keyword'), _(b'KEY=VALUE')),
4054 ],
4061 ],
4055 _(b'[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
4062 _(b'[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
4056 optionalrepo=True,
4063 optionalrepo=True,
4057 )
4064 )
4058 def debugtemplate(ui, repo, tmpl, **opts):
4065 def debugtemplate(ui, repo, tmpl, **opts):
4059 """parse and apply a template
4066 """parse and apply a template
4060
4067
4061 If -r/--rev is given, the template is processed as a log template and
4068 If -r/--rev is given, the template is processed as a log template and
4062 applied to the given changesets. Otherwise, it is processed as a generic
4069 applied to the given changesets. Otherwise, it is processed as a generic
4063 template.
4070 template.
4064
4071
4065 Use --verbose to print the parsed tree.
4072 Use --verbose to print the parsed tree.
4066 """
4073 """
4067 revs = None
4074 revs = None
4068 if opts['rev']:
4075 if opts['rev']:
4069 if repo is None:
4076 if repo is None:
4070 raise error.RepoError(
4077 raise error.RepoError(
4071 _(b'there is no Mercurial repository here (.hg not found)')
4078 _(b'there is no Mercurial repository here (.hg not found)')
4072 )
4079 )
4073 revs = logcmdutil.revrange(repo, opts['rev'])
4080 revs = logcmdutil.revrange(repo, opts['rev'])
4074
4081
4075 props = {}
4082 props = {}
4076 for d in opts['define']:
4083 for d in opts['define']:
4077 try:
4084 try:
4078 k, v = (e.strip() for e in d.split(b'=', 1))
4085 k, v = (e.strip() for e in d.split(b'=', 1))
4079 if not k or k == b'ui':
4086 if not k or k == b'ui':
4080 raise ValueError
4087 raise ValueError
4081 props[k] = v
4088 props[k] = v
4082 except ValueError:
4089 except ValueError:
4083 raise error.Abort(_(b'malformed keyword definition: %s') % d)
4090 raise error.Abort(_(b'malformed keyword definition: %s') % d)
4084
4091
4085 if ui.verbose:
4092 if ui.verbose:
4086 aliases = ui.configitems(b'templatealias')
4093 aliases = ui.configitems(b'templatealias')
4087 tree = templater.parse(tmpl)
4094 tree = templater.parse(tmpl)
4088 ui.note(templater.prettyformat(tree), b'\n')
4095 ui.note(templater.prettyformat(tree), b'\n')
4089 newtree = templater.expandaliases(tree, aliases)
4096 newtree = templater.expandaliases(tree, aliases)
4090 if newtree != tree:
4097 if newtree != tree:
4091 ui.notenoi18n(
4098 ui.notenoi18n(
4092 b"* expanded:\n", templater.prettyformat(newtree), b'\n'
4099 b"* expanded:\n", templater.prettyformat(newtree), b'\n'
4093 )
4100 )
4094
4101
4095 if revs is None:
4102 if revs is None:
4096 tres = formatter.templateresources(ui, repo)
4103 tres = formatter.templateresources(ui, repo)
4097 t = formatter.maketemplater(ui, tmpl, resources=tres)
4104 t = formatter.maketemplater(ui, tmpl, resources=tres)
4098 if ui.verbose:
4105 if ui.verbose:
4099 kwds, funcs = t.symbolsuseddefault()
4106 kwds, funcs = t.symbolsuseddefault()
4100 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
4107 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
4101 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
4108 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
4102 ui.write(t.renderdefault(props))
4109 ui.write(t.renderdefault(props))
4103 else:
4110 else:
4104 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
4111 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
4105 if ui.verbose:
4112 if ui.verbose:
4106 kwds, funcs = displayer.t.symbolsuseddefault()
4113 kwds, funcs = displayer.t.symbolsuseddefault()
4107 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
4114 ui.writenoi18n(b"* keywords: %s\n" % b', '.join(sorted(kwds)))
4108 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
4115 ui.writenoi18n(b"* functions: %s\n" % b', '.join(sorted(funcs)))
4109 for r in revs:
4116 for r in revs:
4110 displayer.show(repo[r], **pycompat.strkwargs(props))
4117 displayer.show(repo[r], **pycompat.strkwargs(props))
4111 displayer.close()
4118 displayer.close()
4112
4119
4113
4120
4114 @command(
4121 @command(
4115 b'debuguigetpass',
4122 b'debuguigetpass',
4116 [
4123 [
4117 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4124 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4118 ],
4125 ],
4119 _(b'[-p TEXT]'),
4126 _(b'[-p TEXT]'),
4120 norepo=True,
4127 norepo=True,
4121 )
4128 )
4122 def debuguigetpass(ui, prompt=b''):
4129 def debuguigetpass(ui, prompt=b''):
4123 """show prompt to type password"""
4130 """show prompt to type password"""
4124 r = ui.getpass(prompt)
4131 r = ui.getpass(prompt)
4125 if r is None:
4132 if r is None:
4126 r = b"<default response>"
4133 r = b"<default response>"
4127 ui.writenoi18n(b'response: %s\n' % r)
4134 ui.writenoi18n(b'response: %s\n' % r)
4128
4135
4129
4136
4130 @command(
4137 @command(
4131 b'debuguiprompt',
4138 b'debuguiprompt',
4132 [
4139 [
4133 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4140 (b'p', b'prompt', b'', _(b'prompt text'), _(b'TEXT')),
4134 ],
4141 ],
4135 _(b'[-p TEXT]'),
4142 _(b'[-p TEXT]'),
4136 norepo=True,
4143 norepo=True,
4137 )
4144 )
4138 def debuguiprompt(ui, prompt=b''):
4145 def debuguiprompt(ui, prompt=b''):
4139 """show plain prompt"""
4146 """show plain prompt"""
4140 r = ui.prompt(prompt)
4147 r = ui.prompt(prompt)
4141 ui.writenoi18n(b'response: %s\n' % r)
4148 ui.writenoi18n(b'response: %s\n' % r)
4142
4149
4143
4150
4144 @command(b'debugupdatecaches', [])
4151 @command(b'debugupdatecaches', [])
4145 def debugupdatecaches(ui, repo, *pats, **opts):
4152 def debugupdatecaches(ui, repo, *pats, **opts):
4146 """warm all known caches in the repository"""
4153 """warm all known caches in the repository"""
4147 with repo.wlock(), repo.lock():
4154 with repo.wlock(), repo.lock():
4148 repo.updatecaches(caches=repository.CACHES_ALL)
4155 repo.updatecaches(caches=repository.CACHES_ALL)
4149
4156
4150
4157
4151 @command(
4158 @command(
4152 b'debugupgraderepo',
4159 b'debugupgraderepo',
4153 [
4160 [
4154 (
4161 (
4155 b'o',
4162 b'o',
4156 b'optimize',
4163 b'optimize',
4157 [],
4164 [],
4158 _(b'extra optimization to perform'),
4165 _(b'extra optimization to perform'),
4159 _(b'NAME'),
4166 _(b'NAME'),
4160 ),
4167 ),
4161 (b'', b'run', False, _(b'performs an upgrade')),
4168 (b'', b'run', False, _(b'performs an upgrade')),
4162 (b'', b'backup', True, _(b'keep the old repository content around')),
4169 (b'', b'backup', True, _(b'keep the old repository content around')),
4163 (b'', b'changelog', None, _(b'select the changelog for upgrade')),
4170 (b'', b'changelog', None, _(b'select the changelog for upgrade')),
4164 (b'', b'manifest', None, _(b'select the manifest for upgrade')),
4171 (b'', b'manifest', None, _(b'select the manifest for upgrade')),
4165 (b'', b'filelogs', None, _(b'select all filelogs for upgrade')),
4172 (b'', b'filelogs', None, _(b'select all filelogs for upgrade')),
4166 ],
4173 ],
4167 )
4174 )
4168 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
4175 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
4169 """upgrade a repository to use different features
4176 """upgrade a repository to use different features
4170
4177
4171 If no arguments are specified, the repository is evaluated for upgrade
4178 If no arguments are specified, the repository is evaluated for upgrade
4172 and a list of problems and potential optimizations is printed.
4179 and a list of problems and potential optimizations is printed.
4173
4180
4174 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
4181 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
4175 can be influenced via additional arguments. More details will be provided
4182 can be influenced via additional arguments. More details will be provided
4176 by the command output when run without ``--run``.
4183 by the command output when run without ``--run``.
4177
4184
4178 During the upgrade, the repository will be locked and no writes will be
4185 During the upgrade, the repository will be locked and no writes will be
4179 allowed.
4186 allowed.
4180
4187
4181 At the end of the upgrade, the repository may not be readable while new
4188 At the end of the upgrade, the repository may not be readable while new
4182 repository data is swapped in. This window will be as long as it takes to
4189 repository data is swapped in. This window will be as long as it takes to
4183 rename some directories inside the ``.hg`` directory. On most machines, this
4190 rename some directories inside the ``.hg`` directory. On most machines, this
4184 should complete almost instantaneously and the chances of a consumer being
4191 should complete almost instantaneously and the chances of a consumer being
4185 unable to access the repository should be low.
4192 unable to access the repository should be low.
4186
4193
4187 By default, all revlogs will be upgraded. You can restrict this using flags
4194 By default, all revlogs will be upgraded. You can restrict this using flags
4188 such as `--manifest`:
4195 such as `--manifest`:
4189
4196
4190 * `--manifest`: only optimize the manifest
4197 * `--manifest`: only optimize the manifest
4191 * `--no-manifest`: optimize all revlog but the manifest
4198 * `--no-manifest`: optimize all revlog but the manifest
4192 * `--changelog`: optimize the changelog only
4199 * `--changelog`: optimize the changelog only
4193 * `--no-changelog --no-manifest`: optimize filelogs only
4200 * `--no-changelog --no-manifest`: optimize filelogs only
4194 * `--filelogs`: optimize the filelogs only
4201 * `--filelogs`: optimize the filelogs only
4195 * `--no-changelog --no-manifest --no-filelogs`: skip all revlog optimizations
4202 * `--no-changelog --no-manifest --no-filelogs`: skip all revlog optimizations
4196 """
4203 """
4197 return upgrade.upgraderepo(
4204 return upgrade.upgraderepo(
4198 ui, repo, run=run, optimize=set(optimize), backup=backup, **opts
4205 ui, repo, run=run, optimize=set(optimize), backup=backup, **opts
4199 )
4206 )
4200
4207
4201
4208
4202 @command(
4209 @command(
4203 b'debugwalk', cmdutil.walkopts, _(b'[OPTION]... [FILE]...'), inferrepo=True
4210 b'debugwalk', cmdutil.walkopts, _(b'[OPTION]... [FILE]...'), inferrepo=True
4204 )
4211 )
4205 def debugwalk(ui, repo, *pats, **opts):
4212 def debugwalk(ui, repo, *pats, **opts):
4206 """show how files match on given patterns"""
4213 """show how files match on given patterns"""
4207 opts = pycompat.byteskwargs(opts)
4214 opts = pycompat.byteskwargs(opts)
4208 m = scmutil.match(repo[None], pats, opts)
4215 m = scmutil.match(repo[None], pats, opts)
4209 if ui.verbose:
4216 if ui.verbose:
4210 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
4217 ui.writenoi18n(b'* matcher:\n', stringutil.prettyrepr(m), b'\n')
4211 items = list(repo[None].walk(m))
4218 items = list(repo[None].walk(m))
4212 if not items:
4219 if not items:
4213 return
4220 return
4214 f = lambda fn: fn
4221 f = lambda fn: fn
4215 if ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/':
4222 if ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/':
4216 f = lambda fn: util.normpath(fn)
4223 f = lambda fn: util.normpath(fn)
4217 fmt = b'f %%-%ds %%-%ds %%s' % (
4224 fmt = b'f %%-%ds %%-%ds %%s' % (
4218 max([len(abs) for abs in items]),
4225 max([len(abs) for abs in items]),
4219 max([len(repo.pathto(abs)) for abs in items]),
4226 max([len(repo.pathto(abs)) for abs in items]),
4220 )
4227 )
4221 for abs in items:
4228 for abs in items:
4222 line = fmt % (
4229 line = fmt % (
4223 abs,
4230 abs,
4224 f(repo.pathto(abs)),
4231 f(repo.pathto(abs)),
4225 m.exact(abs) and b'exact' or b'',
4232 m.exact(abs) and b'exact' or b'',
4226 )
4233 )
4227 ui.write(b"%s\n" % line.rstrip())
4234 ui.write(b"%s\n" % line.rstrip())
4228
4235
4229
4236
4230 @command(b'debugwhyunstable', [], _(b'REV'))
4237 @command(b'debugwhyunstable', [], _(b'REV'))
4231 def debugwhyunstable(ui, repo, rev):
4238 def debugwhyunstable(ui, repo, rev):
4232 """explain instabilities of a changeset"""
4239 """explain instabilities of a changeset"""
4233 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
4240 for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
4234 dnodes = b''
4241 dnodes = b''
4235 if entry.get(b'divergentnodes'):
4242 if entry.get(b'divergentnodes'):
4236 dnodes = (
4243 dnodes = (
4237 b' '.join(
4244 b' '.join(
4238 b'%s (%s)' % (ctx.hex(), ctx.phasestr())
4245 b'%s (%s)' % (ctx.hex(), ctx.phasestr())
4239 for ctx in entry[b'divergentnodes']
4246 for ctx in entry[b'divergentnodes']
4240 )
4247 )
4241 + b' '
4248 + b' '
4242 )
4249 )
4243 ui.write(
4250 ui.write(
4244 b'%s: %s%s %s\n'
4251 b'%s: %s%s %s\n'
4245 % (entry[b'instability'], dnodes, entry[b'reason'], entry[b'node'])
4252 % (entry[b'instability'], dnodes, entry[b'reason'], entry[b'node'])
4246 )
4253 )
4247
4254
4248
4255
4249 @command(
4256 @command(
4250 b'debugwireargs',
4257 b'debugwireargs',
4251 [
4258 [
4252 (b'', b'three', b'', b'three'),
4259 (b'', b'three', b'', b'three'),
4253 (b'', b'four', b'', b'four'),
4260 (b'', b'four', b'', b'four'),
4254 (b'', b'five', b'', b'five'),
4261 (b'', b'five', b'', b'five'),
4255 ]
4262 ]
4256 + cmdutil.remoteopts,
4263 + cmdutil.remoteopts,
4257 _(b'REPO [OPTIONS]... [ONE [TWO]]'),
4264 _(b'REPO [OPTIONS]... [ONE [TWO]]'),
4258 norepo=True,
4265 norepo=True,
4259 )
4266 )
4260 def debugwireargs(ui, repopath, *vals, **opts):
4267 def debugwireargs(ui, repopath, *vals, **opts):
4261 opts = pycompat.byteskwargs(opts)
4268 opts = pycompat.byteskwargs(opts)
4262 repo = hg.peer(ui, opts, repopath)
4269 repo = hg.peer(ui, opts, repopath)
4263 try:
4270 try:
4264 for opt in cmdutil.remoteopts:
4271 for opt in cmdutil.remoteopts:
4265 del opts[opt[1]]
4272 del opts[opt[1]]
4266 args = {}
4273 args = {}
4267 for k, v in pycompat.iteritems(opts):
4274 for k, v in pycompat.iteritems(opts):
4268 if v:
4275 if v:
4269 args[k] = v
4276 args[k] = v
4270 args = pycompat.strkwargs(args)
4277 args = pycompat.strkwargs(args)
4271 # run twice to check that we don't mess up the stream for the next command
4278 # run twice to check that we don't mess up the stream for the next command
4272 res1 = repo.debugwireargs(*vals, **args)
4279 res1 = repo.debugwireargs(*vals, **args)
4273 res2 = repo.debugwireargs(*vals, **args)
4280 res2 = repo.debugwireargs(*vals, **args)
4274 ui.write(b"%s\n" % res1)
4281 ui.write(b"%s\n" % res1)
4275 if res1 != res2:
4282 if res1 != res2:
4276 ui.warn(b"%s\n" % res2)
4283 ui.warn(b"%s\n" % res2)
4277 finally:
4284 finally:
4278 repo.close()
4285 repo.close()
4279
4286
4280
4287
4281 def _parsewirelangblocks(fh):
4288 def _parsewirelangblocks(fh):
4282 activeaction = None
4289 activeaction = None
4283 blocklines = []
4290 blocklines = []
4284 lastindent = 0
4291 lastindent = 0
4285
4292
4286 for line in fh:
4293 for line in fh:
4287 line = line.rstrip()
4294 line = line.rstrip()
4288 if not line:
4295 if not line:
4289 continue
4296 continue
4290
4297
4291 if line.startswith(b'#'):
4298 if line.startswith(b'#'):
4292 continue
4299 continue
4293
4300
4294 if not line.startswith(b' '):
4301 if not line.startswith(b' '):
4295 # New block. Flush previous one.
4302 # New block. Flush previous one.
4296 if activeaction:
4303 if activeaction:
4297 yield activeaction, blocklines
4304 yield activeaction, blocklines
4298
4305
4299 activeaction = line
4306 activeaction = line
4300 blocklines = []
4307 blocklines = []
4301 lastindent = 0
4308 lastindent = 0
4302 continue
4309 continue
4303
4310
4304 # Else we start with an indent.
4311 # Else we start with an indent.
4305
4312
4306 if not activeaction:
4313 if not activeaction:
4307 raise error.Abort(_(b'indented line outside of block'))
4314 raise error.Abort(_(b'indented line outside of block'))
4308
4315
4309 indent = len(line) - len(line.lstrip())
4316 indent = len(line) - len(line.lstrip())
4310
4317
4311 # If this line is indented more than the last line, concatenate it.
4318 # If this line is indented more than the last line, concatenate it.
4312 if indent > lastindent and blocklines:
4319 if indent > lastindent and blocklines:
4313 blocklines[-1] += line.lstrip()
4320 blocklines[-1] += line.lstrip()
4314 else:
4321 else:
4315 blocklines.append(line)
4322 blocklines.append(line)
4316 lastindent = indent
4323 lastindent = indent
4317
4324
4318 # Flush last block.
4325 # Flush last block.
4319 if activeaction:
4326 if activeaction:
4320 yield activeaction, blocklines
4327 yield activeaction, blocklines
4321
4328
4322
4329
4323 @command(
4330 @command(
4324 b'debugwireproto',
4331 b'debugwireproto',
4325 [
4332 [
4326 (b'', b'localssh', False, _(b'start an SSH server for this repo')),
4333 (b'', b'localssh', False, _(b'start an SSH server for this repo')),
4327 (b'', b'peer', b'', _(b'construct a specific version of the peer')),
4334 (b'', b'peer', b'', _(b'construct a specific version of the peer')),
4328 (
4335 (
4329 b'',
4336 b'',
4330 b'noreadstderr',
4337 b'noreadstderr',
4331 False,
4338 False,
4332 _(b'do not read from stderr of the remote'),
4339 _(b'do not read from stderr of the remote'),
4333 ),
4340 ),
4334 (
4341 (
4335 b'',
4342 b'',
4336 b'nologhandshake',
4343 b'nologhandshake',
4337 False,
4344 False,
4338 _(b'do not log I/O related to the peer handshake'),
4345 _(b'do not log I/O related to the peer handshake'),
4339 ),
4346 ),
4340 ]
4347 ]
4341 + cmdutil.remoteopts,
4348 + cmdutil.remoteopts,
4342 _(b'[PATH]'),
4349 _(b'[PATH]'),
4343 optionalrepo=True,
4350 optionalrepo=True,
4344 )
4351 )
4345 def debugwireproto(ui, repo, path=None, **opts):
4352 def debugwireproto(ui, repo, path=None, **opts):
4346 """send wire protocol commands to a server
4353 """send wire protocol commands to a server
4347
4354
4348 This command can be used to issue wire protocol commands to remote
4355 This command can be used to issue wire protocol commands to remote
4349 peers and to debug the raw data being exchanged.
4356 peers and to debug the raw data being exchanged.
4350
4357
4351 ``--localssh`` will start an SSH server against the current repository
4358 ``--localssh`` will start an SSH server against the current repository
4352 and connect to that. By default, the connection will perform a handshake
4359 and connect to that. By default, the connection will perform a handshake
4353 and establish an appropriate peer instance.
4360 and establish an appropriate peer instance.
4354
4361
4355 ``--peer`` can be used to bypass the handshake protocol and construct a
4362 ``--peer`` can be used to bypass the handshake protocol and construct a
4356 peer instance using the specified class type. Valid values are ``raw``,
4363 peer instance using the specified class type. Valid values are ``raw``,
4357 ``ssh1``. ``raw`` instances only allow sending raw data payloads and
4364 ``ssh1``. ``raw`` instances only allow sending raw data payloads and
4358 don't support higher-level command actions.
4365 don't support higher-level command actions.
4359
4366
4360 ``--noreadstderr`` can be used to disable automatic reading from stderr
4367 ``--noreadstderr`` can be used to disable automatic reading from stderr
4361 of the peer (for SSH connections only). Disabling automatic reading of
4368 of the peer (for SSH connections only). Disabling automatic reading of
4362 stderr is useful for making output more deterministic.
4369 stderr is useful for making output more deterministic.
4363
4370
4364 Commands are issued via a mini language which is specified via stdin.
4371 Commands are issued via a mini language which is specified via stdin.
4365 The language consists of individual actions to perform. An action is
4372 The language consists of individual actions to perform. An action is
4366 defined by a block. A block is defined as a line with no leading
4373 defined by a block. A block is defined as a line with no leading
4367 space followed by 0 or more lines with leading space. Blocks are
4374 space followed by 0 or more lines with leading space. Blocks are
4368 effectively a high-level command with additional metadata.
4375 effectively a high-level command with additional metadata.
4369
4376
4370 Lines beginning with ``#`` are ignored.
4377 Lines beginning with ``#`` are ignored.
4371
4378
4372 The following sections denote available actions.
4379 The following sections denote available actions.
4373
4380
4374 raw
4381 raw
4375 ---
4382 ---
4376
4383
4377 Send raw data to the server.
4384 Send raw data to the server.
4378
4385
4379 The block payload contains the raw data to send as one atomic send
4386 The block payload contains the raw data to send as one atomic send
4380 operation. The data may not actually be delivered in a single system
4387 operation. The data may not actually be delivered in a single system
4381 call: it depends on the abilities of the transport being used.
4388 call: it depends on the abilities of the transport being used.
4382
4389
4383 Each line in the block is de-indented and concatenated. Then, that
4390 Each line in the block is de-indented and concatenated. Then, that
4384 value is evaluated as a Python b'' literal. This allows the use of
4391 value is evaluated as a Python b'' literal. This allows the use of
4385 backslash escaping, etc.
4392 backslash escaping, etc.
4386
4393
4387 raw+
4394 raw+
4388 ----
4395 ----
4389
4396
4390 Behaves like ``raw`` except flushes output afterwards.
4397 Behaves like ``raw`` except flushes output afterwards.
4391
4398
4392 command <X>
4399 command <X>
4393 -----------
4400 -----------
4394
4401
4395 Send a request to run a named command, whose name follows the ``command``
4402 Send a request to run a named command, whose name follows the ``command``
4396 string.
4403 string.
4397
4404
4398 Arguments to the command are defined as lines in this block. The format of
4405 Arguments to the command are defined as lines in this block. The format of
4399 each line is ``<key> <value>``. e.g.::
4406 each line is ``<key> <value>``. e.g.::
4400
4407
4401 command listkeys
4408 command listkeys
4402 namespace bookmarks
4409 namespace bookmarks
4403
4410
4404 If the value begins with ``eval:``, it will be interpreted as a Python
4411 If the value begins with ``eval:``, it will be interpreted as a Python
4405 literal expression. Otherwise values are interpreted as Python b'' literals.
4412 literal expression. Otherwise values are interpreted as Python b'' literals.
4406 This allows sending complex types and encoding special byte sequences via
4413 This allows sending complex types and encoding special byte sequences via
4407 backslash escaping.
4414 backslash escaping.
4408
4415
4409 The following arguments have special meaning:
4416 The following arguments have special meaning:
4410
4417
4411 ``PUSHFILE``
4418 ``PUSHFILE``
4412 When defined, the *push* mechanism of the peer will be used instead
4419 When defined, the *push* mechanism of the peer will be used instead
4413 of the static request-response mechanism and the content of the
4420 of the static request-response mechanism and the content of the
4414 file specified in the value of this argument will be sent as the
4421 file specified in the value of this argument will be sent as the
4415 command payload.
4422 command payload.
4416
4423
4417 This can be used to submit a local bundle file to the remote.
4424 This can be used to submit a local bundle file to the remote.
4418
4425
4419 batchbegin
4426 batchbegin
4420 ----------
4427 ----------
4421
4428
4422 Instruct the peer to begin a batched send.
4429 Instruct the peer to begin a batched send.
4423
4430
4424 All ``command`` blocks are queued for execution until the next
4431 All ``command`` blocks are queued for execution until the next
4425 ``batchsubmit`` block.
4432 ``batchsubmit`` block.
4426
4433
4427 batchsubmit
4434 batchsubmit
4428 -----------
4435 -----------
4429
4436
4430 Submit previously queued ``command`` blocks as a batch request.
4437 Submit previously queued ``command`` blocks as a batch request.
4431
4438
4432 This action MUST be paired with a ``batchbegin`` action.
4439 This action MUST be paired with a ``batchbegin`` action.
4433
4440
4434 httprequest <method> <path>
4441 httprequest <method> <path>
4435 ---------------------------
4442 ---------------------------
4436
4443
4437 (HTTP peer only)
4444 (HTTP peer only)
4438
4445
4439 Send an HTTP request to the peer.
4446 Send an HTTP request to the peer.
4440
4447
4441 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
4448 The HTTP request line follows the ``httprequest`` action. e.g. ``GET /foo``.
4442
4449
4443 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
4450 Arguments of the form ``<key>: <value>`` are interpreted as HTTP request
4444 headers to add to the request. e.g. ``Accept: foo``.
4451 headers to add to the request. e.g. ``Accept: foo``.
4445
4452
4446 The following arguments are special:
4453 The following arguments are special:
4447
4454
4448 ``BODYFILE``
4455 ``BODYFILE``
4449 The content of the file defined as the value to this argument will be
4456 The content of the file defined as the value to this argument will be
4450 transferred verbatim as the HTTP request body.
4457 transferred verbatim as the HTTP request body.
4451
4458
4452 ``frame <type> <flags> <payload>``
4459 ``frame <type> <flags> <payload>``
4453 Send a unified protocol frame as part of the request body.
4460 Send a unified protocol frame as part of the request body.
4454
4461
4455 All frames will be collected and sent as the body to the HTTP
4462 All frames will be collected and sent as the body to the HTTP
4456 request.
4463 request.
4457
4464
4458 close
4465 close
4459 -----
4466 -----
4460
4467
4461 Close the connection to the server.
4468 Close the connection to the server.
4462
4469
4463 flush
4470 flush
4464 -----
4471 -----
4465
4472
4466 Flush data written to the server.
4473 Flush data written to the server.
4467
4474
4468 readavailable
4475 readavailable
4469 -------------
4476 -------------
4470
4477
4471 Close the write end of the connection and read all available data from
4478 Close the write end of the connection and read all available data from
4472 the server.
4479 the server.
4473
4480
4474 If the connection to the server encompasses multiple pipes, we poll both
4481 If the connection to the server encompasses multiple pipes, we poll both
4475 pipes and read available data.
4482 pipes and read available data.
4476
4483
4477 readline
4484 readline
4478 --------
4485 --------
4479
4486
4480 Read a line of output from the server. If there are multiple output
4487 Read a line of output from the server. If there are multiple output
4481 pipes, reads only the main pipe.
4488 pipes, reads only the main pipe.
4482
4489
4483 ereadline
4490 ereadline
4484 ---------
4491 ---------
4485
4492
4486 Like ``readline``, but read from the stderr pipe, if available.
4493 Like ``readline``, but read from the stderr pipe, if available.
4487
4494
4488 read <X>
4495 read <X>
4489 --------
4496 --------
4490
4497
4491 ``read()`` N bytes from the server's main output pipe.
4498 ``read()`` N bytes from the server's main output pipe.
4492
4499
4493 eread <X>
4500 eread <X>
4494 ---------
4501 ---------
4495
4502
4496 ``read()`` N bytes from the server's stderr pipe, if available.
4503 ``read()`` N bytes from the server's stderr pipe, if available.
4497
4504
4498 Specifying Unified Frame-Based Protocol Frames
4505 Specifying Unified Frame-Based Protocol Frames
4499 ----------------------------------------------
4506 ----------------------------------------------
4500
4507
4501 It is possible to emit a *Unified Frame-Based Protocol* by using special
4508 It is possible to emit a *Unified Frame-Based Protocol* by using special
4502 syntax.
4509 syntax.
4503
4510
4504 A frame is composed as a type, flags, and payload. These can be parsed
4511 A frame is composed as a type, flags, and payload. These can be parsed
4505 from a string of the form:
4512 from a string of the form:
4506
4513
4507 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
4514 <request-id> <stream-id> <stream-flags> <type> <flags> <payload>
4508
4515
4509 ``request-id`` and ``stream-id`` are integers defining the request and
4516 ``request-id`` and ``stream-id`` are integers defining the request and
4510 stream identifiers.
4517 stream identifiers.
4511
4518
4512 ``type`` can be an integer value for the frame type or the string name
4519 ``type`` can be an integer value for the frame type or the string name
4513 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
4520 of the type. The strings are defined in ``wireprotoframing.py``. e.g.
4514 ``command-name``.
4521 ``command-name``.
4515
4522
4516 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
4523 ``stream-flags`` and ``flags`` are a ``|`` delimited list of flag
4517 components. Each component (and there can be just one) can be an integer
4524 components. Each component (and there can be just one) can be an integer
4518 or a flag name for stream flags or frame flags, respectively. Values are
4525 or a flag name for stream flags or frame flags, respectively. Values are
4519 resolved to integers and then bitwise OR'd together.
4526 resolved to integers and then bitwise OR'd together.
4520
4527
4521 ``payload`` represents the raw frame payload. If it begins with
4528 ``payload`` represents the raw frame payload. If it begins with
4522 ``cbor:``, the following string is evaluated as Python code and the
4529 ``cbor:``, the following string is evaluated as Python code and the
4523 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
4530 resulting object is fed into a CBOR encoder. Otherwise it is interpreted
4524 as a Python byte string literal.
4531 as a Python byte string literal.
4525 """
4532 """
4526 opts = pycompat.byteskwargs(opts)
4533 opts = pycompat.byteskwargs(opts)
4527
4534
4528 if opts[b'localssh'] and not repo:
4535 if opts[b'localssh'] and not repo:
4529 raise error.Abort(_(b'--localssh requires a repository'))
4536 raise error.Abort(_(b'--localssh requires a repository'))
4530
4537
4531 if opts[b'peer'] and opts[b'peer'] not in (
4538 if opts[b'peer'] and opts[b'peer'] not in (
4532 b'raw',
4539 b'raw',
4533 b'ssh1',
4540 b'ssh1',
4534 ):
4541 ):
4535 raise error.Abort(
4542 raise error.Abort(
4536 _(b'invalid value for --peer'),
4543 _(b'invalid value for --peer'),
4537 hint=_(b'valid values are "raw" and "ssh1"'),
4544 hint=_(b'valid values are "raw" and "ssh1"'),
4538 )
4545 )
4539
4546
4540 if path and opts[b'localssh']:
4547 if path and opts[b'localssh']:
4541 raise error.Abort(_(b'cannot specify --localssh with an explicit path'))
4548 raise error.Abort(_(b'cannot specify --localssh with an explicit path'))
4542
4549
4543 if ui.interactive():
4550 if ui.interactive():
4544 ui.write(_(b'(waiting for commands on stdin)\n'))
4551 ui.write(_(b'(waiting for commands on stdin)\n'))
4545
4552
4546 blocks = list(_parsewirelangblocks(ui.fin))
4553 blocks = list(_parsewirelangblocks(ui.fin))
4547
4554
4548 proc = None
4555 proc = None
4549 stdin = None
4556 stdin = None
4550 stdout = None
4557 stdout = None
4551 stderr = None
4558 stderr = None
4552 opener = None
4559 opener = None
4553
4560
4554 if opts[b'localssh']:
4561 if opts[b'localssh']:
4555 # We start the SSH server in its own process so there is process
4562 # We start the SSH server in its own process so there is process
4556 # separation. This prevents a whole class of potential bugs around
4563 # separation. This prevents a whole class of potential bugs around
4557 # shared state from interfering with server operation.
4564 # shared state from interfering with server operation.
4558 args = procutil.hgcmd() + [
4565 args = procutil.hgcmd() + [
4559 b'-R',
4566 b'-R',
4560 repo.root,
4567 repo.root,
4561 b'debugserve',
4568 b'debugserve',
4562 b'--sshstdio',
4569 b'--sshstdio',
4563 ]
4570 ]
4564 proc = subprocess.Popen(
4571 proc = subprocess.Popen(
4565 pycompat.rapply(procutil.tonativestr, args),
4572 pycompat.rapply(procutil.tonativestr, args),
4566 stdin=subprocess.PIPE,
4573 stdin=subprocess.PIPE,
4567 stdout=subprocess.PIPE,
4574 stdout=subprocess.PIPE,
4568 stderr=subprocess.PIPE,
4575 stderr=subprocess.PIPE,
4569 bufsize=0,
4576 bufsize=0,
4570 )
4577 )
4571
4578
4572 stdin = proc.stdin
4579 stdin = proc.stdin
4573 stdout = proc.stdout
4580 stdout = proc.stdout
4574 stderr = proc.stderr
4581 stderr = proc.stderr
4575
4582
4576 # We turn the pipes into observers so we can log I/O.
4583 # We turn the pipes into observers so we can log I/O.
4577 if ui.verbose or opts[b'peer'] == b'raw':
4584 if ui.verbose or opts[b'peer'] == b'raw':
4578 stdin = util.makeloggingfileobject(
4585 stdin = util.makeloggingfileobject(
4579 ui, proc.stdin, b'i', logdata=True
4586 ui, proc.stdin, b'i', logdata=True
4580 )
4587 )
4581 stdout = util.makeloggingfileobject(
4588 stdout = util.makeloggingfileobject(
4582 ui, proc.stdout, b'o', logdata=True
4589 ui, proc.stdout, b'o', logdata=True
4583 )
4590 )
4584 stderr = util.makeloggingfileobject(
4591 stderr = util.makeloggingfileobject(
4585 ui, proc.stderr, b'e', logdata=True
4592 ui, proc.stderr, b'e', logdata=True
4586 )
4593 )
4587
4594
4588 # --localssh also implies the peer connection settings.
4595 # --localssh also implies the peer connection settings.
4589
4596
4590 url = b'ssh://localserver'
4597 url = b'ssh://localserver'
4591 autoreadstderr = not opts[b'noreadstderr']
4598 autoreadstderr = not opts[b'noreadstderr']
4592
4599
4593 if opts[b'peer'] == b'ssh1':
4600 if opts[b'peer'] == b'ssh1':
4594 ui.write(_(b'creating ssh peer for wire protocol version 1\n'))
4601 ui.write(_(b'creating ssh peer for wire protocol version 1\n'))
4595 peer = sshpeer.sshv1peer(
4602 peer = sshpeer.sshv1peer(
4596 ui,
4603 ui,
4597 url,
4604 url,
4598 proc,
4605 proc,
4599 stdin,
4606 stdin,
4600 stdout,
4607 stdout,
4601 stderr,
4608 stderr,
4602 None,
4609 None,
4603 autoreadstderr=autoreadstderr,
4610 autoreadstderr=autoreadstderr,
4604 )
4611 )
4605 elif opts[b'peer'] == b'raw':
4612 elif opts[b'peer'] == b'raw':
4606 ui.write(_(b'using raw connection to peer\n'))
4613 ui.write(_(b'using raw connection to peer\n'))
4607 peer = None
4614 peer = None
4608 else:
4615 else:
4609 ui.write(_(b'creating ssh peer from handshake results\n'))
4616 ui.write(_(b'creating ssh peer from handshake results\n'))
4610 peer = sshpeer.makepeer(
4617 peer = sshpeer.makepeer(
4611 ui,
4618 ui,
4612 url,
4619 url,
4613 proc,
4620 proc,
4614 stdin,
4621 stdin,
4615 stdout,
4622 stdout,
4616 stderr,
4623 stderr,
4617 autoreadstderr=autoreadstderr,
4624 autoreadstderr=autoreadstderr,
4618 )
4625 )
4619
4626
4620 elif path:
4627 elif path:
4621 # We bypass hg.peer() so we can proxy the sockets.
4628 # We bypass hg.peer() so we can proxy the sockets.
4622 # TODO consider not doing this because we skip
4629 # TODO consider not doing this because we skip
4623 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
4630 # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
4624 u = urlutil.url(path)
4631 u = urlutil.url(path)
4625 if u.scheme != b'http':
4632 if u.scheme != b'http':
4626 raise error.Abort(_(b'only http:// paths are currently supported'))
4633 raise error.Abort(_(b'only http:// paths are currently supported'))
4627
4634
4628 url, authinfo = u.authinfo()
4635 url, authinfo = u.authinfo()
4629 openerargs = {
4636 openerargs = {
4630 'useragent': b'Mercurial debugwireproto',
4637 'useragent': b'Mercurial debugwireproto',
4631 }
4638 }
4632
4639
4633 # Turn pipes/sockets into observers so we can log I/O.
4640 # Turn pipes/sockets into observers so we can log I/O.
4634 if ui.verbose:
4641 if ui.verbose:
4635 openerargs.update(
4642 openerargs.update(
4636 {
4643 {
4637 'loggingfh': ui,
4644 'loggingfh': ui,
4638 'loggingname': b's',
4645 'loggingname': b's',
4639 'loggingopts': {
4646 'loggingopts': {
4640 'logdata': True,
4647 'logdata': True,
4641 'logdataapis': False,
4648 'logdataapis': False,
4642 },
4649 },
4643 }
4650 }
4644 )
4651 )
4645
4652
4646 if ui.debugflag:
4653 if ui.debugflag:
4647 openerargs['loggingopts']['logdataapis'] = True
4654 openerargs['loggingopts']['logdataapis'] = True
4648
4655
4649 # Don't send default headers when in raw mode. This allows us to
4656 # Don't send default headers when in raw mode. This allows us to
4650 # bypass most of the behavior of our URL handling code so we can
4657 # bypass most of the behavior of our URL handling code so we can
4651 # have near complete control over what's sent on the wire.
4658 # have near complete control over what's sent on the wire.
4652 if opts[b'peer'] == b'raw':
4659 if opts[b'peer'] == b'raw':
4653 openerargs['sendaccept'] = False
4660 openerargs['sendaccept'] = False
4654
4661
4655 opener = urlmod.opener(ui, authinfo, **openerargs)
4662 opener = urlmod.opener(ui, authinfo, **openerargs)
4656
4663
4657 if opts[b'peer'] == b'raw':
4664 if opts[b'peer'] == b'raw':
4658 ui.write(_(b'using raw connection to peer\n'))
4665 ui.write(_(b'using raw connection to peer\n'))
4659 peer = None
4666 peer = None
4660 elif opts[b'peer']:
4667 elif opts[b'peer']:
4661 raise error.Abort(
4668 raise error.Abort(
4662 _(b'--peer %s not supported with HTTP peers') % opts[b'peer']
4669 _(b'--peer %s not supported with HTTP peers') % opts[b'peer']
4663 )
4670 )
4664 else:
4671 else:
4665 peer = httppeer.makepeer(ui, path, opener=opener)
4672 peer = httppeer.makepeer(ui, path, opener=opener)
4666
4673
4667 # We /could/ populate stdin/stdout with sock.makefile()...
4674 # We /could/ populate stdin/stdout with sock.makefile()...
4668 else:
4675 else:
4669 raise error.Abort(_(b'unsupported connection configuration'))
4676 raise error.Abort(_(b'unsupported connection configuration'))
4670
4677
4671 batchedcommands = None
4678 batchedcommands = None
4672
4679
4673 # Now perform actions based on the parsed wire language instructions.
4680 # Now perform actions based on the parsed wire language instructions.
4674 for action, lines in blocks:
4681 for action, lines in blocks:
4675 if action in (b'raw', b'raw+'):
4682 if action in (b'raw', b'raw+'):
4676 if not stdin:
4683 if not stdin:
4677 raise error.Abort(_(b'cannot call raw/raw+ on this peer'))
4684 raise error.Abort(_(b'cannot call raw/raw+ on this peer'))
4678
4685
4679 # Concatenate the data together.
4686 # Concatenate the data together.
4680 data = b''.join(l.lstrip() for l in lines)
4687 data = b''.join(l.lstrip() for l in lines)
4681 data = stringutil.unescapestr(data)
4688 data = stringutil.unescapestr(data)
4682 stdin.write(data)
4689 stdin.write(data)
4683
4690
4684 if action == b'raw+':
4691 if action == b'raw+':
4685 stdin.flush()
4692 stdin.flush()
4686 elif action == b'flush':
4693 elif action == b'flush':
4687 if not stdin:
4694 if not stdin:
4688 raise error.Abort(_(b'cannot call flush on this peer'))
4695 raise error.Abort(_(b'cannot call flush on this peer'))
4689 stdin.flush()
4696 stdin.flush()
4690 elif action.startswith(b'command'):
4697 elif action.startswith(b'command'):
4691 if not peer:
4698 if not peer:
4692 raise error.Abort(
4699 raise error.Abort(
4693 _(
4700 _(
4694 b'cannot send commands unless peer instance '
4701 b'cannot send commands unless peer instance '
4695 b'is available'
4702 b'is available'
4696 )
4703 )
4697 )
4704 )
4698
4705
4699 command = action.split(b' ', 1)[1]
4706 command = action.split(b' ', 1)[1]
4700
4707
4701 args = {}
4708 args = {}
4702 for line in lines:
4709 for line in lines:
4703 # We need to allow empty values.
4710 # We need to allow empty values.
4704 fields = line.lstrip().split(b' ', 1)
4711 fields = line.lstrip().split(b' ', 1)
4705 if len(fields) == 1:
4712 if len(fields) == 1:
4706 key = fields[0]
4713 key = fields[0]
4707 value = b''
4714 value = b''
4708 else:
4715 else:
4709 key, value = fields
4716 key, value = fields
4710
4717
4711 if value.startswith(b'eval:'):
4718 if value.startswith(b'eval:'):
4712 value = stringutil.evalpythonliteral(value[5:])
4719 value = stringutil.evalpythonliteral(value[5:])
4713 else:
4720 else:
4714 value = stringutil.unescapestr(value)
4721 value = stringutil.unescapestr(value)
4715
4722
4716 args[key] = value
4723 args[key] = value
4717
4724
4718 if batchedcommands is not None:
4725 if batchedcommands is not None:
4719 batchedcommands.append((command, args))
4726 batchedcommands.append((command, args))
4720 continue
4727 continue
4721
4728
4722 ui.status(_(b'sending %s command\n') % command)
4729 ui.status(_(b'sending %s command\n') % command)
4723
4730
4724 if b'PUSHFILE' in args:
4731 if b'PUSHFILE' in args:
4725 with open(args[b'PUSHFILE'], 'rb') as fh:
4732 with open(args[b'PUSHFILE'], 'rb') as fh:
4726 del args[b'PUSHFILE']
4733 del args[b'PUSHFILE']
4727 res, output = peer._callpush(
4734 res, output = peer._callpush(
4728 command, fh, **pycompat.strkwargs(args)
4735 command, fh, **pycompat.strkwargs(args)
4729 )
4736 )
4730 ui.status(_(b'result: %s\n') % stringutil.escapestr(res))
4737 ui.status(_(b'result: %s\n') % stringutil.escapestr(res))
4731 ui.status(
4738 ui.status(
4732 _(b'remote output: %s\n') % stringutil.escapestr(output)
4739 _(b'remote output: %s\n') % stringutil.escapestr(output)
4733 )
4740 )
4734 else:
4741 else:
4735 with peer.commandexecutor() as e:
4742 with peer.commandexecutor() as e:
4736 res = e.callcommand(command, args).result()
4743 res = e.callcommand(command, args).result()
4737
4744
4738 ui.status(
4745 ui.status(
4739 _(b'response: %s\n')
4746 _(b'response: %s\n')
4740 % stringutil.pprint(res, bprefix=True, indent=2)
4747 % stringutil.pprint(res, bprefix=True, indent=2)
4741 )
4748 )
4742
4749
4743 elif action == b'batchbegin':
4750 elif action == b'batchbegin':
4744 if batchedcommands is not None:
4751 if batchedcommands is not None:
4745 raise error.Abort(_(b'nested batchbegin not allowed'))
4752 raise error.Abort(_(b'nested batchbegin not allowed'))
4746
4753
4747 batchedcommands = []
4754 batchedcommands = []
4748 elif action == b'batchsubmit':
4755 elif action == b'batchsubmit':
4749 # There is a batching API we could go through. But it would be
4756 # There is a batching API we could go through. But it would be
4750 # difficult to normalize requests into function calls. It is easier
4757 # difficult to normalize requests into function calls. It is easier
4751 # to bypass this layer and normalize to commands + args.
4758 # to bypass this layer and normalize to commands + args.
4752 ui.status(
4759 ui.status(
4753 _(b'sending batch with %d sub-commands\n')
4760 _(b'sending batch with %d sub-commands\n')
4754 % len(batchedcommands)
4761 % len(batchedcommands)
4755 )
4762 )
4756 assert peer is not None
4763 assert peer is not None
4757 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
4764 for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
4758 ui.status(
4765 ui.status(
4759 _(b'response #%d: %s\n') % (i, stringutil.escapestr(chunk))
4766 _(b'response #%d: %s\n') % (i, stringutil.escapestr(chunk))
4760 )
4767 )
4761
4768
4762 batchedcommands = None
4769 batchedcommands = None
4763
4770
4764 elif action.startswith(b'httprequest '):
4771 elif action.startswith(b'httprequest '):
4765 if not opener:
4772 if not opener:
4766 raise error.Abort(
4773 raise error.Abort(
4767 _(b'cannot use httprequest without an HTTP peer')
4774 _(b'cannot use httprequest without an HTTP peer')
4768 )
4775 )
4769
4776
4770 request = action.split(b' ', 2)
4777 request = action.split(b' ', 2)
4771 if len(request) != 3:
4778 if len(request) != 3:
4772 raise error.Abort(
4779 raise error.Abort(
4773 _(
4780 _(
4774 b'invalid httprequest: expected format is '
4781 b'invalid httprequest: expected format is '
4775 b'"httprequest <method> <path>'
4782 b'"httprequest <method> <path>'
4776 )
4783 )
4777 )
4784 )
4778
4785
4779 method, httppath = request[1:]
4786 method, httppath = request[1:]
4780 headers = {}
4787 headers = {}
4781 body = None
4788 body = None
4782 frames = []
4789 frames = []
4783 for line in lines:
4790 for line in lines:
4784 line = line.lstrip()
4791 line = line.lstrip()
4785 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
4792 m = re.match(b'^([a-zA-Z0-9_-]+): (.*)$', line)
4786 if m:
4793 if m:
4787 # Headers need to use native strings.
4794 # Headers need to use native strings.
4788 key = pycompat.strurl(m.group(1))
4795 key = pycompat.strurl(m.group(1))
4789 value = pycompat.strurl(m.group(2))
4796 value = pycompat.strurl(m.group(2))
4790 headers[key] = value
4797 headers[key] = value
4791 continue
4798 continue
4792
4799
4793 if line.startswith(b'BODYFILE '):
4800 if line.startswith(b'BODYFILE '):
4794 with open(line.split(b' ', 1), b'rb') as fh:
4801 with open(line.split(b' ', 1), b'rb') as fh:
4795 body = fh.read()
4802 body = fh.read()
4796 elif line.startswith(b'frame '):
4803 elif line.startswith(b'frame '):
4797 frame = wireprotoframing.makeframefromhumanstring(
4804 frame = wireprotoframing.makeframefromhumanstring(
4798 line[len(b'frame ') :]
4805 line[len(b'frame ') :]
4799 )
4806 )
4800
4807
4801 frames.append(frame)
4808 frames.append(frame)
4802 else:
4809 else:
4803 raise error.Abort(
4810 raise error.Abort(
4804 _(b'unknown argument to httprequest: %s') % line
4811 _(b'unknown argument to httprequest: %s') % line
4805 )
4812 )
4806
4813
4807 url = path + httppath
4814 url = path + httppath
4808
4815
4809 if frames:
4816 if frames:
4810 body = b''.join(bytes(f) for f in frames)
4817 body = b''.join(bytes(f) for f in frames)
4811
4818
4812 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
4819 req = urlmod.urlreq.request(pycompat.strurl(url), body, headers)
4813
4820
4814 # urllib.Request insists on using has_data() as a proxy for
4821 # urllib.Request insists on using has_data() as a proxy for
4815 # determining the request method. Override that to use our
4822 # determining the request method. Override that to use our
4816 # explicitly requested method.
4823 # explicitly requested method.
4817 req.get_method = lambda: pycompat.sysstr(method)
4824 req.get_method = lambda: pycompat.sysstr(method)
4818
4825
4819 try:
4826 try:
4820 res = opener.open(req)
4827 res = opener.open(req)
4821 body = res.read()
4828 body = res.read()
4822 except util.urlerr.urlerror as e:
4829 except util.urlerr.urlerror as e:
4823 # read() method must be called, but only exists in Python 2
4830 # read() method must be called, but only exists in Python 2
4824 getattr(e, 'read', lambda: None)()
4831 getattr(e, 'read', lambda: None)()
4825 continue
4832 continue
4826
4833
4827 ct = res.headers.get('Content-Type')
4834 ct = res.headers.get('Content-Type')
4828 if ct == 'application/mercurial-cbor':
4835 if ct == 'application/mercurial-cbor':
4829 ui.write(
4836 ui.write(
4830 _(b'cbor> %s\n')
4837 _(b'cbor> %s\n')
4831 % stringutil.pprint(
4838 % stringutil.pprint(
4832 cborutil.decodeall(body), bprefix=True, indent=2
4839 cborutil.decodeall(body), bprefix=True, indent=2
4833 )
4840 )
4834 )
4841 )
4835
4842
4836 elif action == b'close':
4843 elif action == b'close':
4837 assert peer is not None
4844 assert peer is not None
4838 peer.close()
4845 peer.close()
4839 elif action == b'readavailable':
4846 elif action == b'readavailable':
4840 if not stdout or not stderr:
4847 if not stdout or not stderr:
4841 raise error.Abort(
4848 raise error.Abort(
4842 _(b'readavailable not available on this peer')
4849 _(b'readavailable not available on this peer')
4843 )
4850 )
4844
4851
4845 stdin.close()
4852 stdin.close()
4846 stdout.read()
4853 stdout.read()
4847 stderr.read()
4854 stderr.read()
4848
4855
4849 elif action == b'readline':
4856 elif action == b'readline':
4850 if not stdout:
4857 if not stdout:
4851 raise error.Abort(_(b'readline not available on this peer'))
4858 raise error.Abort(_(b'readline not available on this peer'))
4852 stdout.readline()
4859 stdout.readline()
4853 elif action == b'ereadline':
4860 elif action == b'ereadline':
4854 if not stderr:
4861 if not stderr:
4855 raise error.Abort(_(b'ereadline not available on this peer'))
4862 raise error.Abort(_(b'ereadline not available on this peer'))
4856 stderr.readline()
4863 stderr.readline()
4857 elif action.startswith(b'read '):
4864 elif action.startswith(b'read '):
4858 count = int(action.split(b' ', 1)[1])
4865 count = int(action.split(b' ', 1)[1])
4859 if not stdout:
4866 if not stdout:
4860 raise error.Abort(_(b'read not available on this peer'))
4867 raise error.Abort(_(b'read not available on this peer'))
4861 stdout.read(count)
4868 stdout.read(count)
4862 elif action.startswith(b'eread '):
4869 elif action.startswith(b'eread '):
4863 count = int(action.split(b' ', 1)[1])
4870 count = int(action.split(b' ', 1)[1])
4864 if not stderr:
4871 if not stderr:
4865 raise error.Abort(_(b'eread not available on this peer'))
4872 raise error.Abort(_(b'eread not available on this peer'))
4866 stderr.read(count)
4873 stderr.read(count)
4867 else:
4874 else:
4868 raise error.Abort(_(b'unknown action: %s') % action)
4875 raise error.Abort(_(b'unknown action: %s') % action)
4869
4876
4870 if batchedcommands is not None:
4877 if batchedcommands is not None:
4871 raise error.Abort(_(b'unclosed "batchbegin" request'))
4878 raise error.Abort(_(b'unclosed "batchbegin" request'))
4872
4879
4873 if peer:
4880 if peer:
4874 peer.close()
4881 peer.close()
4875
4882
4876 if proc:
4883 if proc:
4877 proc.kill()
4884 proc.kill()
@@ -1,447 +1,447 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 abort
3 abort
4 add
4 add
5 addremove
5 addremove
6 annotate
6 annotate
7 archive
7 archive
8 backout
8 backout
9 bisect
9 bisect
10 bookmarks
10 bookmarks
11 branch
11 branch
12 branches
12 branches
13 bundle
13 bundle
14 cat
14 cat
15 clone
15 clone
16 commit
16 commit
17 config
17 config
18 continue
18 continue
19 copy
19 copy
20 diff
20 diff
21 export
21 export
22 files
22 files
23 forget
23 forget
24 graft
24 graft
25 grep
25 grep
26 heads
26 heads
27 help
27 help
28 identify
28 identify
29 import
29 import
30 incoming
30 incoming
31 init
31 init
32 locate
32 locate
33 log
33 log
34 manifest
34 manifest
35 merge
35 merge
36 outgoing
36 outgoing
37 parents
37 parents
38 paths
38 paths
39 phase
39 phase
40 pull
40 pull
41 purge
41 purge
42 push
42 push
43 recover
43 recover
44 remove
44 remove
45 rename
45 rename
46 resolve
46 resolve
47 revert
47 revert
48 rollback
48 rollback
49 root
49 root
50 serve
50 serve
51 shelve
51 shelve
52 status
52 status
53 summary
53 summary
54 tag
54 tag
55 tags
55 tags
56 tip
56 tip
57 unbundle
57 unbundle
58 unshelve
58 unshelve
59 update
59 update
60 verify
60 verify
61 version
61 version
62
62
63 Show all commands that start with "a"
63 Show all commands that start with "a"
64 $ hg debugcomplete a
64 $ hg debugcomplete a
65 abort
65 abort
66 add
66 add
67 addremove
67 addremove
68 annotate
68 annotate
69 archive
69 archive
70
70
71 Do not show debug commands if there are other candidates
71 Do not show debug commands if there are other candidates
72 $ hg debugcomplete d
72 $ hg debugcomplete d
73 diff
73 diff
74
74
75 Show debug commands if there are no other candidates
75 Show debug commands if there are no other candidates
76 $ hg debugcomplete debug
76 $ hg debugcomplete debug
77 debug-repair-issue6528
77 debug-repair-issue6528
78 debugancestor
78 debugancestor
79 debugantivirusrunning
79 debugantivirusrunning
80 debugapplystreamclonebundle
80 debugapplystreamclonebundle
81 debugbackupbundle
81 debugbackupbundle
82 debugbuilddag
82 debugbuilddag
83 debugbundle
83 debugbundle
84 debugcapabilities
84 debugcapabilities
85 debugchangedfiles
85 debugchangedfiles
86 debugcheckstate
86 debugcheckstate
87 debugcolor
87 debugcolor
88 debugcommands
88 debugcommands
89 debugcomplete
89 debugcomplete
90 debugconfig
90 debugconfig
91 debugcreatestreamclonebundle
91 debugcreatestreamclonebundle
92 debugdag
92 debugdag
93 debugdata
93 debugdata
94 debugdate
94 debugdate
95 debugdeltachain
95 debugdeltachain
96 debugdirstate
96 debugdirstate
97 debugdirstateignorepatternshash
97 debugdirstateignorepatternshash
98 debugdiscovery
98 debugdiscovery
99 debugdownload
99 debugdownload
100 debugextensions
100 debugextensions
101 debugfileset
101 debugfileset
102 debugformat
102 debugformat
103 debugfsinfo
103 debugfsinfo
104 debuggetbundle
104 debuggetbundle
105 debugignore
105 debugignore
106 debugindex
106 debugindex
107 debugindexdot
107 debugindexdot
108 debugindexstats
108 debugindexstats
109 debuginstall
109 debuginstall
110 debugknown
110 debugknown
111 debuglabelcomplete
111 debuglabelcomplete
112 debuglocks
112 debuglocks
113 debugmanifestfulltextcache
113 debugmanifestfulltextcache
114 debugmergestate
114 debugmergestate
115 debugnamecomplete
115 debugnamecomplete
116 debugnodemap
116 debugnodemap
117 debugobsolete
117 debugobsolete
118 debugp1copies
118 debugp1copies
119 debugp2copies
119 debugp2copies
120 debugpathcomplete
120 debugpathcomplete
121 debugpathcopies
121 debugpathcopies
122 debugpeer
122 debugpeer
123 debugpickmergetool
123 debugpickmergetool
124 debugpushkey
124 debugpushkey
125 debugpvec
125 debugpvec
126 debugrebuilddirstate
126 debugrebuilddirstate
127 debugrebuildfncache
127 debugrebuildfncache
128 debugrename
128 debugrename
129 debugrequires
129 debugrequires
130 debugrevlog
130 debugrevlog
131 debugrevlogindex
131 debugrevlogindex
132 debugrevspec
132 debugrevspec
133 debugserve
133 debugserve
134 debugsetparents
134 debugsetparents
135 debugshell
135 debugshell
136 debugsidedata
136 debugsidedata
137 debugssl
137 debugssl
138 debugstrip
138 debugstrip
139 debugsub
139 debugsub
140 debugsuccessorssets
140 debugsuccessorssets
141 debugtagscache
141 debugtagscache
142 debugtemplate
142 debugtemplate
143 debuguigetpass
143 debuguigetpass
144 debuguiprompt
144 debuguiprompt
145 debugupdatecaches
145 debugupdatecaches
146 debugupgraderepo
146 debugupgraderepo
147 debugwalk
147 debugwalk
148 debugwhyunstable
148 debugwhyunstable
149 debugwireargs
149 debugwireargs
150 debugwireproto
150 debugwireproto
151
151
152 Do not show the alias of a debug command if there are other candidates
152 Do not show the alias of a debug command if there are other candidates
153 (this should hide rawcommit)
153 (this should hide rawcommit)
154 $ hg debugcomplete r
154 $ hg debugcomplete r
155 recover
155 recover
156 remove
156 remove
157 rename
157 rename
158 resolve
158 resolve
159 revert
159 revert
160 rollback
160 rollback
161 root
161 root
162 Show the alias of a debug command if there are no other candidates
162 Show the alias of a debug command if there are no other candidates
163 $ hg debugcomplete rawc
163 $ hg debugcomplete rawc
164
164
165
165
166 Show the global options
166 Show the global options
167 $ hg debugcomplete --options | sort
167 $ hg debugcomplete --options | sort
168 --color
168 --color
169 --config
169 --config
170 --cwd
170 --cwd
171 --debug
171 --debug
172 --debugger
172 --debugger
173 --encoding
173 --encoding
174 --encodingmode
174 --encodingmode
175 --help
175 --help
176 --hidden
176 --hidden
177 --noninteractive
177 --noninteractive
178 --pager
178 --pager
179 --profile
179 --profile
180 --quiet
180 --quiet
181 --repository
181 --repository
182 --time
182 --time
183 --traceback
183 --traceback
184 --verbose
184 --verbose
185 --version
185 --version
186 -R
186 -R
187 -h
187 -h
188 -q
188 -q
189 -v
189 -v
190 -y
190 -y
191
191
192 Show the options for the "serve" command
192 Show the options for the "serve" command
193 $ hg debugcomplete --options serve | sort
193 $ hg debugcomplete --options serve | sort
194 --accesslog
194 --accesslog
195 --address
195 --address
196 --certificate
196 --certificate
197 --cmdserver
197 --cmdserver
198 --color
198 --color
199 --config
199 --config
200 --cwd
200 --cwd
201 --daemon
201 --daemon
202 --daemon-postexec
202 --daemon-postexec
203 --debug
203 --debug
204 --debugger
204 --debugger
205 --encoding
205 --encoding
206 --encodingmode
206 --encodingmode
207 --errorlog
207 --errorlog
208 --help
208 --help
209 --hidden
209 --hidden
210 --ipv6
210 --ipv6
211 --name
211 --name
212 --noninteractive
212 --noninteractive
213 --pager
213 --pager
214 --pid-file
214 --pid-file
215 --port
215 --port
216 --prefix
216 --prefix
217 --print-url
217 --print-url
218 --profile
218 --profile
219 --quiet
219 --quiet
220 --repository
220 --repository
221 --stdio
221 --stdio
222 --style
222 --style
223 --subrepos
223 --subrepos
224 --templates
224 --templates
225 --time
225 --time
226 --traceback
226 --traceback
227 --verbose
227 --verbose
228 --version
228 --version
229 --web-conf
229 --web-conf
230 -6
230 -6
231 -A
231 -A
232 -E
232 -E
233 -R
233 -R
234 -S
234 -S
235 -a
235 -a
236 -d
236 -d
237 -h
237 -h
238 -n
238 -n
239 -p
239 -p
240 -q
240 -q
241 -t
241 -t
242 -v
242 -v
243 -y
243 -y
244
244
245 Show an error if we use --options with an ambiguous abbreviation
245 Show an error if we use --options with an ambiguous abbreviation
246 $ hg debugcomplete --options s
246 $ hg debugcomplete --options s
247 hg: command 's' is ambiguous:
247 hg: command 's' is ambiguous:
248 serve shelve showconfig status summary
248 serve shelve showconfig status summary
249 [10]
249 [10]
250
250
251 Show all commands + options
251 Show all commands + options
252 $ hg debugcommands
252 $ hg debugcommands
253 abort: dry-run
253 abort: dry-run
254 add: include, exclude, subrepos, dry-run
254 add: include, exclude, subrepos, dry-run
255 addremove: similarity, subrepos, include, exclude, dry-run
255 addremove: similarity, subrepos, include, exclude, dry-run
256 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
256 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, skip, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, include, exclude, template
257 archive: no-decode, prefix, rev, type, subrepos, include, exclude
257 archive: no-decode, prefix, rev, type, subrepos, include, exclude
258 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
258 backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
259 bisect: reset, good, bad, skip, extend, command, noupdate
259 bisect: reset, good, bad, skip, extend, command, noupdate
260 bookmarks: force, rev, delete, rename, inactive, list, template
260 bookmarks: force, rev, delete, rename, inactive, list, template
261 branch: force, clean, rev
261 branch: force, clean, rev
262 branches: active, closed, rev, template
262 branches: active, closed, rev, template
263 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
263 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
264 cat: output, rev, decode, include, exclude, template
264 cat: output, rev, decode, include, exclude, template
265 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
265 clone: noupdate, updaterev, rev, branch, pull, uncompressed, stream, ssh, remotecmd, insecure
266 commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
266 commit: addremove, close-branch, amend, secret, edit, force-close-branch, interactive, include, exclude, message, logfile, date, user, subrepos
267 config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template
267 config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template
268 continue: dry-run
268 continue: dry-run
269 copy: forget, after, at-rev, force, include, exclude, dry-run
269 copy: forget, after, at-rev, force, include, exclude, dry-run
270 debug-repair-issue6528: to-report, from-report, paranoid, dry-run
270 debug-repair-issue6528: to-report, from-report, paranoid, dry-run
271 debugancestor:
271 debugancestor:
272 debugantivirusrunning:
272 debugantivirusrunning:
273 debugapplystreamclonebundle:
273 debugapplystreamclonebundle:
274 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
274 debugbackupbundle: recover, patch, git, limit, no-merges, stat, graph, style, template
275 debugbuilddag: mergeable-file, overwritten-file, new-file
275 debugbuilddag: mergeable-file, overwritten-file, new-file, from-existing
276 debugbundle: all, part-type, spec
276 debugbundle: all, part-type, spec
277 debugcapabilities:
277 debugcapabilities:
278 debugchangedfiles: compute
278 debugchangedfiles: compute
279 debugcheckstate:
279 debugcheckstate:
280 debugcolor: style
280 debugcolor: style
281 debugcommands:
281 debugcommands:
282 debugcomplete: options
282 debugcomplete: options
283 debugcreatestreamclonebundle:
283 debugcreatestreamclonebundle:
284 debugdag: tags, branches, dots, spaces
284 debugdag: tags, branches, dots, spaces
285 debugdata: changelog, manifest, dir
285 debugdata: changelog, manifest, dir
286 debugdate: extended
286 debugdate: extended
287 debugdeltachain: changelog, manifest, dir, template
287 debugdeltachain: changelog, manifest, dir, template
288 debugdirstateignorepatternshash:
288 debugdirstateignorepatternshash:
289 debugdirstate: nodates, dates, datesort, all
289 debugdirstate: nodates, dates, datesort, all
290 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
290 debugdiscovery: old, nonheads, rev, seed, local-as-revs, remote-as-revs, ssh, remotecmd, insecure, template
291 debugdownload: output
291 debugdownload: output
292 debugextensions: template
292 debugextensions: template
293 debugfileset: rev, all-files, show-matcher, show-stage
293 debugfileset: rev, all-files, show-matcher, show-stage
294 debugformat: template
294 debugformat: template
295 debugfsinfo:
295 debugfsinfo:
296 debuggetbundle: head, common, type
296 debuggetbundle: head, common, type
297 debugignore:
297 debugignore:
298 debugindex: changelog, manifest, dir, template
298 debugindex: changelog, manifest, dir, template
299 debugindexdot: changelog, manifest, dir
299 debugindexdot: changelog, manifest, dir
300 debugindexstats:
300 debugindexstats:
301 debuginstall: template
301 debuginstall: template
302 debugknown:
302 debugknown:
303 debuglabelcomplete:
303 debuglabelcomplete:
304 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
304 debuglocks: force-free-lock, force-free-wlock, set-lock, set-wlock
305 debugmanifestfulltextcache: clear, add
305 debugmanifestfulltextcache: clear, add
306 debugmergestate: style, template
306 debugmergestate: style, template
307 debugnamecomplete:
307 debugnamecomplete:
308 debugnodemap: dump-new, dump-disk, check, metadata
308 debugnodemap: dump-new, dump-disk, check, metadata
309 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
309 debugobsolete: flags, record-parents, rev, exclusive, index, delete, date, user, template
310 debugp1copies: rev
310 debugp1copies: rev
311 debugp2copies: rev
311 debugp2copies: rev
312 debugpathcomplete: full, normal, added, removed
312 debugpathcomplete: full, normal, added, removed
313 debugpathcopies: include, exclude
313 debugpathcopies: include, exclude
314 debugpeer:
314 debugpeer:
315 debugpickmergetool: rev, changedelete, include, exclude, tool
315 debugpickmergetool: rev, changedelete, include, exclude, tool
316 debugpushkey:
316 debugpushkey:
317 debugpvec:
317 debugpvec:
318 debugrebuilddirstate: rev, minimal
318 debugrebuilddirstate: rev, minimal
319 debugrebuildfncache: only-data
319 debugrebuildfncache: only-data
320 debugrename: rev
320 debugrename: rev
321 debugrequires:
321 debugrequires:
322 debugrevlog: changelog, manifest, dir, dump
322 debugrevlog: changelog, manifest, dir, dump
323 debugrevlogindex: changelog, manifest, dir, format
323 debugrevlogindex: changelog, manifest, dir, format
324 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
324 debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized
325 debugserve: sshstdio, logiofd, logiofile
325 debugserve: sshstdio, logiofd, logiofile
326 debugsetparents:
326 debugsetparents:
327 debugshell:
327 debugshell:
328 debugsidedata: changelog, manifest, dir
328 debugsidedata: changelog, manifest, dir
329 debugssl:
329 debugssl:
330 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
330 debugstrip: rev, force, no-backup, nobackup, , keep, bookmark, soft
331 debugsub: rev
331 debugsub: rev
332 debugsuccessorssets: closest
332 debugsuccessorssets: closest
333 debugtagscache:
333 debugtagscache:
334 debugtemplate: rev, define
334 debugtemplate: rev, define
335 debuguigetpass: prompt
335 debuguigetpass: prompt
336 debuguiprompt: prompt
336 debuguiprompt: prompt
337 debugupdatecaches:
337 debugupdatecaches:
338 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
338 debugupgraderepo: optimize, run, backup, changelog, manifest, filelogs
339 debugwalk: include, exclude
339 debugwalk: include, exclude
340 debugwhyunstable:
340 debugwhyunstable:
341 debugwireargs: three, four, five, ssh, remotecmd, insecure
341 debugwireargs: three, four, five, ssh, remotecmd, insecure
342 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
342 debugwireproto: localssh, peer, noreadstderr, nologhandshake, ssh, remotecmd, insecure
343 diff: rev, from, to, change, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
343 diff: rev, from, to, change, text, git, binary, nodates, noprefix, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, ignore-space-at-eol, unified, stat, root, include, exclude, subrepos
344 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
344 export: bookmark, output, switch-parent, rev, text, git, binary, nodates, template
345 files: rev, print0, include, exclude, template, subrepos
345 files: rev, print0, include, exclude, template, subrepos
346 forget: interactive, include, exclude, dry-run
346 forget: interactive, include, exclude, dry-run
347 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
347 graft: rev, base, continue, stop, abort, edit, log, no-commit, force, currentdate, currentuser, date, user, tool, dry-run
348 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
348 grep: print0, all, diff, text, follow, ignore-case, files-with-matches, line-number, rev, all-files, user, date, template, include, exclude
349 heads: rev, topo, active, closed, style, template
349 heads: rev, topo, active, closed, style, template
350 help: extension, command, keyword, system
350 help: extension, command, keyword, system
351 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
351 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure, template
352 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
352 import: strip, base, secret, edit, force, no-commit, bypass, partial, exact, prefix, import-branch, message, logfile, date, user, similarity
353 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
353 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
354 init: ssh, remotecmd, insecure
354 init: ssh, remotecmd, insecure
355 locate: rev, print0, fullpath, include, exclude
355 locate: rev, print0, fullpath, include, exclude
356 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, bookmark, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
356 log: follow, follow-first, date, copies, keyword, rev, line-range, removed, only-merges, user, only-branch, branch, bookmark, prune, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
357 manifest: rev, all, template
357 manifest: rev, all, template
358 merge: force, rev, preview, abort, tool
358 merge: force, rev, preview, abort, tool
359 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
359 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
360 parents: rev, style, template
360 parents: rev, style, template
361 paths: template
361 paths: template
362 phase: public, draft, secret, force, rev
362 phase: public, draft, secret, force, rev
363 pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure
363 pull: update, force, confirm, rev, bookmark, branch, ssh, remotecmd, insecure
364 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
364 purge: abort-on-err, all, ignored, dirs, files, print, print0, confirm, include, exclude
365 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
365 push: force, rev, bookmark, all-bookmarks, branch, new-branch, pushvars, publish, ssh, remotecmd, insecure
366 recover: verify
366 recover: verify
367 remove: after, force, subrepos, include, exclude, dry-run
367 remove: after, force, subrepos, include, exclude, dry-run
368 rename: forget, after, at-rev, force, include, exclude, dry-run
368 rename: forget, after, at-rev, force, include, exclude, dry-run
369 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
369 resolve: all, list, mark, unmark, no-status, re-merge, tool, include, exclude, template
370 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
370 revert: all, date, rev, no-backup, interactive, include, exclude, dry-run
371 rollback: dry-run, force
371 rollback: dry-run, force
372 root: template
372 root: template
373 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, print-url, subrepos
373 serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate, print-url, subrepos
374 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
374 shelve: addremove, unknown, cleanup, date, delete, edit, keep, list, message, name, patch, interactive, stat, include, exclude
375 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
375 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, terse, copies, print0, rev, change, include, exclude, subrepos, template
376 summary: remote
376 summary: remote
377 tag: force, local, rev, remove, edit, message, date, user
377 tag: force, local, rev, remove, edit, message, date, user
378 tags: template
378 tags: template
379 tip: patch, git, style, template
379 tip: patch, git, style, template
380 unbundle: update
380 unbundle: update
381 unshelve: abort, continue, interactive, keep, name, tool, date
381 unshelve: abort, continue, interactive, keep, name, tool, date
382 update: clean, check, merge, date, rev, tool
382 update: clean, check, merge, date, rev, tool
383 verify: full
383 verify: full
384 version: template
384 version: template
385
385
386 $ hg init a
386 $ hg init a
387 $ cd a
387 $ cd a
388 $ echo fee > fee
388 $ echo fee > fee
389 $ hg ci -q -Amfee
389 $ hg ci -q -Amfee
390 $ hg tag fee
390 $ hg tag fee
391 $ mkdir fie
391 $ mkdir fie
392 $ echo dead > fie/dead
392 $ echo dead > fie/dead
393 $ echo live > fie/live
393 $ echo live > fie/live
394 $ hg bookmark fo
394 $ hg bookmark fo
395 $ hg branch -q fie
395 $ hg branch -q fie
396 $ hg ci -q -Amfie
396 $ hg ci -q -Amfie
397 $ echo fo > fo
397 $ echo fo > fo
398 $ hg branch -qf default
398 $ hg branch -qf default
399 $ hg ci -q -Amfo
399 $ hg ci -q -Amfo
400 $ echo Fum > Fum
400 $ echo Fum > Fum
401 $ hg ci -q -AmFum
401 $ hg ci -q -AmFum
402 $ hg bookmark Fum
402 $ hg bookmark Fum
403
403
404 Test debugpathcomplete
404 Test debugpathcomplete
405
405
406 $ hg debugpathcomplete f
406 $ hg debugpathcomplete f
407 fee
407 fee
408 fie
408 fie
409 fo
409 fo
410 $ hg debugpathcomplete -f f
410 $ hg debugpathcomplete -f f
411 fee
411 fee
412 fie/dead
412 fie/dead
413 fie/live
413 fie/live
414 fo
414 fo
415
415
416 $ hg rm Fum
416 $ hg rm Fum
417 $ hg debugpathcomplete -r F
417 $ hg debugpathcomplete -r F
418 Fum
418 Fum
419
419
420 Test debugnamecomplete
420 Test debugnamecomplete
421
421
422 $ hg debugnamecomplete
422 $ hg debugnamecomplete
423 Fum
423 Fum
424 default
424 default
425 fee
425 fee
426 fie
426 fie
427 fo
427 fo
428 tip
428 tip
429 $ hg debugnamecomplete f
429 $ hg debugnamecomplete f
430 fee
430 fee
431 fie
431 fie
432 fo
432 fo
433
433
434 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
434 Test debuglabelcomplete, a deprecated name for debugnamecomplete that is still
435 used for completions in some shells.
435 used for completions in some shells.
436
436
437 $ hg debuglabelcomplete
437 $ hg debuglabelcomplete
438 Fum
438 Fum
439 default
439 default
440 fee
440 fee
441 fie
441 fie
442 fo
442 fo
443 tip
443 tip
444 $ hg debuglabelcomplete f
444 $ hg debuglabelcomplete f
445 fee
445 fee
446 fie
446 fie
447 fo
447 fo
General Comments 0
You need to be logged in to leave comments. Login now