changeset 11029:08e6048592a8

merge with i18n
author Wagner Bruna <wbruna@yahoo.com>
date Sat, 24 Apr 2010 01:37:49 -0300
parents db4d7077f48d (diff) e21fcbbfa27e (current diff)
children d02b5c528dca
files
diffstat 61 files changed, 1636 insertions(+), 1317 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon Apr 19 19:50:04 2010 +0200
+++ b/Makefile	Sat Apr 24 01:37:49 2010 -0300
@@ -51,7 +51,7 @@
 install: install-bin install-doc
 
 install-bin: build
-	$(PYTHON) setup.py $(PURE) install --prefix="$(PREFIX)" --force
+	$(PYTHON) setup.py $(PURE) install --root="$(DESTDIR)/" --prefix="$(PREFIX)" --force
 
 install-doc: doc
 	cd doc && $(MAKE) $(MFLAGS) install
--- a/doc/Makefile	Mon Apr 19 19:50:04 2010 +0200
+++ b/doc/Makefile	Sat Apr 24 01:37:49 2010 -0300
@@ -6,7 +6,6 @@
 MANDIR=$(PREFIX)/share/man
 INSTALL=install -c -m 644
 PYTHON=python
-RST2HTML=$(shell which rst2html 2> /dev/null || echo rst2html.py)
 
 export LANGUAGE=C
 export LC_ALL=C
@@ -25,11 +24,11 @@
 	mv $@.tmp $@
 
 %: %.txt common.txt
-	$(PYTHON) rst2man.py --halt warning \
+	$(PYTHON) runrst manpage --halt warning \
 	  --strip-elements-with-class htmlonly $*.txt $*
 
 %.html: %.txt common.txt
-	$(RST2HTML) --halt warning \
+	$(PYTHON) runrst html --halt warning \
 	  --link-stylesheet --stylesheet-path style.css $*.txt $*.html
 
 MANIFEST: man html
--- a/doc/hgrc.5.txt	Mon Apr 19 19:50:04 2010 +0200
+++ b/doc/hgrc.5.txt	Sat Apr 24 01:37:49 2010 -0300
@@ -263,8 +263,8 @@
 Use the ``[defaults]`` section to define command defaults, i.e. the
 default options/arguments to pass to the specified commands.
 
-The following example makes ``hg log`` run in verbose mode, and ``hg
-status`` show only the modified files, by default::
+The following example makes :hg:`log` run in verbose mode, and :hg:`hg
+status` show only the modified files, by default::
 
   [defaults]
   log = -v
@@ -752,7 +752,7 @@
 ``archivemeta``
     Whether to include the .hg_archival.txt file containing meta data
     (hashes for the repository base and for tip) in archives created
