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