Mercurial > hg
view doc/gendoc.py @ 24429:69bd0ec2f9be
commands.push: abort when revisions evaluate to empty set (BC)
If the "-r" argument is specified to "hg push," the user has expressed
an intent for a specific changeset to be present on the remote. If that
expression cannot be mapped to a known changeset, the user's intent is
ambiguous and cannot be acted upon without making assumptions.
Previously, if arguments to `push -r <rev>` evaluated to an empty set
(perhaps the user specified a revset that didn't evaluate to anything),
the empty "revs" list would be passed down to "exchange.push" where
it appears the empty list was being interpreted as "push everything."
This patch adds validation to the "-r" argument to the push command. If
the argument is specified but doesn't resolve to a changeset, the
command will abort instead of doing something potentially unexpected.
This patch is technically breaking backwards compatibility. I believe
this is justified because the new behavior closes a crack that could
result in undefined or under-defined behavior. Also, this patch doesn't
drop client capabilities because if users really wanted to push all
changesets, they can simply omit the "-r" argument from push completely.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Mon, 23 Mar 2015 18:21:01 -0700 |
parents | e0b29a0c36c4 |
children | 7e8e3c0920a6 |
line wrap: on
line source
"""usage: %s DOC ... where DOC is the name of a document """ import os, sys, textwrap # import from the live mercurial repo sys.path.insert(0, "..") # fall back to pure modules if required C extensions are not available sys.path.append(os.path.join('..', 'mercurial', 'pure')) from mercurial import demandimport; demandimport.enable() from mercurial import minirst from mercurial.commands import table, globalopts from mercurial.i18n import gettext, _ from mercurial.help import helptable, loaddoc from mercurial import extensions def get_desc(docstr): if not docstr: return "", "" # sanitize docstr = docstr.strip("\n") docstr = docstr.rstrip() shortdesc = docstr.splitlines()[0].strip() i = docstr.find("\n") if i != -1: desc = docstr[i + 2:] else: desc = shortdesc desc = textwrap.dedent(desc) 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 = _("VALUE") allopts = [] if shortopt: allopts.append("-%s" % shortopt) if longopt: allopts.append("--%s" % longopt) if isinstance(default, list): allopts[-1] += " <%s[+]>" % optlabel elif (default is not None) and not isinstance(default, bool): allopts[-1] += " <%s>" % optlabel if '\n' in desc: # only remove line breaks and indentation desc = ' '.join(l.lstrip() for l in desc.split('\n')) desc += default and _(" (default: %s)") % default or "" yield (", ".join(allopts), desc) def get_cmd(cmd, cmdtable): d = {} attr = cmdtable[cmd] cmds = cmd.lstrip("^").split("|") d['cmd'] = cmds[0] d['aliases'] = cmd.split("|")[1:] d['desc'] = get_desc(gettext(attr[0].__doc__)) d['opts'] = list(get_opts(attr[1])) s = 'hg ' + cmds[0] if len(attr) > 2: if not attr[2].startswith('hg'): s += ' ' + attr[2] else: s = attr[2] d['synopsis'] = s.strip() return d def showdoc(ui): # print options ui.write(minirst.section(_("Options"))) multioccur = False for optstr, desc in get_opts(globalopts): ui.write("%s\n %s\n\n" % (optstr, desc)) if optstr.endswith("[+]>"): multioccur = True if multioccur: ui.write(_("\n[+] marked option can be specified multiple times\n")) ui.write("\n") # print cmds ui.write(minirst.section(_("Commands"))) commandprinter(ui, table, minirst.subsection) # print help topics # The config help topic is included in the hgrc.5 man page. helpprinter(ui, helptable, minirst.section, exclude=['config']) ui.write(minirst.section(_("Extensions"))) ui.write(_("This section contains help for extensions that are " "distributed together with Mercurial. Help for other " "extensions is available in the help system.")) ui.write("\n\n" ".. contents::\n" " :class: htmlonly\n" " :local:\n" " :depth: 1\n\n") for extensionname in sorted(allextensionnames()): mod = extensions.load(None, extensionname, None) ui.write(minirst.subsection(extensionname)) ui.write("%s\n\n" % gettext(mod.__doc__)) cmdtable = getattr(mod, 'cmdtable', None) if cmdtable: ui.write(minirst.subsubsection(_('Commands'))) commandprinter(ui, cmdtable, minirst.subsubsubsection) def showtopic(ui, topic): extrahelptable = [ (["common"], '', loaddoc('common')), (["hg.1"], '', loaddoc('hg.1')), (["hgignore.5"], '', loaddoc('hgignore.5')), (["hgrc.5"], '', loaddoc('hgrc.5')), (["hgignore.5.gendoc"], '', loaddoc('hgignore')), (["hgrc.5.gendoc"], '', loaddoc('config')), ] helpprinter(ui, helptable + extrahelptable, None, include=[topic]) def helpprinter(ui, helptable, sectionfunc, include=[], exclude=[]): for names, sec, doc in helptable: if exclude and names[0] in exclude: continue if include and names[0] not in include: continue for name in names: ui.write(".. _%s:\n" % name) ui.write("\n") if sectionfunc: ui.write(sectionfunc(sec)) if callable(doc): doc = doc() ui.write(doc) ui.write("\n") def commandprinter(ui, cmdtable, sectionfunc): h = {} for c, attr in cmdtable.items(): f = c.split("|")[0] f = f.lstrip("^") h[f] = c cmds = h.keys() cmds.sort() for f in cmds: if f.startswith("debug"): continue d = get_cmd(h[f], cmdtable) ui.write(sectionfunc(d['cmd'])) # short description ui.write(d['desc'][0]) # synopsis ui.write("::\n\n") synopsislines = d['synopsis'].splitlines() for line in synopsislines: # some commands (such as rebase) have a multi-line # synopsis ui.write(" %s\n" % line) ui.write('\n') # description ui.write("%s\n\n" % d['desc'][1]) # options opt_output = list(d['opts']) if opt_output: opts_len = max([len(line[0]) for line in opt_output]) ui.write(_("Options:\n\n")) multioccur = False for optstr, desc in opt_output: if desc: s = "%-*s %s" % (opts_len, optstr, desc) else: s = optstr ui.write("%s\n" % s) if optstr.endswith("[+]>"): multioccur = True if multioccur: ui.write(_("\n[+] marked option can be specified" " multiple times\n")) ui.write("\n") # aliases if d['aliases']: ui.write(_(" aliases: %s\n\n") % " ".join(d['aliases'])) def allextensionnames(): return extensions.enabled().keys() + extensions.disabled().keys() if __name__ == "__main__": doc = 'hg.1.gendoc' if len(sys.argv) > 1: doc = sys.argv[1] if doc == 'hg.1.gendoc': showdoc(sys.stdout) else: showtopic(sys.stdout, sys.argv[1])