-    by the hg archive command or downloaded via hgweb.
+    by the :hg:`archive` command or downloaded via hgweb.
     Default is True.
 ``askusername``
     Whether to prompt for a username when committing. If True, and
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/manpage.py	Sat Apr 24 01:37:49 2010 -0300
@@ -0,0 +1,1102 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# $Id: manpage.py 6110 2009-08-31 14:40:33Z grubert $
+# Author: Engelbert Gruber <grubert@users.sourceforge.net>
+# Copyright: This module is put into the public domain.
+
+"""
+Simple man page writer for reStructuredText.
+
+Man pages (short for "manual pages") contain system documentation on unix-like
+systems. The pages are grouped in numbered sections:
+
+ 1 executable programs and shell commands
+ 2 system calls
+ 3 library functions
+ 4 special files
+ 5 file formats
+ 6 games
+ 7 miscellaneous
+ 8 system administration
+
+Man pages are written *troff*, a text file formatting system.
+
+See http://www.tldp.org/HOWTO/Man-Page for a start.
+
+Man pages have no subsection only parts.
+Standard parts
+
+  NAME ,
+  SYNOPSIS ,
+  DESCRIPTION ,
+  OPTIONS ,
+  FILES ,
+  SEE ALSO ,
+  BUGS ,
+
+and
+
+  AUTHOR .
+
+A unix-like system keeps an index of the DESCRIPTIONs, which is accesable
+by the command whatis or apropos.
+
+"""
+
+__docformat__ = 'reStructuredText'
+
+import re
+
+from docutils import nodes, writers, languages
+import roman
+
+FIELD_LIST_INDENT = 7
+DEFINITION_LIST_INDENT = 7
+OPTION_LIST_INDENT = 7
+BLOCKQOUTE_INDENT = 3.5
+
+# Define two macros so man/roff can calculate the
+# indent/unindent margins by itself
+MACRO_DEF = (r""".
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+""")
+
+class Writer(writers.Writer):
+
+    supported = ('manpage')
+    """Formats this writer supports."""
+
+    output = None
+    """Final translated form of `document`."""
+
+    def __init__(self):
+        writers.Writer.__init__(self)
+        self.translator_class = Translator
+
+    def translate(self):
+        visitor = self.translator_class(self.document)
+        self.document.walkabout(visitor)
+        self.output = visitor.astext()
+
+
+class Table:
+    def __init__(self):
+        self._rows = []
+        self._options = ['center']
+        self._tab_char = '\t'
+        self._coldefs = []
+    def new_row(self):
+        self._rows.append([])
+    def append_separator(self, separator):
+        """Append the separator for table head."""
+        self._rows.append([separator])
+    def append_cell(self, cell_lines):
+        """cell_lines is an array of lines"""
+        start = 0
+        if len(cell_lines) > 0 and cell_lines[0] == '.sp\n':
+            start = 1
+        self._rows[-1].append(cell_lines[start:])
+        if len(self._coldefs) < len(self._rows[-1]):
+            self._coldefs.append('l')
+    def _minimize_cell(self, cell_lines):
+        """Remove leading and trailing blank and ``.sp`` lines"""
+        while (cell_lines and cell_lines[0] in ('\n', '.sp\n')):
+            del cell_lines[0]
+        while (cell_lines and cell_lines[-1] in ('\n', '.sp\n')):
+            del cell_lines[-1]
+    def as_list(self):
+        text = ['.TS\n']
+        text.append(' '.join(self._options) + ';\n')
+        text.append('|%s|.\n' % ('|'.join(self._coldefs)))
+        for row in self._rows:
+            # row = array of cells. cell = array of lines.
+            text.append('_\n')       # line above
+            text.append('T{\n')
+            for i in range(len(row)):
+                cell = row[i]
+                self._minimize_cell(cell)
+                text.extend(cell)
+                if not text[-1].endswith('\n'):
+                    text[-1] += '\n'
+                if i < len(row)-1:
+                    text.append('T}'+self._tab_char+'T{\n')
+                else:
+                    text.append('T}\n')
+        text.append('_\n')
+        text.append('.TE\n')
+        return text
+
+class Translator(nodes.NodeVisitor):
+    """"""
+
+    words_and_spaces = re.compile(r'\S+| +|\n')
+    document_start = """Man page generated from reStructeredText."""
+
+    def __init__(self, document):
+        nodes.NodeVisitor.__init__(self, document)
+        self.settings = settings = document.settings
+        lcode = settings.language_code
+        self.language = languages.get_language(lcode)
+        self.head = []
+        self.body = []
+        self.foot = []
+        self.section_level = 0
+        self.context = []
+        self.topic_class = ''
+        self.colspecs = []
+        self.compact_p = 1
+        self.compact_simple = None
+        # the list style "*" bullet or "#" numbered
+        self._list_char = []
+        # writing the header .TH and .SH NAME is postboned after
+        # docinfo.
+        self._docinfo = {
+                "title" : "", "title_upper": "",
+                "subtitle" : "",
+                "manual_section" : "", "manual_group" : "",
+                "author" : [],
+                "date" : "",
+                "copyright" : "",
+                "version" : "",
+                    }
+        self._docinfo_keys = []     # a list to keep the sequence as in source.
+        self._docinfo_names = {}    # to get name from text not normalized.
+        self._in_docinfo = None
+        self._active_table = None
+        self._in_literal = False
+        self.header_written = 0
+        self._line_block = 0
+        self.authors = []
+        self.section_level = 0
+        self._indent = [0]
+        # central definition of simple processing rules
+        # what to output on : visit, depart
+        # Do not use paragraph requests ``.PP`` because these set indentation.
+        # use ``.sp``. Remove superfluous ``.sp`` in ``astext``.
+        #
+        # Fonts are put on a stack, the top one is used.
+        # ``.ft P`` or ``\\fP`` pop from stack.
+        # ``B`` bold, ``I`` italic, ``R`` roman should be available.
+        # Hopefully ``C`` courier too.
+        self.defs = {
+                'indent' : ('.INDENT %.1f\n', '.UNINDENT\n'),
+                'definition_list_item' : ('.TP', ''),
+                'field_name' : ('.TP\n.B ', '\n'),
+                'literal' : ('\\fB', '\\fP'),
+                'literal_block' : ('.sp\n.nf\n.ft C\n', '\n.ft P\n.fi\n'),
+
+                'option_list_item' : ('.TP\n', ''),
+
+                'reference' : (r'\%', r'\:'),
+                'emphasis': ('\\fI', '\\fP'),
+                'strong' : ('\\fB', '\\fP'),
+                'term' : ('\n.B ', '\n'),
+                'title_reference' : ('\\fI', '\\fP'),
+
+                'topic-title' : ('.SS ',),
+                'sidebar-title' : ('.SS ',),
+
+                'problematic' : ('\n.nf\n', '\n.fi\n'),
+                    }
+        # NOTE don't specify the newline before a dot-command, but ensure
+        # it is there.
+
+    def comment_begin(self, text):
+        """Return commented version of the passed text WITHOUT end of
+        line/comment."""
+        prefix = '.\\" '
+        out_text = ''.join(
+            [(prefix + in_line + '\n')
+            for in_line in text.split('\n')])
+        return out_text
+
+    def comment(self, text):
+        """Return commented version of the passed text."""
+        return self.comment_begin(text)+'.\n'
+
+    def ensure_eol(self):
+        """Ensure the last line in body is terminated by new line."""
+        if self.body[-1][-1] != '\n':
+            self.body.append('\n')
+
+    def astext(self):
+        """Return the final formatted document as a string."""
+        if not self.header_written:
+            # ensure we get a ".TH" as viewers require it.
+            self.head.append(self.header())
+        # filter body
+        for i in xrange(len(self.body)-1, 0, -1):
+            # remove superfluous vertical gaps.
+            if self.body[i] == '.sp\n':
+                if self.body[i - 1][:4] in ('.BI ','.IP '):
+                    self.body[i] = '.\n'
+                elif (self.body[i - 1][:3] == '.B ' and
+                    self.body[i - 2][:4] == '.TP\n'):
+                    self.body[i] = '.\n'
+                elif (self.body[i - 1] == '\n' and
+                    self.body[i - 2][0] != '.' and
+                    (self.body[i - 3][:7] == '.TP\n.B '
+                        or self.body[i - 3][:4] == '\n.B ')
+                     ):
+                    self.body[i] = '.\n'
+        return ''.join(self.head + self.body + self.foot)
+
+    def deunicode(self, text):
+        text = text.replace(u'\xa0', '\\ ')
+        text = text.replace(u'\u2020', '\\(dg')
+        return text
+
+    def visit_Text(self, node):
+        text = node.astext()
+        text = text.replace('\\','\\e')
+        replace_pairs = [
+            (u'-', ur'\-'),
+            (u'\'', ur'\(aq'),
+            (u'ยด', ur'\''),
+            (u'`', ur'\(ga'),
+            ]
+        for (in_char, out_markup) in replace_pairs:
+            text = text.replace(in_char, out_markup)
+        # unicode
+        text = self.deunicode(text)
+        if self._in_literal:
+            # prevent interpretation of "." at line start
+            if text[0] == '.':
+                text = '\\&' + text
+            text = text.replace('\n.', '\n\\&.')
+        self.body.append(text)
+
+    def depart_Text(self, node):
+        pass
+
+    def list_start(self, node):
+        class enum_char:
+            enum_style = {
+                    'bullet'     : '\\(bu',
+                    'emdash'     : '\\(em',
+                     }
+
+            def __init__(self, style):
+                self._style = style
+                if node.has_key('start'):
+                    self._cnt = node['start'] - 1
+                else:
+                    self._cnt = 0
+                self._indent = 2
+                if style == 'arabic':
+                    # indentation depends on number of childrens
+                    # and start value.
+                    self._indent = len(str(len(node.children)))
+                    self._indent += len(str(self._cnt)) + 1
+                elif style == 'loweralpha':
+                    self._cnt += ord('a') - 1
+                    self._indent = 3
+                elif style == 'upperalpha':
+                    self._cnt += ord('A') - 1
+                    self._indent = 3
+                elif style.endswith('roman'):
+                    self._indent = 5
+
+            def next(self):
+                if self._style == 'bullet':
+                    return self.enum_style[self._style]
+                elif self._style == 'emdash':
+                    return self.enum_style[self._style]
+                self._cnt += 1
+                # TODO add prefix postfix
+                if self._style == 'arabic':
+                    return "%d." % self._cnt
+                elif self._style in ('loweralpha', 'upperalpha'):
+                    return "%c." % self._cnt
+                elif self._style.endswith('roman'):
+                    res = roman.toRoman(self._cnt) + '.'
+                    if self._style.startswith('upper'):
+                        return res.upper()
+                    return res.lower()
+                else:
+                    return "%d." % self._cnt
+            def get_width(self):
+                return self._indent
+            def __repr__(self):
+                return 'enum_style-%s' % list(self._style)
+
+        if node.has_key('enumtype'):
+            self._list_char.append(enum_char(node['enumtype']))
+        else:
+            self._list_char.append(enum_char('bullet'))
+        if len(self._list_char) > 1:
+            # indent nested lists
+            self.indent(self._list_char[-2].get_width())
+        else:
+            self.indent(self._list_char[-1].get_width())
+
+    def list_end(self):
+        self.dedent()
+        self._list_char.pop()
+
+    def header(self):
+        tmpl = (".TH %(title_upper)s %(manual_section)s"
+                " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n"
+                ".SH NAME\n"
+                "%(title)s \- %(subtitle)s\n")
+        return tmpl % self._docinfo
+
+    def append_header(self):
+        """append header with .TH and .SH NAME"""
+        # NOTE before everything
+        # .TH title_upper section date source manual
+        if self.header_written:
+            return
+        self.body.append(self.header())
+        self.body.append(MACRO_DEF)
+        self.header_written = 1
+
+    def visit_address(self, node):
+        self.visit_docinfo_item(node, 'address')
+
+    def depart_address(self, node):
+        pass
+
+    def visit_admonition(self, node, name=None):
+        if name:
+            self.body.append('.IP %s\n' %
+                        self.language.labels.get(name, name))
+
+    def depart_admonition(self, node):
+        self.body.append('.RE\n')
+
+    def visit_attention(self, node):
+        self.visit_admonition(node, 'attention')
+
+    depart_attention = depart_admonition
+
+    def visit_docinfo_item(self, node, name):
+        if name == 'author':
+            self._docinfo[name].append(node.astext())
+        else:
+            self._docinfo[name] = node.astext()
+        self._docinfo_keys.append(name)
+        raise nodes.SkipNode
+
+    def depart_docinfo_item(self, node):
+        pass
+
+    def visit_author(self, node):
+        self.visit_docinfo_item(node, 'author')
+
+    depart_author = depart_docinfo_item
+
+    def visit_authors(self, node):
+        # _author is called anyway.
+        pass
+
+    def depart_authors(self, node):
+        pass
+
+    def visit_block_quote(self, node):
+        # BUG/HACK: indent alway uses the _last_ indention,
+        # thus we need two of them.
+        self.indent(BLOCKQOUTE_INDENT)
+        self.indent(0)
+
+    def depart_block_quote(self, node):
+        self.dedent()
+        self.dedent()
+
+    def visit_bullet_list(self, node):
+        self.list_start(node)
+
+    def depart_bullet_list(self, node):
+        self.list_end()
+
+    def visit_caption(self, node):
+        pass
+
+    def depart_caption(self, node):
+        pass
+
+    def visit_caution(self, node):
+        self.visit_admonition(node, 'caution')
+
+    depart_caution = depart_admonition
+
+    def visit_citation(self, node):
+        num, text = node.astext().split(None, 1)
+        num = num.strip()
+        self.body.append('.IP [%s] 5\n' % num)
+
+    def depart_citation(self, node):
+        pass
+
+    def visit_citation_reference(self, node):
+        self.body.append('['+node.astext()+']')
+        raise nodes.SkipNode
+
+    def visit_classifier(self, node):
+        pass
+
+    def depart_classifier(self, node):
+        pass
+
+    def visit_colspec(self, node):
+        self.colspecs.append(node)
+
+    def depart_colspec(self, node):
+        pass
+
+    def write_colspecs(self):
+        self.body.append("%s.\n" % ('L '*len(self.colspecs)))
+
+    def visit_comment(self, node,
+                      sub=re.compile('-(?=-)').sub):
+        self.body.append(self.comment(node.astext()))
+        raise nodes.SkipNode
+
+    def visit_contact(self, node):
+        self.visit_docinfo_item(node, 'contact')
+
+    depart_contact = depart_docinfo_item
+
+    def visit_container(self, node):
+        pass
+
+    def depart_container(self, node):
+        pass
+
+    def visit_compound(self, node):
+        pass
+
+    def depart_compound(self, node):
+        pass
+
+    def visit_copyright(self, node):
+        self.visit_docinfo_item(node, 'copyright')
+
+    def visit_danger(self, node):
+        self.visit_admonition(node, 'danger')
+
+    depart_danger = depart_admonition
+
+    def visit_date(self, node):
+        self.visit_docinfo_item(node, 'date')
+
+    def visit_decoration(self, node):
+        pass
+
+    def depart_decoration(self, node):
+        pass
+
+    def visit_definition(self, node):
+        pass
+
+    def depart_definition(self, node):
+        pass
+
+    def visit_definition_list(self, node):
+        self.indent(DEFINITION_LIST_INDENT)
+
+    def depart_definition_list(self, node):
+        self.dedent()
+
+    def visit_definition_list_item(self, node):
+        self.body.append(self.defs['definition_list_item'][0])
+
+    def depart_definition_list_item(self, node):
+        self.body.append(self.defs['definition_list_item'][1])
+
+    def visit_description(self, node):
+        pass
+
+    def depart_description(self, node):
+        pass
+
+    def visit_docinfo(self, node):
+        self._in_docinfo = 1
+
+    def depart_docinfo(self, node):
+        self._in_docinfo = None
+        # NOTE nothing should be written before this
+        self.append_header()
+
+    def visit_doctest_block(self, node):
+        self.body.append(self.defs['literal_block'][0])
+        self._in_literal = True
+
+    def depart_doctest_block(self, node):
+        self._in_literal = False
+        self.body.append(self.defs['literal_block'][1])
+
+    def visit_document(self, node):
+        # no blank line between comment and header.
+        self.body.append(self.comment(self.document_start).rstrip()+'\n')
+        # writing header is postboned
+        self.header_written = 0
+
+    def depart_document(self, node):
+        if self._docinfo['author']:
+            self.body.append('.SH AUTHOR\n%s\n'
+                    % ', '.join(self._docinfo['author']))
+        skip = ('author', 'copyright', 'date',
+                'manual_group', 'manual_section',
+                'subtitle',
+                'title', 'title_upper', 'version')
+        for name in self._docinfo_keys:
+            if name == 'address':
+                self.body.append("\n%s:\n%s%s.nf\n%s\n.fi\n%s%s" % (
+                                    self.language.labels.get(name, name),
+                                    self.defs['indent'][0] % 0,
+                                    self.defs['indent'][0] % BLOCKQOUTE_INDENT,
+                                    self._docinfo[name],
+                                    self.defs['indent'][1],
+                                    self.defs['indent'][1]))
+            elif not name in skip:
+                if name in self._docinfo_names:
+                    label = self._docinfo_names[name]
+                else:
+                    label = self.language.labels.get(name, name)
+                self.body.append("\n%s: %s\n" % (label, self._docinfo[name]))
+        if self._docinfo['copyright']:
+            self.body.append('.SH COPYRIGHT\n%s\n'
+                    % self._docinfo['copyright'])
+        self.body.append(self.comment(
+                        'Generated by docutils manpage writer.\n'))
+
+    def visit_emphasis(self, node):
+        self.body.append(self.defs['emphasis'][0])
+
+    def depart_emphasis(self, node):
+        self.body.append(self.defs['emphasis'][1])
+
+    def visit_entry(self, node):
+        # a cell in a table row
+        if 'morerows' in node:
+            self.document.reporter.warning('"table row spanning" not supported',
+                    base_node=node)
+        if 'morecols' in node:
+            self.document.reporter.warning(
+                    '"table cell spanning" not supported', base_node=node)
+        self.context.append(len(self.body))
+
+    def depart_entry(self, node):
+        start = self.context.pop()
+        self._active_table.append_cell(self.body[start:])
+        del self.body[start:]
+
+    def visit_enumerated_list(self, node):
+        self.list_start(node)
+
+    def depart_enumerated_list(self, node):
+        self.list_end()
+
+    def visit_error(self, node):
+        self.visit_admonition(node, 'error')
+
+    depart_error = depart_admonition
+
+    def visit_field(self, node):
+        pass
+
+    def depart_field(self, node):
+        pass
+
+    def visit_field_body(self, node):
+        if self._in_docinfo:
+            name_normalized = self._field_name.lower().replace(" ","_")
+            self._docinfo_names[name_normalized] = self._field_name
+            self.visit_docinfo_item(node, name_normalized)
+            raise nodes.SkipNode
+
+    def depart_field_body(self, node):
+        pass
+
+    def visit_field_list(self, node):
+        self.indent(FIELD_LIST_INDENT)
+
+    def depart_field_list(self, node):
+        self.dedent()
+
+    def visit_field_name(self, node):
+        if self._in_docinfo:
+            self._field_name = node.astext()
+            raise nodes.SkipNode
+        else:
+            self.body.append(self.defs['field_name'][0])
+
+    def depart_field_name(self, node):
+        self.body.append(self.defs['field_name'][1])
+
+    def visit_figure(self, node):
+        self.indent(2.5)
+        self.indent(0)
+
+    def depart_figure(self, node):
+        self.dedent()
+        self.dedent()
+
+    def visit_footer(self, node):
+        self.document.reporter.warning('"footer" not supported',
+                base_node=node)
+
+    def depart_footer(self, node):
+        pass
+
+    def visit_footnote(self, node):
+        num, text = node.astext().split(None, 1)
+        num = num.strip()
+        self.body.append('.IP [%s] 5\n' % self.deunicode(num))
+
+    def depart_footnote(self, node):
+        pass
+
+    def footnote_backrefs(self, node):
+        self.document.reporter.warning('"footnote_backrefs" not supported',
+                base_node=node)
+
+    def visit_footnote_reference(self, node):
+        self.body.append('['+self.deunicode(node.astext())+']')
+        raise nodes.SkipNode
+
+    def depart_footnote_reference(self, node):
+        pass
+
+    def visit_generated(self, node):
+        pass
+
+    def depart_generated(self, node):
+        pass
+
+    def visit_header(self, node):
+        raise NotImplementedError, node.astext()
+
+    def depart_header(self, node):
+        pass
+
+    def visit_hint(self, node):
+        self.visit_admonition(node, 'hint')
+
+    depart_hint = depart_admonition
+
+    def visit_subscript(self, node):
+        self.body.append('\\s-2\\d')
+
+    def depart_subscript(self, node):
+        self.body.append('\\u\\s0')
+
+    def visit_superscript(self, node):
+        self.body.append('\\s-2\\u')
+
+    def depart_superscript(self, node):
+        self.body.append('\\d\\s0')
+
+    def visit_attribution(self, node):
+        self.body.append('\\(em ')
+
+    def depart_attribution(self, node):
+        self.body.append('\n')
+
+    def visit_image(self, node):
+        self.document.reporter.warning('"image" not supported',
+                base_node=node)
+        text = []
+        if 'alt' in node.attributes:
+            text.append(node.attributes['alt'])
+        if 'uri' in node.attributes:
+            text.append(node.attributes['uri'])
+        self.body.append('[image: %s]\n' % ('/'.join(text)))
+        raise nodes.SkipNode
+
+    def visit_important(self, node):
+        self.visit_admonition(node, 'important')
+
+    depart_important = depart_admonition
+
+    def visit_label(self, node):
+        # footnote and citation
+        if (isinstance(node.parent, nodes.footnote)
+            or isinstance(node.parent, nodes.citation)):
+            raise nodes.SkipNode
+        self.document.reporter.warning('"unsupported "label"',
+                base_node=node)
+        self.body.append('[')
+
+    def depart_label(self, node):
+        self.body.append(']\n')
+
+    def visit_legend(self, node):
+        pass
+
+    def depart_legend(self, node):
+        pass
+
+    # WHAT should we use .INDENT, .UNINDENT ?
+    def visit_line_block(self, node):
+        self._line_block += 1
+        if self._line_block == 1:
+            self.body.append('.sp\n')
+            self.body.append('.nf\n')
+        else:
+            self.body.append('.in +2\n')
+
+    def depart_line_block(self, node):
+        self._line_block -= 1
+        if self._line_block == 0:
+            self.body.append('.fi\n')
+            self.body.append('.sp\n')
+        else:
+            self.body.append('.in -2\n')
+
+    def visit_line(self, node):
+        pass
+
+    def depart_line(self, node):
+        self.body.append('\n')
+
+    def visit_list_item(self, node):
+        # man 7 man argues to use ".IP" instead of ".TP"
+        self.body.append('.IP %s %d\n' % (
+                self._list_char[-1].next(),
+                self._list_char[-1].get_width(),))
+
+    def depart_list_item(self, node):
+        pass
+
+    def visit_literal(self, node):
+        self.body.append(self.defs['literal'][0])
+
+    def depart_literal(self, node):
+        self.body.append(self.defs['literal'][1])
+
+    def visit_literal_block(self, node):
+        self.body.append(self.defs['literal_block'][0])
+        self._in_literal = True
+
+    def depart_literal_block(self, node):
+        self._in_literal = False
+        self.body.append(self.defs['literal_block'][1])
+
+    def visit_meta(self, node):
+        raise NotImplementedError, node.astext()
+
+    def depart_meta(self, node):
+        pass
+
+    def visit_note(self, node):
+        self.visit_admonition(node, 'note')
+
+    depart_note = depart_admonition
+
+    def indent(self, by=0.5):
+        # if we are in a section ".SH" there already is a .RS
+        step = self._indent[-1]
+        self._indent.append(by)
+        self.body.append(self.defs['indent'][0] % step)
+
+    def dedent(self):
+        self._indent.pop()
+        self.body.append(self.defs['indent'][1])
+
+    def visit_option_list(self, node):
+        self.indent(OPTION_LIST_INDENT)
+
+    def depart_option_list(self, node):
+        self.dedent()
+
+    def visit_option_list_item(self, node):
+        # one item of the list
+        self.body.append(self.defs['option_list_item'][0])
+
+    def depart_option_list_item(self, node):
+        self.body.append(self.defs['option_list_item'][1])
+
+    def visit_option_group(self, node):
+        # as one option could have several forms it is a group
+        # options without parameter bold only, .B, -v
+        # options with parameter bold italic, .BI, -f file
+        #
+        # we do not know if .B or .BI
+        self.context.append('.B')           # blind guess
+        self.context.append(len(self.body)) # to be able to insert later
+        self.context.append(0)              # option counter
+
+    def depart_option_group(self, node):
+        self.context.pop()  # the counter
+        start_position = self.context.pop()
+        text = self.body[start_position:]
+        del self.body[start_position:]
+        self.body.append('%s%s\n' % (self.context.pop(), ''.join(text)))
+
+    def visit_option(self, node):
+        # each form of the option will be presented separately
+        if self.context[-1] > 0:
+            self.body.append(', ')
+        if self.context[-3] == '.BI':
+            self.body.append('\\')
+        self.body.append(' ')
+
+    def depart_option(self, node):
+        self.context[-1] += 1
+
+    def visit_option_string(self, node):
+        # do not know if .B or .BI
+        pass
+
+    def depart_option_string(self, node):
+        pass
+
+    def visit_option_argument(self, node):
+        self.context[-3] = '.BI' # bold/italic alternate
+        if node['delimiter'] != ' ':
+            self.body.append('\\fB%s ' % node['delimiter'])
+        elif self.body[len(self.body)-1].endswith('='):
+            # a blank only means no blank in output, just changing font
+            self.body.append(' ')
+        else:
+            # blank backslash blank, switch font then a blank
+            self.body.append(' \\ ')
+
+    def depart_option_argument(self, node):
+        pass
+
+    def visit_organization(self, node):
+        self.visit_docinfo_item(node, 'organization')
+
+    def depart_organization(self, node):
+        pass
+
+    def visit_paragraph(self, node):
+        # ``.PP`` : Start standard indented paragraph.
+        # ``.LP`` : Start block paragraph, all except the first.
+        # ``.P [type]``  : Start paragraph type.
+        # NOTE dont use paragraph starts because they reset indentation.
+        # ``.sp`` is only vertical space
+        self.ensure_eol()
+        self.body.append('.sp\n')
+
+    def depart_paragraph(self, node):
+        self.body.append('\n')
+
+    def visit_problematic(self, node):
+        self.body.append(self.defs['problematic'][0])
+
+    def depart_problematic(self, node):
+        self.body.append(self.defs['problematic'][1])
+
+    def visit_raw(self, node):
+        if node.get('format') == 'manpage':
+            self.body.append(node.astext() + "\n")
+        # Keep non-manpage raw text out of output:
+        raise nodes.SkipNode
+
+    def visit_reference(self, node):
+        """E.g. link or email address."""
+        self.body.append(self.defs['reference'][0])
+
+    def depart_reference(self, node):
+        self.body.append(self.defs['reference'][1])
+
+    def visit_revision(self, node):
+        self.visit_docinfo_item(node, 'revision')
+
+    depart_revision = depart_docinfo_item
+
+    def visit_row(self, node):
+        self._active_table.new_row()
+
+    def depart_row(self, node):
+        pass
+
+    def visit_section(self, node):
+        self.section_level += 1
+
+    def depart_section(self, node):
+        self.section_level -= 1
+
+    def visit_status(self, node):
+        self.visit_docinfo_item(node, 'status')
+
+    depart_status = depart_docinfo_item
+
+    def visit_strong(self, node):
+        self.body.append(self.defs['strong'][0])
+
+    def depart_strong(self, node):
+        self.body.append(self.defs['strong'][1])
+
+    def visit_substitution_definition(self, node):
+        """Internal only."""
+        raise nodes.SkipNode
+
+    def visit_substitution_reference(self, node):
+        self.document.reporter.warning('"substitution_reference" not supported',
+                base_node=node)
+
+    def visit_subtitle(self, node):
+        if isinstance(node.parent, nodes.sidebar):
+            self.body.append(self.defs['strong'][0])
+        elif isinstance(node.parent, nodes.document):
+            self.visit_docinfo_item(node, 'subtitle')
+        elif isinstance(node.parent, nodes.section):
+            self.body.append(self.defs['strong'][0])
+
+    def depart_subtitle(self, node):
+        # document subtitle calls SkipNode
+        self.body.append(self.defs['strong'][1]+'\n.PP\n')
+
+    def visit_system_message(self, node):
+        # TODO add report_level
+        #if node['level'] < self.document.reporter['writer'].report_level:
+        #    Level is too low to display:
+        #    raise nodes.SkipNode
+        attr = {}
+        backref_text = ''
+        if node.hasattr('id'):
+            attr['name'] = node['id']
+        if node.hasattr('line'):
+            line = ', line %s' % node['line']
+        else:
+            line = ''
+        self.body.append('.IP "System Message: %s/%s (%s:%s)"\n'
+                         % (node['type'], node['level'], node['source'], line))
+
+    def depart_system_message(self, node):
+        pass
+
+    def visit_table(self, node):
+        self._active_table = Table()
+
+    def depart_table(self, node):
+        self.ensure_eol()
+        self.body.extend(self._active_table.as_list())
+        self._active_table = None
+
+    def visit_target(self, node):
+        # targets are in-document hyper targets, without any use for man-pages.
+        raise nodes.SkipNode
+
+    def visit_tbody(self, node):
+        pass
+
+    def depart_tbody(self, node):
+        pass
+
+    def visit_term(self, node):
+        self.body.append(self.defs['term'][0])
+
+    def depart_term(self, node):
+        self.body.append(self.defs['term'][1])
+
+    def visit_tgroup(self, node):
+        pass
+
+    def depart_tgroup(self, node):
+        pass
+
+    def visit_thead(self, node):
+        # MAYBE double line '='
+        pass
+
+    def depart_thead(self, node):
+        # MAYBE double line '='
+        pass
+
+    def visit_tip(self, node):
+        self.visit_admonition(node, 'tip')
+
+    depart_tip = depart_admonition
+
+    def visit_title(self, node):
+        if isinstance(node.parent, nodes.topic):
+            self.body.append(self.defs['topic-title'][0])
+        elif isinstance(node.parent, nodes.sidebar):
+            self.body.append(self.defs['sidebar-title'][0])
+        elif isinstance(node.parent, nodes.admonition):
+            self.body.append('.IP "')
+        elif self.section_level == 0:
+            self._docinfo['title'] = node.astext()
+            # document title for .TH
+            self._docinfo['title_upper'] = node.astext().upper()
+            raise nodes.SkipNode
+        elif self.section_level == 1:
+            self.body.append('.SH ')
+            for n in node.traverse(nodes.Text):
+                n.parent.replace(n, nodes.Text(n.astext().upper()))
+        else:
+            self.body.append('.SS ')
+
+    def depart_title(self, node):
+        if isinstance(node.parent, nodes.admonition):
+            self.body.append('"')
+        self.body.append('\n')
+
+    def visit_title_reference(self, node):
+        """inline citation reference"""
+        self.body.append(self.defs['title_reference'][0])
+
+    def depart_title_reference(self, node):
+        self.body.append(self.defs['title_reference'][1])
+
+    def visit_topic(self, node):
+        pass
+
+    def depart_topic(self, node):
+        pass
+
+    def visit_sidebar(self, node):
+        pass
+
+    def depart_sidebar(self, node):
+        pass
+
+    def visit_rubric(self, node):
+        pass
+
+    def depart_rubric(self, node):
+        pass
+
+    def visit_transition(self, node):
+        # .PP      Begin a new paragraph and reset prevailing indent.
+        # .sp N    leaves N lines of blank space.
+        # .ce      centers the next line
+        self.body.append('\n.sp\n.ce\n----\n')
+
+    def depart_transition(self, node):
+        self.body.append('\n.ce 0\n.sp\n')
+
+    def visit_version(self, node):
+        self.visit_docinfo_item(node, 'version')
+
+    def visit_warning(self, node):
+        self.visit_admonition(node, 'warning')
+
+    depart_warning = depart_admonition
+
+    def unimplemented_visit(self, node):
+        raise NotImplementedError('visiting unimplemented node type: %s'
+                                  % node.__class__.__name__)
+
+# vim: set fileencoding=utf-8 et ts=4 ai :
--- a/doc/rst2man.py	Mon Apr 19 19:50:04 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1109 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-# $Id: manpage.py 6110 2009-08-31 14:40:33Z grubert $
-# Author: Engelbert Gruber <grubert@users.sourceforge.net>
-# Copyright: This module is put into the public domain.
-
-"""
-Simple man page writer for reStructuredText.
-
-Man pages (short for "manual pages") contain system documentation on unix-like
-systems. The pages are grouped in numbered sections:
-
- 1 executable programs and shell commands
- 2 system calls
- 3 library functions
- 4 special files
- 5 file formats
- 6 games
- 7 miscellaneous
- 8 system administration
-
-Man pages are written *troff*, a text file formatting system.
-
-See http://www.tldp.org/HOWTO/Man-Page for a start.
-
-Man pages have no subsection only parts.
-Standard parts
-
-  NAME ,
-  SYNOPSIS ,
-  DESCRIPTION ,
-  OPTIONS ,
-  FILES ,
-  SEE ALSO ,
-  BUGS ,
-
-and
-
-  AUTHOR .
-
-A unix-like system keeps an index of the DESCRIPTIONs, which is accesable
-by the command whatis or apropos.
-
-"""
-
-__docformat__ = 'reStructuredText'
-
-import re
-
-from docutils import nodes, writers, languages
-import roman
-
-FIELD_LIST_INDENT = 7
-DEFINITION_LIST_INDENT = 7
-OPTION_LIST_INDENT = 7
-BLOCKQOUTE_INDENT = 3.5
-
-# Define two macros so man/roff can calculate the
-# indent/unindent margins by itself
-MACRO_DEF = (r""".
-.nr rst2man-indent-level 0
-.
-.de1 rstReportMargin
-\\$1 \\n[an-margin]
-level \\n[rst2man-indent-level]
-level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
--
-\\n[rst2man-indent0]
-\\n[rst2man-indent1]
-\\n[rst2man-indent2]
-..
-.de1 INDENT
-.\" .rstReportMargin pre:
-. RS \\$1
-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
-. nr rst2man-indent-level +1
-.\" .rstReportMargin post:
-..
-.de UNINDENT
-. RE
-.\" indent \\n[an-margin]
-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.nr rst2man-indent-level -1
-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
-..
-""")
-
-class Writer(writers.Writer):
-
-    supported = ('manpage')
-    """Formats this writer supports."""
-
-    output = None
-    """Final translated form of `document`."""
-
-    def __init__(self):
-        writers.Writer.__init__(self)
-        self.translator_class = Translator
-
-    def translate(self):
-        visitor = self.translator_class(self.document)
-        self.document.walkabout(visitor)
-        self.output = visitor.astext()
-
-
-class Table:
-    def __init__(self):
-        self._rows = []
-        self._options = ['center']
-        self._tab_char = '\t'
-        self._coldefs = []
-    def new_row(self):
-        self._rows.append([])
-    def append_separator(self, separator):
-        """Append the separator for table head."""
-        self._rows.append([separator])
-    def append_cell(self, cell_lines):
-        """cell_lines is an array of lines"""
-        start = 0
-        if len(cell_lines) > 0 and cell_lines[0] == '.sp\n':
-            start = 1
-        self._rows[-1].append(cell_lines[start:])
-        if len(self._coldefs) < len(self._rows[-1]):
-            self._coldefs.append('l')
-    def _minimize_cell(self, cell_lines):
-        """Remove leading and trailing blank and ``.sp`` lines"""
-        while (cell_lines and cell_lines[0] in ('\n', '.sp\n')):
-            del cell_lines[0]
-        while (cell_lines and cell_lines[-1] in ('\n', '.sp\n')):
-            del cell_lines[-1]
-    def as_list(self):
-        text = ['.TS\n']
-        text.append(' '.join(self._options) + ';\n')
-        text.append('|%s|.\n' % ('|'.join(self._coldefs)))
-        for row in self._rows:
-            # row = array of cells. cell = array of lines.
-            text.append('_\n')       # line above
-            text.append('T{\n')
-            for i in range(len(row)):
-                cell = row[i]
-                self._minimize_cell(cell)
-                text.extend(cell)
-                if not text[-1].endswith('\n'):
-                    text[-1] += '\n'
-                if i < len(row)-1:
-                    text.append('T}'+self._tab_char+'T{\n')
-                else:
-                    text.append('T}\n')
-        text.append('_\n')
-        text.append('.TE\n')
-        return text
-
-class Translator(nodes.NodeVisitor):
-    """"""
-
-    words_and_spaces = re.compile(r'\S+| +|\n')
-    document_start = """Man page generated from reStructeredText."""
-
-    def __init__(self, document):
-        nodes.NodeVisitor.__init__(self, document)
-        self.settings = settings = document.settings
-        lcode = settings.language_code
-        self.language = languages.get_language(lcode)
-        self.head = []
-        self.body = []
-        self.foot = []
-        self.section_level = 0
-        self.context = []
-        self.topic_class = ''
-        self.colspecs = []
-        self.compact_p = 1
-        self.compact_simple = None
-        # the list style "*" bullet or "#" numbered
-        self._list_char = []
-        # writing the header .TH and .SH NAME is postboned after
-        # docinfo.
-        self._docinfo = {
-                "title" : "", "title_upper": "",
-                "subtitle" : "",
-                "manual_section" : "", "manual_group" : "",
-                "author" : [],
-                "date" : "",
-                "copyright" : "",
-                "version" : "",
-                    }
-        self._docinfo_keys = []     # a list to keep the sequence as in source.
-        self._docinfo_names = {}    # to get name from text not normalized.
-        self._in_docinfo = None
-        self._active_table = None
-        self._in_literal = False
-        self.header_written = 0
-        self._line_block = 0
-        self.authors = []
-        self.section_level = 0
-        self._indent = [0]
-        # central definition of simple processing rules
-        # what to output on : visit, depart
-        # Do not use paragraph requests ``.PP`` because these set indentation.
-        # use ``.sp``. Remove superfluous ``.sp`` in ``astext``.
-        #
-        # Fonts are put on a stack, the top one is used.
-        # ``.ft P`` or ``\\fP`` pop from stack.
-        # ``B`` bold, ``I`` italic, ``R`` roman should be available.
-        # Hopefully ``C`` courier too.
-        self.defs = {
-                'indent' : ('.INDENT %.1f\n', '.UNINDENT\n'),
-                'definition_list_item' : ('.TP', ''),
-                'field_name' : ('.TP\n.B ', '\n'),
-                'literal' : ('\\fB', '\\fP'),
-                'literal_block' : ('.sp\n.nf\n.ft C\n', '\n.ft P\n.fi\n'),
-
-                'option_list_item' : ('.TP\n', ''),
-
-                'reference' : (r'\%', r'\:'),
-                'emphasis': ('\\fI', '\\fP'),
-                'strong' : ('\\fB', '\\fP'),
-                'term' : ('\n.B ', '\n'),
-                'title_reference' : ('\\fI', '\\fP'),
-
-                'topic-title' : ('.SS ',),
-                'sidebar-title' : ('.SS ',),
-
-                'problematic' : ('\n.nf\n', '\n.fi\n'),
-                    }
-        # NOTE don't specify the newline before a dot-command, but ensure
-        # it is there.
-
-    def comment_begin(self, text):
-        """Return commented version of the passed text WITHOUT end of
-        line/comment."""
-        prefix = '.\\" '
-        out_text = ''.join(
-            [(prefix + in_line + '\n')
-            for in_line in text.split('\n')])
-        return out_text
-
-    def comment(self, text):
-        """Return commented version of the passed text."""
-        return self.comment_begin(text)+'.\n'
-
-    def ensure_eol(self):
-        """Ensure the last line in body is terminated by new line."""
-        if self.body[-1][-1] != '\n':
-            self.body.append('\n')
-
-    def astext(self):
-        """Return the final formatted document as a string."""
-        if not self.header_written:
-            # ensure we get a ".TH" as viewers require it.
-            self.head.append(self.header())
-        # filter body
-        for i in xrange(len(self.body)-1, 0, -1):
-            # remove superfluous vertical gaps.
-            if self.body[i] == '.sp\n':
-                if self.body[i - 1][:4] in ('.BI ','.IP '):
-                    self.body[i] = '.\n'
-                elif (self.body[i - 1][:3] == '.B ' and
-                    self.body[i - 2][:4] == '.TP\n'):
-                    self.body[i] = '.\n'
-                elif (self.body[i - 1] == '\n' and
-                    self.body[i - 2][0] != '.' and
-                    (self.body[i - 3][:7] == '.TP\n.B '
-                        or self.body[i - 3][:4] == '\n.B ')
-                     ):
-                    self.body[i] = '.\n'
-        return ''.join(self.head + self.body + self.foot)
-
-    def deunicode(self, text):
-        text = text.replace(u'\xa0', '\\ ')
-        text = text.replace(u'\u2020', '\\(dg')
-        return text
-
-    def visit_Text(self, node):
-        text = node.astext()
-        text = text.replace('\\','\\e')
-        replace_pairs = [
-            (u'-', ur'\-'),
-            (u'\'', ur'\(aq'),
-            (u'ยด', ur'\''),
-            (u'`', ur'\(ga'),
-            ]
-        for (in_char, out_markup) in replace_pairs:
-            text = text.replace(in_char, out_markup)
-        # unicode
-        text = self.deunicode(text)
-        if self._in_literal:
-            # prevent interpretation of "." at line start
-            if text[0] == '.':
-                text = '\\&' + text
-            text = text.replace('\n.', '\n\\&.')
-        self.body.append(text)
-
-    def depart_Text(self, node):
-        pass
-
-    def list_start(self, node):
-        class enum_char:
-            enum_style = {
-                    'bullet'     : '\\(bu',
-                    'emdash'     : '\\(em',
-                     }
-
-            def __init__(self, style):
-                self._style = style
-                if node.has_key('start'):
-                    self._cnt = node['start'] - 1
-                else:
-                    self._cnt = 0
-                self._indent = 2
-                if style == 'arabic':
-                    # indentation depends on number of childrens
-                    # and start value.
-                    self._indent = len(str(len(node.children)))
-                    self._indent += len(str(self._cnt)) + 1
-                elif style == 'loweralpha':
-                    self._cnt += ord('a') - 1
-                    self._indent = 3
-                elif style == 'upperalpha':
-                    self._cnt += ord('A') - 1
-                    self._indent = 3
-                elif style.endswith('roman'):
-                    self._indent = 5
-
-            def next(self):
-                if self._style == 'bullet':
-                    return self.enum_style[self._style]
-                elif self._style == 'emdash':
-                    return self.enum_style[self._style]
-                self._cnt += 1
-                # TODO add prefix postfix
-                if self._style == 'arabic':
-                    return "%d." % self._cnt
-                elif self._style in ('loweralpha', 'upperalpha'):
-                    return "%c." % self._cnt
-                elif self._style.endswith('roman'):
-                    res = roman.toRoman(self._cnt) + '.'
-                    if self._style.startswith('upper'):
-                        return res.upper()
-                    return res.lower()
-                else:
-                    return "%d." % self._cnt
-            def get_width(self):
-                return self._indent
-            def __repr__(self):
-                return 'enum_style-%s' % list(self._style)
-
-        if node.has_key('enumtype'):
-            self._list_char.append(enum_char(node['enumtype']))
-        else:
-            self._list_char.append(enum_char('bullet'))
-        if len(self._list_char) > 1:
-            # indent nested lists
-            self.indent(self._list_char[-2].get_width())
-        else:
-            self.indent(self._list_char[-1].get_width())
-
-    def list_end(self):
-        self.dedent()
-        self._list_char.pop()
-
-    def header(self):
-        tmpl = (".TH %(title_upper)s %(manual_section)s"
-                " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n"
-                ".SH NAME\n"
-                "%(title)s \- %(subtitle)s\n")
-        return tmpl % self._docinfo
-
-    def append_header(self):
-        """append header with .TH and .SH NAME"""
-        # NOTE before everything
-        # .TH title_upper section date source manual
-        if self.header_written:
-            return
-        self.body.append(self.header())
-        self.body.append(MACRO_DEF)
-        self.header_written = 1
-
-    def visit_address(self, node):
-        self.visit_docinfo_item(node, 'address')
-
-    def depart_address(self, node):
-        pass
-
-    def visit_admonition(self, node, name=None):
-        if name:
-            self.body.append('.IP %s\n' %
-                        self.language.labels.get(name, name))
-
-    def depart_admonition(self, node):
-        self.body.append('.RE\n')
-
-    def visit_attention(self, node):
-        self.visit_admonition(node, 'attention')
-
-    depart_attention = depart_admonition
-
-    def visit_docinfo_item(self, node, name):
-        if name == 'author':
-            self._docinfo[name].append(node.astext())
-        else:
-            self._docinfo[name] = node.astext()
-        self._docinfo_keys.append(name)
-        raise nodes.SkipNode
-
-    def depart_docinfo_item(self, node):
-        pass
-
-    def visit_author(self, node):
-        self.visit_docinfo_item(node, 'author')
-
-    depart_author = depart_docinfo_item
-
-    def visit_authors(self, node):
-        # _author is called anyway.
-        pass
-
-    def depart_authors(self, node):
-        pass
-
-    def visit_block_quote(self, node):
-        # BUG/HACK: indent alway uses the _last_ indention,
-        # thus we need two of them.
-        self.indent(BLOCKQOUTE_INDENT)
-        self.indent(0)
-
-    def depart_block_quote(self, node):
-        self.dedent()
-        self.dedent()
-
-    def visit_bullet_list(self, node):
-        self.list_start(node)
-
-    def depart_bullet_list(self, node):
-        self.list_end()
-
-    def visit_caption(self, node):
-        pass
-
-    def depart_caption(self, node):
-        pass
-
-    def visit_caution(self, node):
-        self.visit_admonition(node, 'caution')
-
-    depart_caution = depart_admonition
-
-    def visit_citation(self, node):
-        num, text = node.astext().split(None, 1)
-        num = num.strip()
-        self.body.append('.IP [%s] 5\n' % num)
-
-    def depart_citation(self, node):
-        pass
-
-    def visit_citation_reference(self, node):
-        self.body.append('['+node.astext()+']')
-        raise nodes.SkipNode
-
-    def visit_classifier(self, node):
-        pass
-
-    def depart_classifier(self, node):
-        pass
-
-    def visit_colspec(self, node):
-        self.colspecs.append(node)
-
-    def depart_colspec(self, node):
-        pass
-
-    def write_colspecs(self):
-        self.body.append("%s.\n" % ('L '*len(self.colspecs)))
-
-    def visit_comment(self, node,
-                      sub=re.compile('-(?=-)').sub):
-        self.body.append(self.comment(node.astext()))
-        raise nodes.SkipNode
-
-    def visit_contact(self, node):
-        self.visit_docinfo_item(node, 'contact')
-
-    depart_contact = depart_docinfo_item
-
-    def visit_container(self, node):
-        pass
-
-    def depart_container(self, node):
-        pass
-
-    def visit_compound(self, node):
-        pass
-
-    def depart_compound(self, node):
-        pass
-
-    def visit_copyright(self, node):
-        self.visit_docinfo_item(node, 'copyright')
-
-    def visit_danger(self, node):
-        self.visit_admonition(node, 'danger')
-
-    depart_danger = depart_admonition
-
-    def visit_date(self, node):
-        self.visit_docinfo_item(node, 'date')
-
-    def visit_decoration(self, node):
-        pass
-
-    def depart_decoration(self, node):
-        pass
-
-    def visit_definition(self, node):
-        pass
-
-    def depart_definition(self, node):
-        pass
-
-    def visit_definition_list(self, node):
-        self.indent(DEFINITION_LIST_INDENT)
-
-    def depart_definition_list(self, node):
-        self.dedent()
-
-    def visit_definition_list_item(self, node):
-        self.body.append(self.defs['definition_list_item'][0])
-
-    def depart_definition_list_item(self, node):
-        self.body.append(self.defs['definition_list_item'][1])
-
-    def visit_description(self, node):
-        pass
-
-    def depart_description(self, node):
-        pass
-
-    def visit_docinfo(self, node):
-        self._in_docinfo = 1
-
-    def depart_docinfo(self, node):
-        self._in_docinfo = None
-        # NOTE nothing should be written before this
-        self.append_header()
-
-    def visit_doctest_block(self, node):
-        self.body.append(self.defs['literal_block'][0])
-        self._in_literal = True
-
-    def depart_doctest_block(self, node):
-        self._in_literal = False
-        self.body.append(self.defs['literal_block'][1])
-
-    def visit_document(self, node):
-        # no blank line between comment and header.
-        self.body.append(self.comment(self.document_start).rstrip()+'\n')
-        # writing header is postboned
-        self.header_written = 0
-
-    def depart_document(self, node):
-        if self._docinfo['author']:
-            self.body.append('.SH AUTHOR\n%s\n'
-                    % ', '.join(self._docinfo['author']))
-        skip = ('author', 'copyright', 'date',
-                'manual_group', 'manual_section',
-                'subtitle',
-                'title', 'title_upper', 'version')
-        for name in self._docinfo_keys:
-            if name == 'address':
-                self.body.append("\n%s:\n%s%s.nf\n%s\n.fi\n%s%s" % (
-                                    self.language.labels.get(name, name),
-                                    self.defs['indent'][0] % 0,
-                                    self.defs['indent'][0] % BLOCKQOUTE_INDENT,
-                                    self._docinfo[name],
-                                    self.defs['indent'][1],
-                                    self.defs['indent'][1]))
-            elif not name in skip:
-                if name in self._docinfo_names:
-                    label = self._docinfo_names[name]
-                else:
-                    label = self.language.labels.get(name, name)
-                self.body.append("\n%s: %s\n" % (label, self._docinfo[name]))
-        if self._docinfo['copyright']:
-            self.body.append('.SH COPYRIGHT\n%s\n'
-                    % self._docinfo['copyright'])
-        self.body.append(self.comment(
-                        'Generated by docutils manpage writer.\n'))
-
-    def visit_emphasis(self, node):
-        self.body.append(self.defs['emphasis'][0])
-
-    def depart_emphasis(self, node):
-        self.body.append(self.defs['emphasis'][1])
-
-    def visit_entry(self, node):
-        # a cell in a table row
-        if 'morerows' in node:
-            self.document.reporter.warning('"table row spanning" not supported',
-                    base_node=node)
-        if 'morecols' in node:
-            self.document.reporter.warning(
-                    '"table cell spanning" not supported', base_node=node)
-        self.context.append(len(self.body))
-
-    def depart_entry(self, node):
-        start = self.context.pop()
-        self._active_table.append_cell(self.body[start:])
-        del self.body[start:]
-
-    def visit_enumerated_list(self, node):
-        self.list_start(node)
-
-    def depart_enumerated_list(self, node):
-        self.list_end()
-
-    def visit_error(self, node):
-        self.visit_admonition(node, 'error')
-
-    depart_error = depart_admonition
-
-    def visit_field(self, node):
-        pass
-
-    def depart_field(self, node):
-        pass
-
-    def visit_field_body(self, node):
-        if self._in_docinfo:
-            name_normalized = self._field_name.lower().replace(" ","_")
-            self._docinfo_names[name_normalized] = self._field_name
-            self.visit_docinfo_item(node, name_normalized)
-            raise nodes.SkipNode
-
-    def depart_field_body(self, node):
-        pass
-
-    def visit_field_list(self, node):
-        self.indent(FIELD_LIST_INDENT)
-
-    def depart_field_list(self, node):
-        self.dedent()
-
-    def visit_field_name(self, node):
-        if self._in_docinfo:
-            self._field_name = node.astext()
-            raise nodes.SkipNode
-        else:
-            self.body.append(self.defs['field_name'][0])
-
-    def depart_field_name(self, node):
-        self.body.append(self.defs['field_name'][1])
-
-    def visit_figure(self, node):
-        self.indent(2.5)
-        self.indent(0)
-
-    def depart_figure(self, node):
-        self.dedent()
-        self.dedent()
-
-    def visit_footer(self, node):
-        self.document.reporter.warning('"footer" not supported',
-                base_node=node)
-
-    def depart_footer(self, node):
-        pass
-
-    def visit_footnote(self, node):
-        num, text = node.astext().split(None, 1)
-        num = num.strip()
-        self.body.append('.IP [%s] 5\n' % self.deunicode(num))
-
-    def depart_footnote(self, node):
-        pass
-
-    def footnote_backrefs(self, node):
-        self.document.reporter.warning('"footnote_backrefs" not supported',
-                base_node=node)
-
-    def visit_footnote_reference(self, node):
-        self.body.append('['+self.deunicode(node.astext())+']')
-        raise nodes.SkipNode
-
-    def depart_footnote_reference(self, node):
-        pass
-
-    def visit_generated(self, node):
-        pass
-
-    def depart_generated(self, node):
-        pass
-
-    def visit_header(self, node):
-        raise NotImplementedError, node.astext()
-
-    def depart_header(self, node):
-        pass
-
-    def visit_hint(self, node):
-        self.visit_admonition(node, 'hint')
-
-    depart_hint = depart_admonition
-
-    def visit_subscript(self, node):
-        self.body.append('\\s-2\\d')
-
-    def depart_subscript(self, node):
-        self.body.append('\\u\\s0')
-
-    def visit_superscript(self, node):
-        self.body.append('\\s-2\\u')
-
-    def depart_superscript(self, node):
-        self.body.append('\\d\\s0')
-
-    def visit_attribution(self, node):
-        self.body.append('\\(em ')
-
-    def depart_attribution(self, node):
-        self.body.append('\n')
-
-    def visit_image(self, node):
-        self.document.reporter.warning('"image" not supported',
-                base_node=node)
-        text = []
-        if 'alt' in node.attributes:
-            text.append(node.attributes['alt'])
-        if 'uri' in node.attributes:
-            text.append(node.attributes['uri'])
-        self.body.append('[image: %s]\n' % ('/'.join(text)))
-        raise nodes.SkipNode
-
-    def visit_important(self, node):
-        self.visit_admonition(node, 'important')
-
-    depart_important = depart_admonition
-
-    def visit_label(self, node):
-        # footnote and citation
-        if (isinstance(node.parent, nodes.footnote)
-            or isinstance(node.parent, nodes.citation)):
-            raise nodes.SkipNode
-        self.document.reporter.warning('"unsupported "label"',
-                base_node=node)
-        self.body.append('[')
-
-    def depart_label(self, node):
-        self.body.append(']\n')
-
-    def visit_legend(self, node):
-        pass
-
-    def depart_legend(self, node):
-        pass
-
-    # WHAT should we use .INDENT, .UNINDENT ?
-    def visit_line_block(self, node):
-        self._line_block += 1
-        if self._line_block == 1:
-            self.body.append('.sp\n')
-            self.body.append('.nf\n')
-        else:
-            self.body.append('.in +2\n')
-
-    def depart_line_block(self, node):
-        self._line_block -= 1
-        if self._line_block == 0:
-            self.body.append('.fi\n')
-            self.body.append('.sp\n')
-        else:
-            self.body.append('.in -2\n')
-
-    def visit_line(self, node):
-        pass
-
-    def depart_line(self, node):
-        self.body.append('\n')
-
-    def visit_list_item(self, node):
-        # man 7 man argues to use ".IP" instead of ".TP"
-        self.body.append('.IP %s %d\n' % (
-                self._list_char[-1].next(),
-                self._list_char[-1].get_width(),))
-
-    def depart_list_item(self, node):
-        pass
-
-    def visit_literal(self, node):
-        self.body.append(self.defs['literal'][0])
-
-    def depart_literal(self, node):
-        self.body.append(self.defs['literal'][1])
-
-    def visit_literal_block(self, node):
-        self.body.append(self.defs['literal_block'][0])
-        self._in_literal = True
-
-    def depart_literal_block(self, node):
-        self._in_literal = False
-        self.body.append(self.defs['literal_block'][1])
-
-    def visit_meta(self, node):
-        raise NotImplementedError, node.astext()
-
-    def depart_meta(self, node):
-        pass
-
-    def visit_note(self, node):
-        self.visit_admonition(node, 'note')
-
-    depart_note = depart_admonition
-
-    def indent(self, by=0.5):
-        # if we are in a section ".SH" there already is a .RS
-        step = self._indent[-1]
-        self._indent.append(by)
-        self.body.append(self.defs['indent'][0] % step)
-
-    def dedent(self):
-        self._indent.pop()
-        self.body.append(self.defs['indent'][1])
-
-    def visit_option_list(self, node):
-        self.indent(OPTION_LIST_INDENT)
-
-    def depart_option_list(self, node):
-        self.dedent()
-
-    def visit_option_list_item(self, node):
-        # one item of the list
-        self.body.append(self.defs['option_list_item'][0])
-
-    def depart_option_list_item(self, node):
-        self.body.append(self.defs['option_list_item'][1])
-
-    def visit_option_group(self, node):
-        # as one option could have several forms it is a group
-        # options without parameter bold only, .B, -v
-        # options with parameter bold italic, .BI, -f file
-        #
-        # we do not know if .B or .BI
-        self.context.append('.B')           # blind guess
-        self.context.append(len(self.body)) # to be able to insert later
-        self.context.append(0)              # option counter
-
-    def depart_option_group(self, node):
-        self.context.pop()  # the counter
-        start_position = self.context.pop()
-        text = self.body[start_position:]
-        del self.body[start_position:]
-        self.body.append('%s%s\n' % (self.context.pop(), ''.join(text)))
-
-    def visit_option(self, node):
-        # each form of the option will be presented separately
-        if self.context[-1] > 0:
-            self.body.append(', ')
-        if self.context[-3] == '.BI':
-            self.body.append('\\')
-        self.body.append(' ')
-
-    def depart_option(self, node):
-        self.context[-1] += 1
-
-    def visit_option_string(self, node):
-        # do not know if .B or .BI
-        pass
-
-    def depart_option_string(self, node):
-        pass
-
-    def visit_option_argument(self, node):
-        self.context[-3] = '.BI' # bold/italic alternate
-        if node['delimiter'] != ' ':
-            self.body.append('\\fB%s ' % node['delimiter'])
-        elif self.body[len(self.body)-1].endswith('='):
-            # a blank only means no blank in output, just changing font
-            self.body.append(' ')
-        else:
-            # blank backslash blank, switch font then a blank
-            self.body.append(' \\ ')
-
-    def depart_option_argument(self, node):
-        pass
-
-    def visit_organization(self, node):
-        self.visit_docinfo_item(node, 'organization')
-
-    def depart_organization(self, node):
-        pass
-
-    def visit_paragraph(self, node):
-        # ``.PP`` : Start standard indented paragraph.
-        # ``.LP`` : Start block paragraph, all except the first.
-        # ``.P [type]``  : Start paragraph type.
-        # NOTE dont use paragraph starts because they reset indentation.
-        # ``.sp`` is only vertical space
-        self.ensure_eol()
-        self.body.append('.sp\n')
-
-    def depart_paragraph(self, node):
-        self.body.append('\n')
-
-    def visit_problematic(self, node):
-        self.body.append(self.defs['problematic'][0])
-
-    def depart_problematic(self, node):
-        self.body.append(self.defs['problematic'][1])
-
-    def visit_raw(self, node):
-        if node.get('format') == 'manpage':
-            self.body.append(node.astext() + "\n")
-        # Keep non-manpage raw text out of output:
-        raise nodes.SkipNode
-
-    def visit_reference(self, node):
-        """E.g. link or email address."""
-        self.body.append(self.defs['reference'][0])
-
-    def depart_reference(self, node):
-        self.body.append(self.defs['reference'][1])
-
-    def visit_revision(self, node):
-        self.visit_docinfo_item(node, 'revision')
-
-    depart_revision = depart_docinfo_item
-
-    def visit_row(self, node):
-        self._active_table.new_row()
-
-    def depart_row(self, node):
-        pass
-
-    def visit_section(self, node):
-        self.section_level += 1
-
-    def depart_section(self, node):
-        self.section_level -= 1
-
-    def visit_status(self, node):
-        self.visit_docinfo_item(node, 'status')
-
-    depart_status = depart_docinfo_item
-
-    def visit_strong(self, node):
-        self.body.append(self.defs['strong'][0])
-
-    def depart_strong(self, node):
-        self.body.append(self.defs['strong'][1])
-
-    def visit_substitution_definition(self, node):
-        """Internal only."""
-        raise nodes.SkipNode
-
-    def visit_substitution_reference(self, node):
-        self.document.reporter.warning('"substitution_reference" not supported',
-                base_node=node)
-
-    def visit_subtitle(self, node):
-        if isinstance(node.parent, nodes.sidebar):
-            self.body.append(self.defs['strong'][0])
-        elif isinstance(node.parent, nodes.document):
-            self.visit_docinfo_item(node, 'subtitle')
-        elif isinstance(node.parent, nodes.section):
-            self.body.append(self.defs['strong'][0])
-
-    def depart_subtitle(self, node):
-        # document subtitle calls SkipNode
-        self.body.append(self.defs['strong'][1]+'\n.PP\n')
-
-    def visit_system_message(self, node):
-        # TODO add report_level
-        #if node['level'] < self.document.reporter['writer'].report_level:
-        #    Level is too low to display:
-        #    raise nodes.SkipNode
-        attr = {}
-        backref_text = ''
-        if node.hasattr('id'):
-            attr['name'] = node['id']
-        if node.hasattr('line'):
-            line = ', line %s' % node['line']
-        else:
-            line = ''
-        self.body.append('.IP "System Message: %s/%s (%s:%s)"\n'
-                         % (node['type'], node['level'], node['source'], line))
-
-    def depart_system_message(self, node):
-        pass
-
-    def visit_table(self, node):
-        self._active_table = Table()
-
-    def depart_table(self, node):
-        self.ensure_eol()
-        self.body.extend(self._active_table.as_list())
-        self._active_table = None
-
-    def visit_target(self, node):
-        # targets are in-document hyper targets, without any use for man-pages.
-        raise nodes.SkipNode
-
-    def visit_tbody(self, node):
-        pass
-
-    def depart_tbody(self, node):
-        pass
-
-    def visit_term(self, node):
-        self.body.append(self.defs['term'][0])
-
-    def depart_term(self, node):
-        self.body.append(self.defs['term'][1])
-
-    def visit_tgroup(self, node):
-        pass
-
-    def depart_tgroup(self, node):
-        pass
-
-    def visit_thead(self, node):
-        # MAYBE double line '='
-        pass
-
-    def depart_thead(self, node):
-        # MAYBE double line '='
-        pass
-
-    def visit_tip(self, node):
-        self.visit_admonition(node, 'tip')
-
-    depart_tip = depart_admonition
-
-    def visit_title(self, node):
-        if isinstance(node.parent, nodes.topic):
-            self.body.append(self.defs['topic-title'][0])
-        elif isinstance(node.parent, nodes.sidebar):
-            self.body.append(self.defs['sidebar-title'][0])
-        elif isinstance(node.parent, nodes.admonition):
-            self.body.append('.IP "')
-        elif self.section_level == 0:
-            self._docinfo['title'] = node.astext()
-            # document title for .TH
-            self._docinfo['title_upper'] = node.astext().upper()
-            raise nodes.SkipNode
-        elif self.section_level == 1:
-            self.body.append('.SH ')
-            for n in node.traverse(nodes.Text):
-                n.parent.replace(n, nodes.Text(n.astext().upper()))
-        else:
-            self.body.append('.SS ')
-
-    def depart_title(self, node):
-        if isinstance(node.parent, nodes.admonition):
-            self.body.append('"')
-        self.body.append('\n')
-
-    def visit_title_reference(self, node):
-        """inline citation reference"""
-        self.body.append(self.defs['title_reference'][0])
-
-    def depart_title_reference(self, node):
-        self.body.append(self.defs['title_reference'][1])
-
-    def visit_topic(self, node):
-        pass
-
-    def depart_topic(self, node):
-        pass
-
-    def visit_sidebar(self, node):
-        pass
-
-    def depart_sidebar(self, node):
-        pass
-
-    def visit_rubric(self, node):
-        pass
-
-    def depart_rubric(self, node):
-        pass
-
-    def visit_transition(self, node):
-        # .PP      Begin a new paragraph and reset prevailing indent.
-        # .sp N    leaves N lines of blank space.
-        # .ce      centers the next line
-        self.body.append('\n.sp\n.ce\n----\n')
-
-    def depart_transition(self, node):
-        self.body.append('\n.ce 0\n.sp\n')
-
-    def visit_version(self, node):
-        self.visit_docinfo_item(node, 'version')
-
-    def visit_warning(self, node):
-        self.visit_admonition(node, 'warning')
-
-    depart_warning = depart_admonition
-
-    def unimplemented_visit(self, node):
-        raise NotImplementedError('visiting unimplemented node type: %s'
-                                  % node.__class__.__name__)
-
-# The following part is taken from the Docutils rst2man.py script:
-if __name__ == "__main__":
-    from docutils.core import publish_cmdline, default_description
-    description = ("Generates plain unix manual documents.  " +
-                   default_description)
-    publish_cmdline(writer=Writer(), description=description)
-
-# vim: set fileencoding=utf-8 et ts=4 ai :
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/runrst	Sat Apr 24 01:37:49 2010 -0300
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#
+# runrst - register custom roles and run correct writer
+#
+# Copyright 2010 Matt Mackall <mpm@selenic.com> and others
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+"""usage: %s WRITER args...
+
+where WRITER is the name of a Docutils writer such as 'html' or 'manpage'
+"""
+
+import sys
+from docutils.parsers.rst import roles
+from docutils.core import publish_cmdline
+from docutils import nodes, utils
+
+def role_hg(name, rawtext, text, lineno, inliner,
+            options={}, content=[]):
+    text = "hg " + utils.unescape(text)
+    linktext = nodes.literal(rawtext, text)
+    parts = text.split()
+    cmd, args = parts[1], parts[2:]
+    if cmd == 'help' and args:
+        cmd = args[0] # link to 'dates' for 'hg help dates'
+    node = nodes.reference(rawtext, '', linktext,
+                           refuri="hg.1.html#%s" % cmd)
+    return [node], []
+
+roles.register_local_role("hg", role_hg)
+
+if __name__ == "__main__":
+    if len(sys.argv) < 2:
+        sys.stderr.write(__doc__ % sys.argv[0])
+        sys.exit(1)
+
+    writer = sys.argv[1]
+    del sys.argv[1]
+
+    publish_cmdline(writer_name=writer)
--- a/hgext/acl.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/acl.py	Sat Apr 24 01:37:49 2010 -0300
@@ -72,10 +72,11 @@
 
 
 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
