Mercurial > hg
view doc/gendoc.py @ 44643:0437959de6f5
phabricator: record all local commits used to create a Differential revision
Arcanist records all of the commits that it squashes into a single review, and
that info will be helpful when adding similar functionality. This info is used
when submitting an updated review, so that the extension can recalculate the old
diff and see if a new one is necessary, or if it is just a property update. It
also shows on the `commits` tab in the `Revision Contents` section.
When submitting in the usual 1:1 commit to review mode, the wire protocol is
unchanged.
The content of `hg:meta` is a bit odd, but such is the problem when folding
several commits. The choice for the parent node is obvious, but the `node`
value uses the tip commit because that seems more natural, and is used elsewhere
to look up the previous diff when updating. The rest of the attributes follow
from there.
Differential Revision: https://phab.mercurial-scm.org/D8308
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Wed, 26 Feb 2020 13:13:49 -0500 |
parents | f0bee3b1b847 |
children | 1a4b9b602e54 |
line wrap: on
line source
#!/usr/bin/env python """usage: %s DOC ... where DOC is the name of a document """ from __future__ import absolute_import import os import sys import textwrap try: import msvcrt msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) except ImportError: pass # This script is executed during installs and may not have C extensions # available. Relax C module requirements. os.environ['HGMODULEPOLICY'] = 'allow' # import from the live mercurial repo sys.path.insert(0, "..") from mercurial import demandimport demandimport.enable() from mercurial import ( commands, encoding, extensions, help, minirst, pycompat, ui as uimod, ) from mercurial.i18n import ( gettext, _, ) table = commands.table globalopts = commands.globalopts helptable = help.helptable loaddoc = help.loaddoc def get_desc(docstr): if not docstr: return b"", b"" # sanitize docstr = docstr.strip(b"\n") docstr = docstr.rstrip() shortdesc = docstr.splitlines()[0].strip() i = docstr.find(b"\n") if i != -1: desc = docstr[i + 2 :] else: desc = shortdesc desc = textwrap.dedent(desc.decode('latin1')).encode('latin1') return (shortdesc, desc) def get_opts(opts): for opt in opts: if len(opt) == 5: shortopt, longopt, default, desc, optlabel = opt else: shortopt, longopt, default, desc = opt optlabel = _(b"VALUE") allopts = [] if shortopt: allopts.append(b"-%s" % shortopt) if longopt: allopts.append(b"--%s" % longopt) if isinstance(default, list): allopts[-1] += b" <%s[+]>" % optlabel elif (default is not None) and not isinstance(default, bool): allopts[-1] += b" <%s>" % optlabel if b'\n' in desc: # only remove line breaks and indentation desc = b' '.join(l.lstrip() for l in desc.split(b'\n')) desc += default and _(b" (default: %s)") % bytes(default) or b"" yield (b", ".join(allopts), desc) def get_cmd(cmd, cmdtable): d = {} attr = cmdtable[cmd] cmds = cmd.lstrip(b"^").split(b"|") d[b'cmd'] = cmds[0] d[b'aliases'] = cmd.split(b"|")[1:] d[b'desc'] = get_desc(gettext(pycompat.getdoc(attr[0]))) d[b'opts'] = list(get_opts(attr[1])) s = b'hg ' + cmds[0] if len(attr) > 2: if not attr[2].startswith(b'hg'): s += b' ' + attr[2] else: s = attr[2] d[b'synopsis'] = s.strip() return d def showdoc(ui): # print options ui.write(minirst.section(_(b"Options"))) multioccur = False for optstr, desc in get_opts(globalopts): ui.write(b"%s\n %s\n\n" % (optstr, desc)) if optstr.endswith(b"[+]>"): multioccur = True if multioccur: ui.write(_(b"\n[+] marked option can be specified multiple times\n")) ui.write(b"\n") # print cmds ui.write(minirst.section(_(b"Commands"))) commandprinter(ui, table, minirst.subsection, minirst.subsubsection) # print help topics # The config help topic is included in the hgrc.5 man page. helpprinter(ui, helptable, minirst.section, exclude=[b'config']) ui.write(minirst.section(_(b"Extensions"))) ui.write( _( b"This section contains help for extensions that are " b"distributed together with Mercurial. Help for other " b"extensions is available in the help system." ) ) ui.write( ( b"\n\n" b".. contents::\n" b" :class: htmlonly\n" b" :local:\n" b" :depth: 1\n\n" ) ) for extensionname in sorted(allextensionnames()): mod = extensions.load(ui, extensionname, None) ui.write(minirst.subsection(extensionname)) ui.write(b"%s\n\n" % gettext(pycompat.getdoc(mod))) cmdtable = getattr(mod, 'cmdtable', None) if cmdtable: ui.write(minirst.subsubsection(_(b'Commands'))) commandprinter( ui, cmdtable, minirst.subsubsubsection, minirst.subsubsubsubsection, ) def showtopic(ui, topic): extrahelptable = [ ([b"common"], b'', loaddoc(b'common'), help.TOPIC_CATEGORY_MISC), ([b"hg.1"], b'', loaddoc(b'hg.1'), help.TOPIC_CATEGORY_CONFIG), ([b"hg-ssh.8"], b'', loaddoc(b'hg-ssh.8'), help.TOPIC_CATEGORY_CONFIG), ( [b"hgignore.5"], b'', loaddoc(b'hgignore.5'), help.TOPIC_CATEGORY_CONFIG, ), ([b"hgrc.5"], b'', loaddoc(b'hgrc.5'), help.TOPIC_CATEGORY_CONFIG), ( [b"hgignore.5.gendoc"], b'', loaddoc(b'hgignore'), help.TOPIC_CATEGORY_CONFIG, ), ( [b"hgrc.5.gendoc"], b'', loaddoc(b'config'), help.TOPIC_CATEGORY_CONFIG, ), ] helpprinter(ui, helptable + extrahelptable, None, include=[topic]) def helpprinter(ui, helptable, sectionfunc, include=[], exclude=[]): for h in helptable: names, sec, doc = h[0:3] if exclude and names[0] in exclude: continue if include and names[0] not in include: continue for name in names: ui.write(b".. _%s:\n" % name) ui.write(b"\n") if sectionfunc: ui.write(sectionfunc(sec)) if callable(doc): doc = doc(ui) ui.write(doc) ui.write(b"\n") def commandprinter(ui, cmdtable, sectionfunc, subsectionfunc): """Render restructuredtext describing a list of commands and their documentations, grouped by command category. Args: ui: UI object to write the output to cmdtable: a dict that maps a string of the command name plus its aliases (separated with pipes) to a 3-tuple of (the command's function, a list of its option descriptions, and a string summarizing available options). Example, with aliases added for demonstration purposes: 'phase|alias1|alias2': ( <function phase at 0x7f0816b05e60>, [ ('p', 'public', False, 'set changeset phase to public'), ..., ('r', 'rev', [], 'target revision', 'REV')], '[-p|-d|-s] [-f] [-r] [REV...]' ) sectionfunc: minirst function to format command category headers subsectionfunc: minirst function to format command headers """ h = {} for c, attr in cmdtable.items(): f = c.split(b"|")[0] f = f.lstrip(b"^") h[f] = c cmds = h.keys() def helpcategory(cmd): """Given a canonical command name from `cmds` (above), retrieve its help category. If helpcategory is None, default to CATEGORY_NONE. """ fullname = h[cmd] details = cmdtable[fullname] helpcategory = details[0].helpcategory return helpcategory or help.registrar.command.CATEGORY_NONE cmdsbycategory = {category: [] for category in help.CATEGORY_ORDER} for cmd in cmds: # If a command category wasn't registered, the command won't get # rendered below, so we raise an AssertionError. if helpcategory(cmd) not in cmdsbycategory: raise AssertionError( "The following command did not register its (category) in " "help.CATEGORY_ORDER: %s (%s)" % (cmd, helpcategory(cmd)) ) cmdsbycategory[helpcategory(cmd)].append(cmd) # Print the help for each command. We present the commands grouped by # category, and we use help.CATEGORY_ORDER as a guide for a helpful order # in which to present the categories. for category in help.CATEGORY_ORDER: categorycmds = cmdsbycategory[category] if not categorycmds: # Skip empty categories continue # Print a section header for the category. # For now, the category header is at the same level as the headers for # the commands in the category; this is fixed in the next commit. ui.write(sectionfunc(help.CATEGORY_NAMES[category])) # Print each command in the category for f in sorted(categorycmds): if f.startswith(b"debug"): continue d = get_cmd(h[f], cmdtable) ui.write(subsectionfunc(d[b'cmd'])) # short description ui.write(d[b'desc'][0]) # synopsis ui.write(b"::\n\n") synopsislines = d[b'synopsis'].splitlines() for line in synopsislines: # some commands (such as rebase) have a multi-line # synopsis ui.write(b" %s\n" % line) ui.write(b'\n') # description ui.write(b"%s\n\n" % d[b'desc'][1]) # options opt_output = list(d[b'opts']) if opt_output: opts_len = max([len(line[0]) for line in opt_output]) ui.write(_(b"Options:\n\n")) multioccur = False for optstr, desc in opt_output: if desc: s = b"%-*s %s" % (opts_len, optstr, desc) else: s = optstr ui.write(b"%s\n" % s) if optstr.endswith(b"[+]>"): multioccur = True if multioccur: ui.write( _( b"\n[+] marked option can be specified" b" multiple times\n" ) ) ui.write(b"\n") # aliases if d[b'aliases']: ui.write(_(b" aliases: %s\n\n") % b" ".join(d[b'aliases'])) def allextensionnames(): return set(extensions.enabled().keys()) | set(extensions.disabled().keys()) if __name__ == "__main__": doc = b'hg.1.gendoc' if len(sys.argv) > 1: doc = encoding.strtolocal(sys.argv[1]) ui = uimod.ui.load() if doc == b'hg.1.gendoc': showdoc(ui) else: showtopic(ui, encoding.strtolocal(sys.argv[1]))