-    if hooktype != 'pretxnchangegroup':
+    if hooktype not in ['pretxnchangegroup', 'pretxncommit']:
         raise util.Abort(_('config error - hook type "%s" cannot stop '
-                           'incoming changesets') % hooktype)
-    if source not in ui.config('acl', 'sources', 'serve').split():
+                           'incoming changesets nor commits') % hooktype)
+    if (hooktype == 'pretxnchangegroup' and
+        source not in ui.config('acl', 'sources', 'serve').split()):
         ui.debug('acl: changes have source "%s" - skipping\n' % source)
         return
 
--- a/hgext/bookmarks.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/bookmarks.py	Sat Apr 24 01:37:49 2010 -0300
@@ -88,10 +88,10 @@
 
     Bookmarks are pointers to certain commits that move when
     committing. Bookmarks are local. They can be renamed, copied and
-    deleted. It is possible to use bookmark names in 'hg merge' and
-    'hg update' to merge and update respectively to a given bookmark.
+    deleted. It is possible to use bookmark names in :hg:`merge` and
+    :hg:`update` to merge and update respectively to a given bookmark.
 
-    You can use 'hg bookmark NAME' to set a bookmark on the working
+    You can use :hg:`bookmark NAME` to set a bookmark on the working
     directory's parent revision with the given name. If you specify
     a revision using -r REV (where REV may be an existing bookmark),
     the bookmark is assigned to that revision.
@@ -308,7 +308,7 @@
                 super(bookmark_repo, self).invalidate()
                 for attr in ('_bookmarks', '_bookmarkcurrent'):
                     if attr in self.__dict__:
-                        delattr(repo, attr)
+                        delattr(self, attr)
 
     repo.__class__ = bookmark_repo
 
--- a/hgext/convert/bzr.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/convert/bzr.py	Sat Apr 24 01:37:49 2010 -0300
@@ -37,13 +37,14 @@
         super(bzr_source, self).__init__(ui, path, rev=rev)
 
         if not os.path.exists(os.path.join(path, '.bzr')):
-            raise NoRepo('%s does not look like a Bazaar repo' % path)
+            raise NoRepo(_('%s does not look like a Bazaar repository')
+                         % path)
 
         try:
             # access bzrlib stuff
             branch
         except NameError:
-            raise NoRepo('Bazaar modules could not be loaded')
+            raise NoRepo(_('Bazaar modules could not be loaded'))
 
         path = os.path.abspath(path)
         self._checkrepotype(path)
--- a/hgext/convert/cvs.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/convert/cvs.py	Sat Apr 24 01:37:49 2010 -0300
@@ -19,7 +19,7 @@
 
         cvs = os.path.join(path, "CVS")
         if not os.path.exists(cvs):
-            raise NoRepo("%s does not look like a CVS checkout" % path)
+            raise NoRepo(_("%s does not look like a CVS checkout") % path)
 
         checktool('cvs')
 
--- a/hgext/convert/cvsps.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/convert/cvsps.py	Sat Apr 24 01:37:49 2010 -0300
@@ -129,7 +129,7 @@
             if prefix == ".":
                 prefix = ""
         except IOError:
-            raise logerror('Not a CVS sandbox')
+            raise logerror(_('not a CVS sandbox'))
 
         if prefix and not prefix.endswith(os.sep):
             prefix += os.sep
@@ -402,6 +402,8 @@
             branchpoints = set()
             for branch, revision in branchmap.iteritems():
                 revparts = tuple([int(i) for i in revision.split('.')])
+                if len(revparts) < 2: # bad tags
+                    continue
                 if revparts[-2] == 0 and revparts[-1] % 2 == 0:
                     # normal branch
                     if revparts[:-2] == e.revision:
@@ -435,8 +437,8 @@
             log.sort(key=lambda x: x.date)
 
             if oldlog and oldlog[-1].date >= log[0].date:
-                raise logerror('Log cache overlaps with new log entries,'
-                               ' re-run without cache.')
+                raise logerror(_('log cache overlaps with new log entries,'
+                                 ' re-run without cache.'))
 
             log = oldlog + log
 
--- a/hgext/convert/darcs.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/convert/darcs.py	Sat Apr 24 01:37:49 2010 -0300
@@ -34,10 +34,10 @@
         # check for _darcs, ElementTree, _darcs/inventory so that we can
         # easily skip test-convert-darcs if ElementTree is not around
         if not os.path.exists(os.path.join(path, '_darcs', 'inventories')):
-            raise NoRepo("%s does not look like a darcs repo" % path)
+            raise NoRepo(_("%s does not look like a darcs repository") % path)
 
         if not os.path.exists(os.path.join(path, '_darcs')):
-            raise NoRepo("%s does not look like a darcs repo" % path)
+            raise NoRepo(_("%s does not look like a darcs repository") % path)
 
         checktool('darcs')
         version = self.run0('--version').splitlines()[0].strip()
--- a/hgext/convert/git.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/convert/git.py	Sat Apr 24 01:37:49 2010 -0300
@@ -7,6 +7,7 @@
 
 import os
 from mercurial import util
+from mercurial.i18n import _
 
 from common import NoRepo, commit, converter_source, checktool
 
@@ -35,7 +36,7 @@
         if os.path.isdir(path + "/.git"):
             path += "/.git"
         if not os.path.exists(path + "/objects"):
-            raise NoRepo("%s does not look like a Git repo" % path)
+            raise NoRepo(_("%s does not look like a Git repository") % path)
 
         checktool('git', 'git')
 
--- a/hgext/convert/gnuarch.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/convert/gnuarch.py	Sat Apr 24 01:37:49 2010 -0300
@@ -31,7 +31,8 @@
         super(gnuarch_source, self).__init__(ui, path, rev=rev)
 
         if not os.path.exists(os.path.join(path, '{arch}')):
-            raise NoRepo(_("%s does not look like a GNU Arch repo") % path)
+            raise NoRepo(_("%s does not look like a GNU Arch repository")
+                         % path)
 
         # Could use checktool, but we want to check for baz or tla.
         self.execmd = None
--- a/hgext/convert/hg.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/convert/hg.py	Sat Apr 24 01:37:49 2010 -0300
@@ -36,7 +36,8 @@
             try:
                 self.repo = hg.repository(self.ui, path)
                 if not self.repo.local():
-                    raise NoRepo(_('%s is not a local Mercurial repo') % path)
+                    raise NoRepo(_('%s is not a local Mercurial repository')
+                                 % path)
             except error.RepoError, err:
                 ui.traceback()
                 raise NoRepo(err.args[0])
@@ -45,11 +46,13 @@
                 ui.status(_('initializing destination %s repository\n') % path)
                 self.repo = hg.repository(self.ui, path, create=True)
                 if not self.repo.local():
-                    raise NoRepo(_('%s is not a local Mercurial repo') % path)
+                    raise NoRepo(_('%s is not a local Mercurial repository')
+                                 % path)
                 self.created.append(path)
             except error.RepoError:
                 ui.traceback()
-                raise NoRepo("could not create hg repo %s as sink" % path)
+                raise NoRepo(_("could not create hg repository %s as sink")
+                             % path)
         self.lock = None
         self.wlock = None
         self.filemapmode = False
@@ -224,7 +227,7 @@
                 raise error.RepoError()
         except error.RepoError:
             ui.traceback()
-            raise NoRepo("%s is not a local Mercurial repo" % path)
+            raise NoRepo(_("%s is not a local Mercurial repository") % path)
         self.lastrev = None
         self.lastctx = None
         self._changescache = None
--- a/hgext/convert/monotone.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/convert/monotone.py	Sat Apr 24 01:37:49 2010 -0300
@@ -20,7 +20,8 @@
         self.ui = ui
         self.path = path
 
-        norepo = NoRepo (_("%s does not look like a monotone repo") % path)
+        norepo = NoRepo(_("%s does not look like a monotone repository")
+                        % path)
         if not os.path.exists(os.path.join(path, '_MTN')):
             # Could be a monotone repository (SQLite db file)
             try:
--- a/hgext/convert/p4.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/convert/p4.py	Sat Apr 24 01:37:49 2010 -0300
@@ -28,7 +28,7 @@
         super(p4_source, self).__init__(ui, path, rev=rev)
 
         if "/" in path and not path.startswith('//'):
-            raise NoRepo('%s does not look like a P4 repo' % path)
+            raise NoRepo(_('%s does not look like a P4 repository') % path)
 
         checktool('p4', abort=False)
 
--- a/hgext/convert/subversion.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/convert/subversion.py	Sat Apr 24 01:37:49 2010 -0300
@@ -207,7 +207,8 @@
                 (os.path.exists(url) and
                  os.path.exists(os.path.join(url, '.svn'))) or
                 issvnurl(ui, url)):
-            raise NoRepo("%s does not look like a Subversion repo" % url)
+            raise NoRepo(_("%s does not look like a Subversion repository")
+                         % url)
 
         try:
             SubversionException
@@ -252,7 +253,8 @@
             self.uuid = svn.ra.get_uuid(self.ra)
         except SubversionException:
             ui.traceback()
-            raise NoRepo("%s does not look like a Subversion repo" % self.url)
+            raise NoRepo(_("%s does not look like a Subversion repository")
+                         % self.url)
 
         if rev:
             try:
@@ -984,7 +986,7 @@
 
             if os.path.isdir(os.path.dirname(path)):
                 if not os.path.exists(os.path.join(path, 'db', 'fs-type')):
-                    ui.status(_('initializing svn repo %r\n') %
+                    ui.status(_('initializing svn repository %r\n') %
                               os.path.basename(path))
                     commandline(ui, 'svnadmin').run0('create', path)
                     created = path
@@ -993,7 +995,8 @@
                     path = '/' + path
                 path = 'file://' + path
 
-            ui.status(_('initializing svn wc %r\n') % os.path.basename(wcpath))
+            ui.status(_('initializing svn working copy %r\n')
+                      % os.path.basename(wcpath))
             self.run0('checkout', path, wcpath)
 
             self.wc = wcpath
--- a/hgext/fetch.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/fetch.py	Sat Apr 24 01:37:49 2010 -0300
@@ -28,7 +28,7 @@
     parent, with local changes as the second. To switch the merge
     order, use --switch-parent.
 
-    See 'hg help dates' for a list of formats valid for -d/--date.
+    See :hg:`help dates` for a list of formats valid for -d/--date.
     '''
 
     date = opts.get('date')
--- a/hgext/highlight/highlight.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/highlight/highlight.py	Sat Apr 24 01:37:49 2010 -0300
@@ -23,7 +23,7 @@
 def pygmentize(field, fctx, style, tmpl):
 
     # append a <link ...> to the syntax highlighting css
-    old_header = ''.join(tmpl('header'))
+    old_header = tmpl.load('header')
     if SYNTAX_CSS not in old_header:
         new_header =  old_header + SYNTAX_CSS
         tmpl.cache['header'] = new_header
--- a/hgext/keyword.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/keyword.py	Sat Apr 24 01:37:49 2010 -0300
@@ -49,25 +49,25 @@
 lose speed in huge repositories.
 
 For [keywordmaps] template mapping and expansion demonstration and
-control run "hg kwdemo". See "hg help templates" for a list of
+control run :hg:`kwdemo`. See :hg:`help templates` for a list of
 available templates and filters.
 
 An additional date template filter {date|utcdate} is provided. It
 returns a date like "2006/09/18 15:13:13".
 
-The default template mappings (view with "hg kwdemo -d") can be
-replaced with customized keywords and templates. Again, run "hg
-kwdemo" to control the results of your config changes.
+The default template mappings (view with :hg:`kwdemo -d`) can be
+replaced with customized keywords and templates. Again, run
+:hg:`kwdemo` to control the results of your config changes.
 
-Before changing/disabling active keywords, run "hg kwshrink" to avoid
+Before changing/disabling active keywords, run :hg:`kwshrink` to avoid
 the risk of inadvertently storing expanded keywords in the change
 history.
 
 To force expansion after enabling it, or a configuration change, run
-"hg kwexpand".
+:hg:`kwexpand`.
 
 Also, when committing with the record extension or using mq's qrecord,
-be aware that keywords cannot be updated. Again, run "hg kwexpand" on
+be aware that keywords cannot be updated. Again, run :hg:`kwexpand` on
 the files in question to update keyword expansions after all changes
 have been checked in.
 
@@ -361,7 +361,7 @@
     execution by including only files that are actual candidates for
     expansion.
 
-    See "hg help keyword" on how to construct patterns both for
+    See :hg:`help keyword` on how to construct patterns both for
     inclusion and exclusion of files.
 
     With -A/--all and -v/--verbose the codes used to show the status
@@ -398,7 +398,7 @@
     '''revert expanded keywords in the working directory
 
     Run before changing/disabling active keywords or if you experience
-    problems with "hg import" or "hg merge".
+    problems with :hg:`import` or :hg:`merge`.
 
     kwshrink refuses to run if given files contain local changes.
     '''
@@ -471,10 +471,10 @@
 
     # monkeypatches
     def kwpatchfile_init(orig, self, ui, fname, opener,
-                         missing=False, eol=None):
+                         missing=False, eolmode=None):
         '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
         rejects or conflicts due to expanded keywords in working dir.'''
-        orig(self, ui, fname, opener, missing, eol)
+        orig(self, ui, fname, opener, missing, eolmode)
         # shrink keywords read from working dir
         self.lines = kwt.shrinklines(self.fname, self.lines)
 
--- a/hgext/mq.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/mq.py	Sat Apr 24 01:37:49 2010 -0300
@@ -14,7 +14,7 @@
 Known patches are represented as patch files in the .hg/patches
 directory. Applied patches are both patch files and changesets.
 
-Common tasks (use "hg help command" for more details)::
+Common tasks (use :hg:`help command` for more details)::
 
   create new patch                          qnew
   import existing patch                     qimport
@@ -1420,7 +1420,7 @@
             if summary:
                 ph = patchheader(self.join(patchname), self.plainmode)
                 msg = ph.message and ph.message[0] or ''
-                if self.ui.interactive():
+                if not self.ui.plain():
                     width = util.termwidth() - len(pfx) - len(patchname) - 2
                     if width > 0:
                         msg = util.ellipsis(msg, width)
@@ -2041,9 +2041,9 @@
     last refresh (thus showing what the current patch would become
     after a qrefresh).
 
-    Use 'hg diff' if you only want to see the changes made since the
-    last qrefresh, or 'hg export qtip' if you want to see changes made
-    by the current patch without including changes made since the
+    Use :hg:`diff` if you only want to see the changes made since the
+    last qrefresh, or :hg:`export qtip` if you want to see changes
+    made by the current patch without including changes made since the
     qrefresh.
     """
     repo.mq.diff(repo, pats, opts)
@@ -2737,7 +2737,7 @@
           ('D', 'currentdate', None, _('add "Date: <current date>" to patch')),
           ('d', 'date', '', _('add "Date: <given date>" to patch'))
           ] + commands.walkopts + commands.commitopts,
-         _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
+         _('hg qnew [-e] [-m TEXT] [-l FILE] PATCH [FILE]...')),
     "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
     "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
     "^qpop":
--- a/hgext/pager.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/pager.py	Sat Apr 24 01:37:49 2010 -0300
@@ -45,8 +45,8 @@
 
 If pager.attend is present, pager.ignore will be ignored.
 
-To ignore global commands like "hg version" or "hg help", you have to
-specify them in the global .hgrc
+To ignore global commands like :hg:`version` or :hg:`help`, you have
+to specify them in the global .hgrc
 '''
 
 import sys, os, signal
--- a/hgext/patchbomb.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/patchbomb.py	Sat Apr 24 01:37:49 2010 -0300
@@ -16,7 +16,7 @@
 
 - The changeset description.
 - [Optional] The result of running diffstat on the patch.
-- The patch itself, as generated by "hg export".
+- The patch itself, as generated by :hg:`export`.
 
 Each message refers to the first in the series using the In-Reply-To
 and References headers, so they will show up as a sequence in threaded
@@ -38,11 +38,11 @@
 Use ``[patchbomb]`` as configuration section name if you need to
 override global ``[email]`` address settings.
 
-Then you can use the "hg email" command to mail a series of changesets
-as a patchbomb.
+Then you can use the :hg:`email` command to mail a series of
+changesets as a patchbomb.
 
 To avoid sending patches prematurely, it is a good idea to first run
-the "email" command with the "-n" option (test only). You will be
+the :hg:`email` command with the "-n" option (test only). You will be
 prompted for an email recipient address, a subject and an introductory
 message describing the patches of your patchbomb. Then when all is
 done, patchbomb messages are displayed. If the PAGER environment
@@ -196,7 +196,7 @@
     description. Next, (optionally) if the diffstat program is
     installed and -d/--diffstat is used, the result of running
     diffstat on the patch. Finally, the patch itself, as generated by
-    "hg export".
+    :hg:`export`.
 
     By default the patch is included as text in the email body for
     easy reviewing. Using the -a/--attach option will instead create
--- a/hgext/purge.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/purge.py	Sat Apr 24 01:37:49 2010 -0300
@@ -37,7 +37,7 @@
 
     This means that purge will delete:
 
-    - Unknown files: files marked with "?" by "hg status"
+    - Unknown files: files marked with "?" by :hg:`status`
     - Empty directories: in fact Mercurial ignores directories unless
       they contain files under source control management
 
@@ -45,7 +45,7 @@
 
     - Modified and unmodified tracked files
     - Ignored files (unless --all is specified)
-    - New files added to the repository (with "hg add")
+    - New files added to the repository (with :hg:`add`)
 
     If directories are given on the command line, only files in these
     directories are considered.
--- a/hgext/record.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/hgext/record.py	Sat Apr 24 01:37:49 2010 -0300
@@ -360,10 +360,10 @@
 def record(ui, repo, *pats, **opts):
     '''interactively select changes to commit
 
-    If a list of files is omitted, all changes reported by "hg status"
+    If a list of files is omitted, all changes reported by :hg:`status`
     will be candidates for recording.
 
-    See 'hg help dates' for a list of formats valid for -d/--date.
+    See :hg:`help dates` for a list of formats valid for -d/--date.
 
     You will be prompted for whether to record changes to each
     modified file, and for files with multiple changes, for each
@@ -388,7 +388,7 @@
 def qrecord(ui, repo, patch, *pats, **opts):
     '''interactively record a new patch
 
-    See 'hg help qnew' & 'hg help record' for more information and
+    See :hg:`help qnew` & :hg:`help record` for more information and
     usage.
     '''
 
--- a/mercurial/cmdutil.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/cmdutil.py	Sat Apr 24 01:37:49 2010 -0300
@@ -129,9 +129,10 @@
     if r:
         dst.setconfig('bundle', 'mainreporoot', r)
 
-    # copy auth section settings
-    for key, val in src.configitems('auth'):
-        dst.setconfig('auth', key, val)
+    # copy auth and http_proxy section settings
+    for sect in ('auth', 'http_proxy'):
+        for key, val in src.configitems(sect):
+            dst.setconfig(sect, key, val)
 
     return dst
 
--- a/mercurial/commands.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/commands.py	Sat Apr 24 01:37:49 2010 -0300
@@ -32,7 +32,7 @@
     .. container:: verbose
 
        An example showing how new (unknown) files are added
-       automatically by ``hg add``::
+       automatically by :hg:`add`::
 
          $ ls
          foo.c
@@ -171,7 +171,7 @@
     :``zip``:   zip archive, compressed using deflate
 
     The exact name of the destination archive or directory is given
-    using a format string; see 'hg help export' for details.
+    using a format string; see :hg:`help export` for details.
 
     Each member added to an archive file has a directory prefix
     prepended. Use -p/--prefix to specify a format string for the
@@ -230,7 +230,7 @@
     changeset afterwards. This saves you from doing the merge by hand.
     The result of this merge is not committed, as with a normal merge.
 
-    See 'hg help dates' for a list of formats valid for -d/--date.
+    See :hg:`help dates` for a list of formats valid for -d/--date.
     '''
     if rev and node:
         raise util.Abort(_("please specify just one revision"))
@@ -456,8 +456,8 @@
     the parent of the working directory, negating a previous branch
     change.
 
-    Use the command 'hg update' to switch to an existing branch. Use
-    'hg commit --close-branch' to mark this branch as closed.
+    Use the command :hg:`update` to switch to an existing branch. Use
+    :hg:`commit --close-branch` to mark this branch as closed.
     """
 
     if opts.get('clean'):
@@ -485,7 +485,7 @@
     If -a/--active is specified, only show active branches. A branch
     is considered active if it contains repository heads.
 
-    Use the command 'hg update' to switch to an existing branch.
+    Use the command :hg:`update` to switch to an existing branch.
     """
 
     hexfunc = ui.debugflag and hex or short
@@ -637,11 +637,11 @@
     The location of the source is added to the new repository's
     .hg/hgrc file, as the default to be used for future pulls.
 
-    See 'hg help urls' for valid source format details.
+    See :hg:`help urls` for valid source format details.
 
     It is possible to specify an ``ssh://`` URL as the destination, but no
     .hg/hgrc and working directory will be created on the remote side.
-    Please see 'hg help urls' for important details about ``ssh://`` URLs.
+    Please see :hg:`help urls` for important details about ``ssh://`` URLs.
 
     A set of changesets (tags, or branch names) to pull may be specified
     by listing each changeset (tag, or branch name) with -r/--rev.
@@ -705,7 +705,7 @@
     centralized RCS, this operation is a local operation. See hg push
     for a way to actively distribute your changes.
 
-    If a list of files is omitted, all changes reported by "hg status"
+    If a list of files is omitted, all changes reported by :hg:`status`
     will be committed.
 
     If you are committing the result of a merge, do not provide any
@@ -714,7 +714,7 @@
     If no commit message is specified, the configured editor is
     started to prompt you for a message.
 
-    See 'hg help dates' for a list of formats valid for -d/--date.
+    See :hg:`help dates` for a list of formats valid for -d/--date.
     """
     extra = {}
     if opts.get('close_branch'):
@@ -802,6 +802,8 @@
             otables.append(entry[1])
         for t in otables:
             for o in t:
+                if "(DEPRECATED)" in o[3]:
+                    continue
                 if o[0]:
                     options.append('-%s' % o[0])
                 options.append('--%s' % o[1])
@@ -1149,7 +1151,7 @@
     anyway, probably with undesirable results.
 
     Use the -g/--git option to generate diffs in the git extended diff
-    format. For more information, read 'hg help diffs'.
+    format. For more information, read :hg:`help diffs`.
     """
 
     revs = opts.get('rev')
@@ -1176,7 +1178,9 @@
     m = cmdutil.match(repo, pats, opts)
     if stat:
         it = patch.diff(repo, node1, node2, match=m, opts=diffopts)
-        width = ui.interactive() and util.termwidth() or 80
+        width = 80
+        if not ui.plain():
+            width = util.termwidth()
         for chunk, label in patch.diffstatui(util.iterlines(it), width=width,
                                              git=diffopts.git):
             ui.write(chunk, label=label)
@@ -1215,7 +1219,7 @@
     diff anyway, probably with undesirable results.
 
     Use the -g/--git option to generate diffs in the git extended diff
-    format. See 'hg help diffs' for more information.
+    format. See :hg:`help diffs` for more information.
 
     With the --switch-parent option, the diff will be against the
     second parent. It can be useful to review a merge.
@@ -1874,7 +1878,7 @@
 
     To read a patch from standard input, use "-" as the patch name. If
     a URL is specified, the patch will be downloaded from it.
-    See 'hg help dates' for a list of formats valid for -d/--date.
+    See :hg:`help dates` for a list of formats valid for -d/--date.
     """
     patches = (patch1,) + patches
 
@@ -2077,7 +2081,7 @@
     If no directory is given, the current directory is used.
 
     It is possible to specify an ``ssh://`` URL as the destination.
-    See 'hg help urls' for more information.
+    See :hg:`help urls` for more information.
     """
     hg.repository(cmdutil.remoteui(ui, opts), dest, create=1)
 
@@ -2132,7 +2136,7 @@
     --follow is set, in which case the working directory parent is
     used as the starting revision.
 
-    See 'hg help dates' for a list of formats valid for -d/--date.
+    See :hg:`help dates` for a list of formats valid for -d/--date.
 
     By default this command prints revision number and changeset id,
     tags, non-trivial parents, user, date and time, and a summary for
@@ -2157,6 +2161,9 @@
     if opts["date"]:
         df = util.matchdate(opts["date"])
 
+    branches = opts.get('branch', []) + opts.get('only_branch', [])
+    opts['branch'] = [repo.lookupbranch(b) for b in branches]
+
     displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
     def prep(ctx, fns):
         rev = ctx.rev()
@@ -2166,7 +2173,7 @@
             return
         if opts.get('only_merges') and len(parents) != 2:
             return
-        if opts.get('only_branch') and ctx.branch() not in opts['only_branch']:
+        if opts.get('branch') and ctx.branch() not in opts['branch']:
             return
         if df and not df(ctx.date()[0]):
             return
@@ -2380,7 +2387,7 @@
     unless a location is specified. When cloning a repository, the
     clone source is written as 'default' in .hg/hgrc.
 
-    See 'hg help urls' for more information.
+    See :hg:`help urls` for more information.
     """
     if search:
         for name, path in ui.configitems("paths"):
@@ -2422,7 +2429,7 @@
     where X is the last changeset listed by hg incoming.
 
     If SOURCE is omitted, the 'default' path will be used.
-    See 'hg help urls' for more information.
+    See :hg:`help urls` for more information.
     """
     source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
     other = hg.repository(cmdutil.remoteui(repo, opts), source)
@@ -2458,7 +2465,7 @@
     If -r/--rev is used, the named revision and all its ancestors will
     be pushed to the remote repository.
 
-    Please see 'hg help urls' for important details about ``ssh://``
+    Please see :hg:`help urls` for important details about ``ssh://``
     URLs. If DESTINATION is omitted, a default path will be used.
     """
     dest = ui.expandpath(dest or 'default-push', dest or 'default')
@@ -2656,8 +2663,8 @@
 
     Using the -r/--rev option, revert the given files or directories
     to their contents as of a specific revision. This can be helpful
-    to "roll back" some or all of an earlier change. See 'hg help
-    dates' for a list of formats valid for -d/--date.
+    to "roll back" some or all of an earlier change. See :hg:`help
+    dates` for a list of formats valid for -d/--date.
 
     Revert modifies the working directory. It does not commit any
     changes, or change the parent of the working directory. If you
@@ -3206,7 +3213,7 @@
     necessary. The file '.hg/localtags' is used for local tags (not
     shared among repositories).
 
-    See 'hg help dates' for a list of formats valid for -d/--date.
+    See :hg:`help dates` for a list of formats valid for -d/--date.
     """
 
     rev_ = "."
@@ -3348,12 +3355,12 @@
     3. With the -C/--clean option, uncommitted changes are discarded and
        the working directory is updated to the requested changeset.
 
-    Use null as the changeset to remove the working directory (like 'hg
-    clone -U').
-
-    If you want to update just one file to an older changeset, use 'hg revert'.
-
-    See 'hg help dates' for a list of formats valid for -d/--date.
+    Use null as the changeset to remove the working directory (like
+    :hg:`clone -U`).
+
+    If you want to update just one file to an older changeset, use :hg:`revert`.
+
+    See :hg:`help dates` for a list of formats valid for -d/--date.
     """
     if rev and node:
         raise util.Abort(_("please specify just one revision"))
@@ -3739,8 +3746,10 @@
           ('', 'removed', None, _('include revisions where files were removed')),
           ('m', 'only-merges', None, _('show only merges')),
           ('u', 'user', [], _('revisions committed by user')),
-          ('b', 'only-branch', [],
-            _('show only changesets within the given named branch')),
+          ('', 'only-branch', [],
+            _('show only changesets within the given named branch (DEPRECATED)')),
+          ('b', 'branch', [],
+            _('show changesets within the given named branch')),
           ('P', 'prune', [],
            _('do not display revision or any of its ancestors')),
          ] + logopts + walkopts,
--- a/mercurial/context.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/context.py	Sat Apr 24 01:37:49 2010 -0300
@@ -276,14 +276,14 @@
 
     def __hash__(self):
         try:
-            return hash((self._path, self._fileid))
+            return hash((self._path, self._filenode))
         except AttributeError:
             return id(self)
 
     def __eq__(self, other):
         try:
             return (self._path == other._path
-                    and self._fileid == other._fileid)
+                    and self._filenode == other._filenode)
         except AttributeError:
             return False
 
@@ -539,15 +539,14 @@
 class workingctx(changectx):
     """A workingctx object makes access to data related to
     the current working directory convenient.
-    parents - a pair of parent nodeids, or None to use the dirstate.
     date - any valid date string or (unixtime, offset), or None.
     user - username string, or None.
     extra - a dictionary of extra values, or None.
     changes - a list of file lists as returned by localrepo.status()
                or None to use the repository status.
     """
-    def __init__(self, repo, parents=None, text="", user=None, date=None,
-                 extra=None, changes=None):
+    def __init__(self, repo, text="", user=None, date=None, extra=None,
+                 changes=None):
         self._repo = repo
         self._rev = None
         self._node = None
@@ -556,8 +555,6 @@
             self._date = util.parsedate(date)
         if user:
             self._user = user
-        if parents:
-            self._parents = [changectx(self._repo, p) for p in parents]
         if changes:
             self._status = list(changes)
 
--- a/mercurial/dirstate.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/dirstate.py	Sat Apr 24 01:37:49 2010 -0300
@@ -285,14 +285,15 @@
         '''Mark a file normal, but possibly dirty.'''
         if self._pl[1] != nullid and f in self._map:
             # if there is a merge going on and the file was either
-            # in state 'm' or dirty before being removed, restore that state.
+            # in state 'm' (-1) or coming from other parent (-2) before
+            # being removed, restore that state.
             entry = self._map[f]
             if entry[0] == 'r' and entry[2] in (-1, -2):
                 source = self._copymap.get(f)
                 if entry[2] == -1:
                     self.merge(f)
                 elif entry[2] == -2:
-                    self.normaldirty(f)
+                    self.otherparent(f)
                 if source:
                     self.copy(source, f)
                 return
@@ -304,8 +305,11 @@
         if f in self._copymap:
             del self._copymap[f]
 
-    def normaldirty(self, f):
-        '''Mark a file normal, but dirty.'''
+    def otherparent(self, f):
+        '''Mark as coming from the other parent, always dirty.'''
+        if self._pl[1] == nullid:
+            raise util.Abort(_("setting %r to other parent "
+                               "only allowed in merges") % f)
         self._dirty = True
         self._addpath(f)
         self._map[f] = ('n', 0, -2, -1)
@@ -326,10 +330,11 @@
         self._droppath(f)
         size = 0
         if self._pl[1] != nullid and f in self._map:
+            # backup the previous state
             entry = self._map[f]
-            if entry[0] == 'm':
+            if entry[0] == 'm': # merge
                 size = -1
-            elif entry[0] == 'n' and entry[2] == -2:
+            elif entry[0] == 'n' and entry[2] == -2: # other parent
                 size = -2
         self._map[f] = ('r', 0, size, 0)
         if size == 0 and f in self._copymap:
@@ -638,7 +643,7 @@
                 if (size >= 0 and
                     (size != st.st_size
                      or ((mode ^ st.st_mode) & 0100 and self._checkexec))
-                    or size == -2
+                    or size == -2 # other parent
                     or fn in self._copymap):
                     madd(fn)
                 elif time != int(st.st_mtime):
--- a/mercurial/dispatch.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/dispatch.py	Sat Apr 24 01:37:49 2010 -0300
@@ -33,10 +33,13 @@
     def catchterm(*args):
         raise error.SignalInterrupt
 
-    for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
-        num = getattr(signal, name, None)
-        if num:
-            signal.signal(num, catchterm)
+    try:
+        for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
+            num = getattr(signal, name, None)
+            if num:
+                signal.signal(num, catchterm)
+    except ValueError:
+        pass # happens if called in a thread
 
     try:
         try:
--- a/mercurial/filemerge.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/filemerge.py	Sat Apr 24 01:37:49 2010 -0300
@@ -135,6 +135,9 @@
     if not fco.cmp(fcd.data()): # files identical?
         return None
 
+    if fca == fco: # backwards, use working dir parent as ancestor
+        fca = fcd.parents()[0]
+
     ui = repo.ui
     fd = fcd.path()
     binary = isbin(fcd) or isbin(fco) or isbin(fca)
--- a/mercurial/help/diffs.txt	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/help/diffs.txt	Sat Apr 24 01:37:49 2010 -0300
@@ -16,7 +16,7 @@
 format.
 
 This means that when generating diffs from a Mercurial repository
-(e.g. with "hg export"), you should be careful about things like file
+(e.g. with :hg:`export`), you should be careful about things like file
 copies and renames or other things mentioned above, because when
 applying a standard diff to a different repository, this extra
 information is lost. Mercurial's internal operations (like push and
--- a/mercurial/help/urls.txt	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/help/urls.txt	Sat Apr 24 01:37:49 2010 -0300
@@ -7,12 +7,12 @@
   ssh://[user[:pass]@]host[:port]/[path][#revision]
 
 Paths in the local filesystem can either point to Mercurial
-repositories or to bundle files (as created by 'hg bundle' or 'hg
-incoming --bundle').
+repositories or to bundle files (as created by :hg:`bundle` or :hg:`
+incoming --bundle`).
 
 An optional identifier after # indicates a particular branch, tag, or
-changeset to use from the remote repository. See also 'hg help
-revisions'.
+changeset to use from the remote repository. See also :hg:`help
+revisions`.
 
 Some features, such as pushing to http:// and https:// URLs are only
 possible if the feature is explicitly enabled on the remote Mercurial
@@ -47,7 +47,7 @@
   ...
 
 You can then use the alias for any command that uses a URL (for
-example 'hg pull alias1' will be treated as 'hg pull URL1').
+example :hg:`pull alias1` will be treated as :hg:`pull URL1`).
 
 Two path aliases are special because they are used as defaults when
 you do not provide the URL to a command:
--- a/mercurial/hgweb/protocol.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/hgweb/protocol.py	Sat Apr 24 01:37:49 2010 -0300
@@ -179,6 +179,8 @@
             raise ErrorResponse(HTTP_OK, inst)
         except (OSError, IOError), inst:
             error = getattr(inst, 'strerror', 'Unknown error')
+            if not isinstance(error, str):
+                error = 'Error: %s' % str(error)
             if inst.errno == errno.ENOENT:
                 code = HTTP_NOT_FOUND
             else:
--- a/mercurial/localrepo.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/localrepo.py	Sat Apr 24 01:37:49 2010 -0300
@@ -455,6 +455,14 @@
             pass
         raise error.RepoLookupError(_("unknown revision '%s'") % key)
 
+    def lookupbranch(self, key, remote=None):
+        repo = remote or self
+        if key in repo.branchmap():
+            return key
+
+        repo = (remote and remote.local()) and remote or self
+        return repo[key].branch()
+
     def local(self):
         return True
 
@@ -790,10 +798,10 @@
 
         wlock = self.wlock()
         try:
-            p1, p2 = self.dirstate.parents()
             wctx = self[None]
+            merge = len(wctx.parents()) > 1
 
-            if (not force and p2 != nullid and match and
+            if (not force and merge and match and
                 (match.files() or match.anypats())):
                 raise util.Abort(_('cannot partially commit a merge '
                                    '(do not specify files or patterns)'))
@@ -833,9 +841,9 @@
                     elif f not in self.dirstate:
                         fail(f, _("file not tracked!"))
 
-            if (not force and not extra.get("close") and p2 == nullid
+            if (not force and not extra.get("close") and not merge
                 and not (changes[0] or changes[1] or changes[2])
-                and self[None].branch() == self['.'].branch()):
+                and wctx.branch() == wctx.p1().branch()):
                 return None
 
             ms = mergemod.mergestate(self)
@@ -844,8 +852,7 @@
                     raise util.Abort(_("unresolved merge conflicts "
                                                     "(see hg resolve)"))
 
-            cctx = context.workingctx(self, (p1, p2), text, user, date,
-                                      extra, changes)
+            cctx = context.workingctx(self, text, user, date, extra, changes)
             if editor:
                 cctx._text = editor(self, cctx, subs)
             edited = (text != cctx._text)
@@ -866,8 +873,9 @@
             msgfile.write(cctx._text)
             msgfile.close()
 
+            p1, p2 = self.dirstate.parents()
+            hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
             try:
-                hookp1, hookp2 = hex(p1), (p2 != nullid and hex(p2) or '')
                 self.hook("precommit", throw=True, parent1=hookp1, parent2=hookp2)
                 ret = self.commitctx(cctx, True)
             except:
--- a/mercurial/merge.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/merge.py	Sat Apr 24 01:37:49 2010 -0300
@@ -364,7 +364,7 @@
             repo.dirstate.normallookup(f)
         elif m == "g": # get
             if branchmerge:
-                repo.dirstate.normaldirty(f)
+                repo.dirstate.otherparent(f)
             else:
                 repo.dirstate.normal(f)
         elif m == "m": # merge
@@ -507,8 +507,8 @@
         stats = applyupdates(repo, action, wc, p2)
 
         if not partial:
+            repo.dirstate.setparents(fp1, fp2)
             recordupdates(repo, action, branchmerge)
-            repo.dirstate.setparents(fp1, fp2)
             if not branchmerge and not fastforward:
                 repo.dirstate.setbranch(p2.branch())
     finally:
--- a/mercurial/minirst.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/minirst.py	Sat Apr 24 01:37:49 2010 -0300
@@ -252,6 +252,15 @@
     return blocks
 
 
+_hgrolere = re.compile(r':hg:`([^`]+)`')
+
+def hgrole(blocks):
+    for b in blocks:
+        if b['type'] == 'paragraph':
+            b['lines'] = [_hgrolere.sub(r'"hg \1"', l) for l in b['lines']]
+    return blocks
+
+
 def addmargins(blocks):
     """Adds empty blocks for vertical spacing.
 
@@ -261,7 +270,7 @@
     i = 1
     while i < len(blocks):
         if (blocks[i]['type'] == blocks[i - 1]['type'] and
-            blocks[i]['type'] in ('bullet', 'option', 'field', 'definition')):
+            blocks[i]['type'] in ('bullet', 'option', 'field')):
             i += 1
         else:
             blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
@@ -289,7 +298,7 @@
         return "%s\n%s" % (term, textwrap.fill(text, width=width,
                                                initial_indent=defindent,
                                                subsequent_indent=defindent))
-    initindent = subindent = indent
+    subindent = indent
     if block['type'] == 'bullet':
         if block['lines'][0].startswith('| '):
             # Remove bullet for line blocks and add no extra
@@ -321,7 +330,7 @@
 
     text = ' '.join(map(str.strip, block['lines']))
     return textwrap.fill(text, width=width,
-                         initial_indent=initindent,
+                         initial_indent=indent,
                          subsequent_indent=subindent)
 
 
@@ -333,6 +342,7 @@
     blocks = findliteralblocks(blocks)
     blocks, pruned = prunecontainers(blocks, keep or [])
     blocks = inlineliterals(blocks)
+    blocks = hgrole(blocks)
     blocks = splitparagraphs(blocks)
     blocks = updatefieldlists(blocks)
     blocks = findsections(blocks)
--- a/mercurial/patch.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/patch.py	Sat Apr 24 01:37:49 2010 -0300
@@ -6,11 +6,12 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
+import cStringIO, email.Parser, os, re
+import tempfile, zlib
+
 from i18n import _
 from node import hex, nullid, short
 import base85, cmdutil, mdiff, util, diffhelpers, copies
-import cStringIO, email.Parser, os, re
-import tempfile, zlib
 
 gitre = re.compile('diff --git a/(.*) b/(.*)')
 
@@ -1125,9 +1126,9 @@
     if (empty is None and not gitworkdone) or empty:
         raise NoHunks
 
+
 def applydiff(ui, fp, changed, strip=1, sourcefile=None, eolmode='strict'):
-    """
-    Reads a patch from fp and tries to apply it.
+    """Reads a patch from fp and tries to apply it.
 
     The dict 'changed' is filled in with all of the filenames changed
     by the patch. Returns 0 for a clean patch, -1 if any rejects were
@@ -1136,7 +1137,17 @@
     If 'eolmode' is 'strict', the patch content and patched file are
     read in binary mode. Otherwise, line endings are ignored when
     patching then normalized according to 'eolmode'.
+
+    Callers probably want to call 'updatedir' after this to apply
+    certain categories of changes not done by this function.
     """
+    return _applydiff(
+        ui, fp, patchfile, copyfile,
+        changed, strip=strip, sourcefile=sourcefile, eolmode=eolmode)
+
+
+def _applydiff(ui, fp, patcher, copyfn, changed, strip=1,
+               sourcefile=None, eolmode='strict'):
     rejects = 0
     err = 0
     current_file = None
@@ -1164,13 +1175,13 @@
             afile, bfile, first_hunk = values
             try:
                 if sourcefile:
-                    current_file = patchfile(ui, sourcefile, opener,
-                                             eolmode=eolmode)
+                    current_file = patcher(ui, sourcefile, opener,
+                                           eolmode=eolmode)
                 else:
                     current_file, missing = selectfile(afile, bfile,
                                                        first_hunk, strip)
-                    current_file = patchfile(ui, current_file, opener,
-                                             missing, eolmode)
+                    current_file = patcher(ui, current_file, opener,
+                                           missing=missing, eolmode=eolmode)
             except PatchError, err:
                 ui.warn(str(err) + '\n')
                 current_file, current_hunk = None, None
@@ -1181,7 +1192,7 @@
             cwd = os.getcwd()
             for gp in gitpatches:
                 if gp.op in ('COPY', 'RENAME'):
-                    copyfile(gp.oldpath, gp.path, cwd)
+                    copyfn(gp.oldpath, gp.path, cwd)
                 changed[gp.path] = gp
         else:
             raise util.Abort(_('unsupported parser state: %s') % state)
--- a/mercurial/subrepo.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/subrepo.py	Sat Apr 24 01:37:49 2010 -0300
@@ -274,7 +274,8 @@
         self._ui = ctx._repo.ui
 
     def _svncommand(self, commands):
-        cmd = ['svn'] + commands + [self._path]
+        path = os.path.join(self._ctx._repo.origroot, self._path)
+        cmd = ['svn'] + commands + [path]
         cmd = [util.shellquote(arg) for arg in cmd]
         cmd = util.quotecommand(' '.join(cmd))
         env = dict(os.environ)
--- a/mercurial/templates/template-vars.txt	Mon Apr 19 19:50:04 2010 +0200
+++ b/mercurial/templates/template-vars.txt	Sat Apr 24 01:37:49 2010 -0300
@@ -28,6 +28,10 @@
 annotate      an annotated file
 entries       the entries relevant to the page
 
+url           base url of hgweb interface
+staticurl     base url for static resources
+
+
 Templates and commands:
   changelog(rev) - a page for browsing changesets
     naventry - a link for jumping to a changeset number
--- a/tests/hghave	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/hghave	Sat Apr 24 01:37:49 2010 -0300
@@ -120,12 +120,12 @@
 def has_git():
     return matchoutput('git --version 2>&1', r'^git version')
 
-def has_rst2html():
-    for name in ('rst2html', 'rst2html.py'):
-        name = name + ' --version 2>&1'
-        if matchoutput(name, r'^rst2html(?:\.py)? \(Docutils'):
-            return True
-    return False
+def has_docutils():
+    try:
+        from docutils.core import publish_cmdline
+        return True
+    except ImportError:
+        return False
 
 def has_svn():
     return matchoutput('svn --version 2>&1', r'^svn, version') and \
@@ -198,7 +198,7 @@
     "outer-repo": (has_outer_repo, "outer repo"),
     "p4": (has_p4, "Perforce server and client"),
     "pygments": (has_pygments, "Pygments source highlighting library"),
-    "rst2html": (has_rst2html, "Docutils rst2html tool"),
+    "docutils": (has_docutils, "Docutils text processing library"),
     "svn": (has_svn, "subversion client and admin tools"),
     "svn-bindings": (has_svn_bindings, "subversion python bindings"),
     "symlink": (has_symlink, "symbolic links"),
--- a/tests/test-convert-svn-sink.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-convert-svn-sink.out	Sat Apr 24 01:37:49 2010 -0300
@@ -4,8 +4,8 @@
 % modify
 1:e0e2b8a9156b
 assuming destination a-hg
-initializing svn repo 'a-hg'
-initializing svn wc 'a-hg-wc'
+initializing svn repository 'a-hg'
+initializing svn working copy 'a-hg-wc'
 scanning source...
 sorting...
 converting...
@@ -57,7 +57,7 @@
 % rename
 2:eb5169441d43
 assuming destination a-hg
-initializing svn wc 'a-hg-wc'
+initializing svn working copy 'a-hg-wc'
 scanning source...
 sorting...
 converting...
@@ -95,7 +95,7 @@
 % copy
 3:60effef6ab48
 assuming destination a-hg
-initializing svn wc 'a-hg-wc'
+initializing svn working copy 'a-hg-wc'
 scanning source...
 sorting...
 converting...
@@ -134,7 +134,7 @@
 % remove
 4:87bbe3013fb6
 assuming destination a-hg
-initializing svn wc 'a-hg-wc'
+initializing svn working copy 'a-hg-wc'
 scanning source...
 sorting...
 converting...
@@ -168,7 +168,7 @@
 % executable
 5:ff42e473c340
 assuming destination a-hg
-initializing svn wc 'a-hg-wc'
+initializing svn working copy 'a-hg-wc'
 scanning source...
 sorting...
 converting...
@@ -196,8 +196,8 @@
 % executable in new directory
 adding d1/a
 assuming destination a-hg
-initializing svn repo 'a-hg'
-initializing svn wc 'a-hg-wc'
+initializing svn repository 'a-hg'
+initializing svn working copy 'a-hg-wc'
 scanning source...
 sorting...
 converting...
@@ -224,7 +224,7 @@
 executable
 % copy to new directory
 assuming destination a-hg
-initializing svn wc 'a-hg-wc'
+initializing svn working copy 'a-hg-wc'
 scanning source...
 sorting...
 converting...
@@ -267,8 +267,8 @@
 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
 use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
 assuming destination b-hg
-initializing svn repo 'b-hg'
-initializing svn wc 'b-hg-wc'
+initializing svn repository 'b-hg'
+initializing svn working copy 'b-hg-wc'
 scanning source...
 sorting...
 converting...
--- a/tests/test-convert.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-convert.out	Sat Apr 24 01:37:49 2010 -0300
@@ -103,8 +103,10 @@
         ignore integrity errors when reading. Use it to fix Mercurial
         repositories with missing revlogs, by converting from and to
         Mercurial.
+
     --config convert.hg.saverev=False         (boolean)
         store original revision ID in changeset (forces target IDs to change)
+
     --config convert.hg.startrev=0            (hg revision identifier)
         convert start revision and its descendants
 
@@ -125,25 +127,30 @@
     --config convert.cvsps.cache=True         (boolean)
         Set to False to disable remote log caching, for testing and debugging
         purposes.
+
     --config convert.cvsps.fuzz=60            (integer)
         Specify the maximum time (in seconds) that is allowed between commits
         with identical user and log message in a single changeset. When very
         large files were checked in as part of a changeset then the default
         may not be long enough.
+
     --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}'
         Specify a regular expression to which commit log messages are matched.
         If a match occurs, then the conversion process will insert a dummy
         revision merging the branch on which this log message occurs to the
         branch indicated in the regex.
+
     --config convert.cvsps.mergefrom='{{mergefrombranch ([-\w]+)}}'
         Specify a regular expression to which commit log messages are matched.
         If a match occurs, then the conversion process will add the most
         recent revision on the branch indicated in the regex as the second
         parent of the changeset.
+
     --config hook.cvslog
         Specify a Python function to be called at the end of gathering the CVS
         log. The function is passed a list with the log entries, and can
         modify the entries in-place, or add or delete them.
+
     --config hook.cvschangesets
         Specify a Python function to be called after the changesets are
         calculated from the the CVS log. The function is passed a list with
@@ -170,8 +177,10 @@
 
     --config convert.svn.branches=branches    (directory name)
         specify the directory containing branches
+
     --config convert.svn.tags=tags            (directory name)
         specify the directory containing tags
+
     --config convert.svn.trunk=trunk          (directory name)
         specify the name of the trunk branch
 
@@ -202,8 +211,10 @@
 
     --config convert.hg.clonebranches=False   (boolean)
         dispatch source branches in separate clones.
+
     --config convert.hg.tagsbranch=default    (branch name)
         tag revisions branch name
+
     --config convert.hg.usebranchnames=True   (boolean)
         preserve branch names
 
@@ -259,13 +270,13 @@
 assuming destination emptydir-hg
 initializing destination emptydir-hg repository
 emptydir does not look like a CVS checkout
-emptydir does not look like a Git repo
-emptydir does not look like a Subversion repo
-emptydir is not a local Mercurial repo
-emptydir does not look like a darcs repo
-emptydir does not look like a monotone repo
-emptydir does not look like a GNU Arch repo
-emptydir does not look like a Bazaar repo
+emptydir does not look like a Git repository
+emptydir does not look like a Subversion repository
+emptydir is not a local Mercurial repository
+emptydir does not look like a darcs repository
+emptydir does not look like a monotone repository
+emptydir does not look like a GNU Arch repository
+emptydir does not look like a Bazaar repository
 cannot find required "p4" tool
 abort: emptydir: missing or unsupported repository
 % convert with imaginary source type
--- a/tests/test-debugcomplete.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-debugcomplete.out	Sat Apr 24 01:37:49 2010 -0300
@@ -171,7 +171,7 @@
 export: output, switch-parent, rev, text, git, nodates
 forget: include, exclude
 init: ssh, remotecmd
-log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, prune, patch, git, limit, no-merges, style, template, include, exclude
+log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, patch, git, limit, no-merges, style, template, include, exclude
 merge: force, rev, preview
 pull: update, force, rev, branch, ssh, remotecmd
 push: force, rev, branch, ssh, remotecmd
--- a/tests/test-gendoc	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-gendoc	Sat Apr 24 01:37:49 2010 -0300
@@ -1,7 +1,6 @@
 #!/bin/sh
 
-"$TESTDIR/hghave" rst2html || exit 80
-RST2HTML=`which rst2html 2> /dev/null || which rst2html.py`
+"$TESTDIR/hghave" docutils || exit 80
 
 HGENCODING=UTF-8
 export HGENCODING
@@ -14,8 +13,8 @@
     echo "" >> gendoc-$LOCALE.txt
     LC_ALL=$LOCALE python $TESTDIR/../doc/gendoc.py >> gendoc-$LOCALE.txt || exit
 
-    # We run rst2html over the file without adding "--halt warning" to
-    # make it report all errors instead of stopping on the first one.
-    echo "checking for parse errors with rst2html"
-    $RST2HTML gendoc-$LOCALE.txt /dev/null
+    # We call runrst without adding "--halt warning" to make it report
+    # all errors instead of stopping on the first one.
+    echo "checking for parse errors"
+    python $TESTDIR/../doc/runrst html gendoc-$LOCALE.txt /dev/null
 done
--- a/tests/test-gendoc.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-gendoc.out	Sat Apr 24 01:37:49 2010 -0300
@@ -1,33 +1,33 @@
 
 % extracting documentation from C
-checking for parse errors with rst2html
+checking for parse errors
 
 % extracting documentation from da
-checking for parse errors with rst2html
+checking for parse errors
 
 % extracting documentation from de
-checking for parse errors with rst2html
+checking for parse errors
 
 % extracting documentation from el
-checking for parse errors with rst2html
+checking for parse errors
 
 % extracting documentation from fr
-checking for parse errors with rst2html
+checking for parse errors
 
 % extracting documentation from it
-checking for parse errors with rst2html
+checking for parse errors
 
 % extracting documentation from ja
-checking for parse errors with rst2html
+checking for parse errors
 
 % extracting documentation from pt_BR
-checking for parse errors with rst2html
+checking for parse errors
 
 % extracting documentation from sv
-checking for parse errors with rst2html
+checking for parse errors
 
 % extracting documentation from zh_CN
-checking for parse errors with rst2html
+checking for parse errors
 
 % extracting documentation from zh_TW
-checking for parse errors with rst2html
+checking for parse errors
--- a/tests/test-help.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-help.out	Sat Apr 24 01:37:49 2010 -0300
@@ -391,7 +391,7 @@
     with undesirable results.
 
     Use the -g/--git option to generate diffs in the git extended diff format.
-    For more information, read 'hg help diffs'.
+    For more information, read "hg help diffs".
 
 options:
 
--- a/tests/test-inotify	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-inotify	Sat Apr 24 01:37:49 2010 -0300
@@ -82,7 +82,7 @@
 echo c >> a
 hg st
 
-hg up 0
+HGMERGE=internal:local hg up 0
 hg st
 
 HGMERGE=internal:local hg up
--- a/tests/test-inotify.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-inotify.out	Sat Apr 24 01:37:49 2010 -0300
@@ -44,7 +44,6 @@
 A h
 R h/h
 M a
-merging a
 1 files updated, 1 files merged, 2 files removed, 0 files unresolved
 M a
 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-log	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-log	Sat Apr 24 01:37:49 2010 -0300
@@ -135,4 +135,46 @@
 hg log -u "user1" -u "user2"
 hg log -u "user3"
 
+cd ..
+
+hg init branches
+cd branches
+
+echo a > a
+hg ci -A -m "commit on default"
+hg branch test
+echo b > b
+hg ci -A -m "commit on test"
+
+hg up default
+echo c > c
+hg ci -A -m "commit on default"
+hg up test
+echo c > c
+hg ci -A -m "commit on test"
+
+echo '% log -b default'
+hg log -b default
+
+echo '% log -b test'
+hg log -b test
+
+echo '% log -b dummy'
+hg log -b dummy
+
+echo '% log -b .'
+hg log -b .
+
+echo '% log -b default -b test'
+hg log -b default -b test
+
+echo '% log -b default -b .'
+hg log -b default -b .
+
+echo '% log -b . -b test'
+hg log -b . -b test
+
+echo '% log -b 2'
+hg log -b 2
+
 exit 0
--- a/tests/test-log.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-log.out	Sat Apr 24 01:37:49 2010 -0300
@@ -324,3 +324,134 @@
 date:        Thu Jan 01 00:00:00 1970 +0000
 summary:     a
 
+adding a
+marked working directory as branch test
+adding b
+0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+adding c
+created new head
+1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+adding c
+% log -b default
+changeset:   2:c3a4f03cc9a7
+parent:      0:24427303d56f
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on default
+
+changeset:   0:24427303d56f
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on default
+
+% log -b test
+changeset:   3:f5d8de11c2e2
+branch:      test
+tag:         tip
+parent:      1:d32277701ccb
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on test
+
+changeset:   1:d32277701ccb
+branch:      test
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on test
+
+% log -b dummy
+abort: unknown revision 'dummy'!
+% log -b .
+changeset:   3:f5d8de11c2e2
+branch:      test
+tag:         tip
+parent:      1:d32277701ccb
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on test
+
+changeset:   1:d32277701ccb
+branch:      test
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on test
+
+% log -b default -b test
+changeset:   3:f5d8de11c2e2
+branch:      test
+tag:         tip
+parent:      1:d32277701ccb
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on test
+
+changeset:   2:c3a4f03cc9a7
+parent:      0:24427303d56f
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on default
+
+changeset:   1:d32277701ccb
+branch:      test
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on test
+
+changeset:   0:24427303d56f
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on default
+
+% log -b default -b .
+changeset:   3:f5d8de11c2e2
+branch:      test
+tag:         tip
+parent:      1:d32277701ccb
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on test
+
+changeset:   2:c3a4f03cc9a7
+parent:      0:24427303d56f
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on default
+
+changeset:   1:d32277701ccb
+branch:      test
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on test
+
+changeset:   0:24427303d56f
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on default
+
+% log -b . -b test
+changeset:   3:f5d8de11c2e2
+branch:      test
+tag:         tip
+parent:      1:d32277701ccb
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on test
+
+changeset:   1:d32277701ccb
+branch:      test
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on test
+
+% log -b 2
+changeset:   2:c3a4f03cc9a7
+parent:      0:24427303d56f
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on default
+
+changeset:   0:24427303d56f
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     commit on default
+
--- a/tests/test-merge-local.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-merge-local.out	Sat Apr 24 01:37:49 2010 -0300
@@ -24,16 +24,20 @@
 use 'hg resolve' to retry unresolved file merges
 merging zzz1_merge_ok
 merging zzz2_merge_bad
-2 files updated, 2 files merged, 3 files removed, 0 files unresolved
+warning: conflicts during merge.
+merging zzz2_merge_bad failed!
+2 files updated, 1 files merged, 3 files removed, 1 files unresolved
+use 'hg resolve' to retry unresolved file merges
 --- a/zzz1_merge_ok
 +++ b/zzz1_merge_ok
-+new first line
 +new last line
 --- a/zzz2_merge_bad
 +++ b/zzz2_merge_bad
 +another last line
++=======
 M zzz1_merge_ok
 M zzz2_merge_bad
+? zzz2_merge_bad.orig
 # local merge with conflicts
 merging zzz1_merge_ok
 merging zzz2_merge_bad
@@ -43,18 +47,23 @@
 use 'hg resolve' to retry unresolved file merges
 merging zzz1_merge_ok
 merging zzz2_merge_bad
-2 files updated, 2 files merged, 3 files removed, 0 files unresolved
+warning: conflicts during merge.
+merging zzz2_merge_bad failed!
+2 files updated, 1 files merged, 3 files removed, 1 files unresolved
+use 'hg resolve' to retry unresolved file merges
 --- a/zzz1_merge_ok
 +++ b/zzz1_merge_ok
-+new first line
 +new last line
 --- a/zzz2_merge_bad
 +++ b/zzz2_merge_bad
 +another last line
 +=======
++=======
 +new last line
++=======
 M zzz1_merge_ok
 M zzz2_merge_bad
+? zzz2_merge_bad.orig
 # local merge without conflicts
 merging zzz1_merge_ok
 4 files updated, 1 files merged, 2 files removed, 0 files unresolved
--- a/tests/test-minirst.py	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-minirst.py	Sat Apr 24 01:37:49 2010 -0300
@@ -178,3 +178,6 @@
 debugformat('containers (debug)', containers, 60, keep=['debug'])
 debugformat('containers (verbose debug)', containers, 60,
             keep=['verbose', 'debug'])
+
+roles = """Please see :hg:`add`."""
+debugformat('roles', roles, 60)
--- a/tests/test-minirst.py.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-minirst.py.out	Sat Apr 24 01:37:49 2010 -0300
@@ -25,10 +25,12 @@
 ----------------------------------------------------------------------
 A Term
   Definition. The indented lines make up the definition.
+
 Another Term
     Another definition. The final line in the definition
     determines the indentation, so this will be indented
     with four spaces.
+
   A Nested/Indented Term
     Definition.
 ----------------------------------------------------------------------
@@ -39,6 +41,7 @@
   Definition. The indented
   lines make up the
   definition.
+
 Another Term
     Another definition. The
     final line in the
@@ -46,6 +49,7 @@
     indentation, so this will
     be indented with four
     spaces.
+
   A Nested/Indented Term
     Definition.
 ----------------------------------------------------------------------
@@ -294,3 +298,8 @@
 []
 ----------------------------------------------------------------------
 
+roles formatted to fit within 60 characters:
+----------------------------------------------------------------------
+Please see "hg add".
+----------------------------------------------------------------------
+
--- a/tests/test-qrecord.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-qrecord.out	Sat Apr 24 01:37:49 2010 -0300
@@ -28,7 +28,7 @@
 
 interactively record a new patch
 
-    See 'hg help qnew' & 'hg help record' for more information and usage.
+    See "hg help qnew" & "hg help record" for more information and usage.
 
 options:
 
--- a/tests/test-record	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-record	Sat Apr 24 01:37:49 2010 -0300
@@ -37,6 +37,10 @@
 EOF
 echo; hg tip -p
 
+echo % summary shows we updated to the new cset
+hg summary
+echo
+
 echo % rename empty file
 
 hg mv empty-rw empty-rename
@@ -315,4 +319,3 @@
 y
 EOF
 echo; hg tip -p
-
--- a/tests/test-record.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-record.out	Sat Apr 24 01:37:49 2010 -0300
@@ -6,7 +6,7 @@
     If a list of files is omitted, all changes reported by "hg status" will be
     candidates for recording.
 
-    See 'hg help dates' for a list of formats valid for -d/--date.
+    See "hg help dates" for a list of formats valid for -d/--date.
 
     You will be prompted for whether to record changes to each modified file,
     and for files with multiple changes, for each change to use. For each
@@ -72,6 +72,13 @@
 summary:     empty
 
 
+% summary shows we updated to the new cset
+parent: 0:c0708cf4e46e tip
+ empty
+branch: default
+commit: (clean)
+update: (current)
+
 % rename empty file
 diff --git a/empty-rw b/empty-rename
 rename from empty-rw
--- a/tests/test-subrepo-svn	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-subrepo-svn	Sat Apr 24 01:37:49 2010 -0300
@@ -16,7 +16,8 @@
 fi
 escapedwd=`python -c "import urllib, sys; sys.stdout.write(urllib.quote(sys.argv[1]))" "$escapedwd"`
 filterpath="s|$escapedwd|/root|"
-filtersvn='s/ in transaction.*/ is out of date/;s/Out of date: /File /'
+filteroutofdate='s/ in transaction.*/ is out of date/;s/Out of date: /File /'
+filterexternal="s|Fetching external item into '.*/s/externals'|Fetching external item into 's/externals'|g"
 
 echo % create subversion repo
 
@@ -62,7 +63,7 @@
 echo % change file in svn and hg, commit
 echo a >> a
 echo alpha >> s/alpha
-hg commit -m 'Message!'
+hg commit -m 'Message!' | sed "$filterexternal"
 hg debugsub | sed "$filterpath"
 
 echo
@@ -81,12 +82,12 @@
 
 echo % this commit from hg will fail
 echo zzz >> s/alpha
-hg ci -m 'amend alpha from hg' 2>&1 | sed "$filtersvn"
+hg ci -m 'amend alpha from hg' 2>&1 | sed "$filteroutofdate"
 svn revert -q s/alpha
 
 echo % this commit fails because of meta changes
 svn propset svn:mime-type 'text/html' s/alpha
-hg ci -m 'amend alpha from hg' 2>&1 | sed "$filtersvn"
+hg ci -m 'amend alpha from hg' 2>&1 | sed "$filteroutofdate"
 svn revert -q s/alpha
 
 echo % this commit fails because of externals changes
@@ -106,3 +107,6 @@
 cd tc
 echo % debugsub in clone
 hg debugsub | sed "$filterpath"
+
+echo % verify subrepo is contained within the repo directory
+python -c "import os.path; print os.path.exists('s')"
--- a/tests/test-subrepo-svn.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-subrepo-svn.out	Sat Apr 24 01:37:49 2010 -0300
@@ -72,11 +72,11 @@
 
 % clone
 updating to branch default
-A    s/alpha
- U   s
+A    tc/s/alpha
+ U   tc/s
 
-Fetching external item into 's/externals'
-A    s/externals/other
+Fetching external item into 'tc/s/externals'
+A    tc/s/externals/other
 Checked out external at revision 1.
 
 Checked out revision 3.
@@ -85,3 +85,5 @@
 path s
  source   file:///root/svn-repo/src
  revision 3
+% verify subrepo is contained within the repo directory
+True
--- a/tests/test-up-local-change.out	Mon Apr 19 19:50:04 2010 +0200
+++ b/tests/test-up-local-change.out	Sat Apr 24 01:37:49 2010 -0300
@@ -48,8 +48,7 @@
 update: a 2/2 files (100.00%)
 picked tool 'true' for a (binary False symlink False)
 merging a
-my a@802f095af299+ other a@33aaa84a386b ancestor a@33aaa84a386b
- premerge successful
+my a@802f095af299+ other a@33aaa84a386b ancestor a@802f095af299
 0 files updated, 1 files merged, 1 files removed, 0 files unresolved
 changeset:   0:33aaa84a386b
 user:        test