Merge with crew-stable
authorPatrick Mezard <pmezard@gmail.com>
Sat, 12 Apr 2008 21:34:01 +0200
changeset 6529 0c611355481b
parent 6528 bd6bf5798f39 (diff)
parent 6519 a7582980d654 (current diff)
child 6530 4b92591c69a7
Merge with crew-stable
mercurial/context.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/dumprevlog	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+# Dump revlogs as raw data stream
+# $ find .hg/store/ -name "*.i" | xargs dumprevlog > repo.dump
+
+import sys
+from mercurial import revlog, node, util
+
+for fp in (sys.stdin, sys.stdout, sys.stderr):
+    util.set_binary(fp)
+
+for f in sys.argv[1:]:
+    binopen = lambda fn: open(fn, 'rb')
+    r = revlog.revlog(binopen, f)
+    print "file:", f
+    for i in xrange(r.count()):
+        n = r.node(i)
+        p = r.parents(n)
+        d = r.revision(n)
+        print "node:", node.hex(n)
+        print "linkrev:", r.linkrev(n)
+        print "parents:", node.hex(p[0]), node.hex(p[1])
+        print "length:", len(d)
+        print "-start-"
+        print d
+        print "-end-"
--- a/contrib/mercurial.el	Sat Apr 12 21:08:03 2008 +0200
+++ b/contrib/mercurial.el	Sat Apr 12 21:34:01 2008 +0200
@@ -35,8 +35,10 @@
 ;; This code has been developed under XEmacs 21.5, and may not work as
 ;; well under GNU Emacs (albeit tested under 21.4).  Patches to
 ;; enhance the portability of this code, fix bugs, and add features
-;; are most welcome.  You can clone a Mercurial repository for this
-;; package from http://www.serpentine.com/hg/hg-emacs
+;; are most welcome.
+
+;; As of version 22.3, GNU Emacs's VC mode has direct support for
+;; Mercurial, so this package may not prove as useful there.
 
 ;; Please send problem reports and suggestions to bos@serpentine.com.
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/undumprevlog	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# Undump a dump from dumprevlog
+# $ hg init
+# $ undumprevlog < repo.dump
+
+import sys
+from mercurial import revlog, node, util, transaction
+
+for fp in (sys.stdin, sys.stdout, sys.stderr):
+    util.set_binary(fp)
+
+opener = util.opener('.', False)
+tr = transaction.transaction(sys.stderr.write, opener, "undump.journal")
+while 1:
+    l = sys.stdin.readline()
+    if not l:
+        break
+    if l.startswith("file:"):
+        f = l[6:-1]
+        r = revlog.revlog(opener, f)
+        print f
+    elif l.startswith("node:"):
+        n = node.bin(l[6:-1])
+    elif l.startswith("linkrev:"):
+        lr = int(l[9:-1])
+    elif l.startswith("parents:"):
+        p = l[9:-1].split()
+        p1 = node.bin(p[0])
+        p2 = node.bin(p[1])
+    elif l.startswith("length:"):
+        length = int(l[8:-1])
+        sys.stdin.readline() # start marker
+        d = sys.stdin.read(length)
+        sys.stdin.readline() # end marker
+        r.addrevision(d, tr, lr, p1, p2)
+
+tr.close()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/win32/hg.bat	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,12 @@
+@echo off
+rem Windows Driver script for Mercurial
+
+setlocal
+set HG=%~f0
+
+rem Use a full path to Python (relative to this script) as the standard Python
+rem install does not put python.exe on the PATH...
+rem %~dp0 is the directory of this script
+
+%~dp0..\python "%~dp0hg" %*
+endlocal
--- a/doc/hg.1.txt	Sat Apr 12 21:08:03 2008 +0200
+++ b/doc/hg.1.txt	Sat Apr 12 21:34:01 2008 +0200
@@ -30,7 +30,7 @@
 
 repository path::
     either the pathname of a local repository or the URI of a remote
-    repository.  There are two available URI protocols, http:// which is
+    repository. There are two available URI protocols, http:// which is
     fast and the static-http:// protocol which is much slower but does not
     require a special server on the web host.
 
@@ -43,7 +43,7 @@
     Mercurial accepts several notations for identifying individual
     revisions.
 
-    A plain integer is treated as a revision number.  Negative
+    A plain integer is treated as a revision number. Negative
     integers are treated as offsets from the tip, with -1 denoting the
     tip.
 
@@ -52,11 +52,11 @@
 
     A hexadecimal string less than 40 characters long is treated as a
     unique revision identifier, and referred to as a short-form
-    identifier.  A short-form identifier is only valid if it is the
+    identifier. A short-form identifier is only valid if it is the
     prefix of one full-length identifier.
 
     Any other string is treated as a tag name, which is a symbolic
-    name associated with a revision identifier.  Tag names may not
+    name associated with a revision identifier. Tag names may not
     contain the ":" character.
 
     The reserved name "tip" is a special tag that always identifies
@@ -78,16 +78,16 @@
     separated by the ":" character.
 
     The syntax of range notation is [BEGIN]:[END], where BEGIN and END
-    are revision identifiers.  Both BEGIN and END are optional.  If
-    BEGIN is not specified, it defaults to revision number 0.  If END
-    is not specified, it defaults to the tip.  The range ":" thus
+    are revision identifiers. Both BEGIN and END are optional. If
+    BEGIN is not specified, it defaults to revision number 0. If END
+    is not specified, it defaults to the tip. The range ":" thus
     means "all revisions".
 
     If BEGIN is greater than END, revisions are treated in reverse
     order.
 
-    A range acts as a closed interval.  This means that a range of 3:5
-    gives 3, 4 and 5.  Similarly, a range of 4:2 gives 4, 3, and 2.
+    A range acts as a closed interval. This means that a range of 3:5
+    gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
 
 FILES
 -----
@@ -103,7 +103,7 @@
  /etc/mercurial/hgrc, $HOME/.hgrc, .hg/hgrc::
     This file contains defaults and configuration. Values in .hg/hgrc
     override those in $HOME/.hgrc, and these override settings made in the
-    global /etc/mercurial/hgrc configuration.  See hgrc(5) for details of
+    global /etc/mercurial/hgrc configuration. See hgrc(5) for details of
     the contents and format of these files.
 
 Some commands (e.g. revert) produce backup files ending in .orig, if
--- a/doc/hgignore.5.txt	Sat Apr 12 21:08:03 2008 +0200
+++ b/doc/hgignore.5.txt	Sat Apr 12 21:34:01 2008 +0200
@@ -17,25 +17,25 @@
 -----------
 
 Mercurial ignores every unmanaged file that matches any pattern in an
-ignore file.  The patterns in an ignore file do not apply to files
-managed by Mercurial.  To control Mercurial's handling of files that
-it manages, see the hg(1) man page.  Look for the "-I" and "-X"
+ignore file. The patterns in an ignore file do not apply to files
+managed by Mercurial. To control Mercurial's handling of files that
+it manages, see the hg(1) man page. Look for the "-I" and "-X"
 options.
 
 In addition, a Mercurial configuration file can point to a set of
-per-user or global ignore files.  See the hgrc(5) man page for details
-of how to configure these files.  Look for the "ignore" entry in the
+per-user or global ignore files. See the hgrc(5) man page for details
+of how to configure these files. Look for the "ignore" entry in the
 "ui" section.
 
 SYNTAX
 ------
 
 An ignore file is a plain text file consisting of a list of patterns,
-with one pattern per line.  Empty lines are skipped.  The "#"
+with one pattern per line. Empty lines are skipped. The "#"
 character is treated as a comment character, and the "\" character is
 treated as an escape character.
 
-Mercurial supports several pattern syntaxes.  The default syntax used
+Mercurial supports several pattern syntaxes. The default syntax used
 is Python/Perl-style regular expressions.
 
 To change the syntax used, use a line of the following form:
@@ -52,9 +52,9 @@
 The chosen syntax stays in effect when parsing all patterns that
 follow, until another syntax is selected.
 
-Neither glob nor regexp patterns are rooted.  A glob-syntax pattern of
+Neither glob nor regexp patterns are rooted. A glob-syntax pattern of
 the form "*.c" will match a file ending in ".c" in any directory, and
-a regexp pattern of the form "\.c$" will do the same.  To root a
+a regexp pattern of the form "\.c$" will do the same. To root a
 regexp pattern, start it with "^".
 
 EXAMPLE
--- a/doc/hgrc.5.txt	Sat Apr 12 21:08:03 2008 +0200
+++ b/doc/hgrc.5.txt	Sat Apr 12 21:34:01 2008 +0200
@@ -17,26 +17,26 @@
 
 Mercurial reads configuration data from several files, if they exist.
 The names of these files depend on the system on which Mercurial is
-installed.  *.rc files from a single directory are read in
-alphabetical order, later ones overriding earlier ones.  Where
+installed. *.rc files from a single directory are read in
+alphabetical order, later ones overriding earlier ones. Where
 multiple paths are given below, settings from later paths override
 earlier ones.
 
 (Unix) <install-root>/etc/mercurial/hgrc.d/*.rc::
 (Unix) <install-root>/etc/mercurial/hgrc::
     Per-installation configuration files, searched for in the
-    directory where Mercurial is installed.  <install-root> is the
+    directory where Mercurial is installed. <install-root> is the
     parent directory of the hg executable (or symlink) being run.
     For example, if installed in /shared/tools/bin/hg, Mercurial will
-    look in /shared/tools/etc/mercurial/hgrc.  Options in these files
+    look in /shared/tools/etc/mercurial/hgrc. Options in these files
     apply to all Mercurial commands executed by any user in any
     directory.
 
 (Unix) /etc/mercurial/hgrc.d/*.rc::
 (Unix) /etc/mercurial/hgrc::
     Per-system configuration files, for the system on which Mercurial
-    is running.  Options in these files apply to all Mercurial
-    commands executed by any user in any directory.  Options in these
+    is running. Options in these files apply to all Mercurial
+    commands executed by any user in any directory. Options in these
     files override per-installation options.
 
 (Windows) <install-dir>\Mercurial.ini::
@@ -45,7 +45,7 @@
   or else::
 (Windows) C:\Mercurial\Mercurial.ini::
     Per-installation/system configuration files, for the system on
-    which Mercurial is running.  Options in these files apply to all
+    which Mercurial is running. Options in these files apply to all
     Mercurial commands executed by any user in any directory.
     Registry keys contain PATH-like strings, every part of which must
     reference a Mercurial.ini file or be a directory where *.rc files
@@ -59,16 +59,16 @@
     Per-user configuration file(s), for the user running Mercurial.
     On Windows 9x, %HOME% is replaced by %APPDATA%.
     Options in these files apply to all Mercurial commands executed
-    by this user in any directory.  Options in thes files override
+    by this user in any directory. Options in thes files override
     per-installation and per-system options.
 
 (Unix, Windows) <repo>/.hg/hgrc::
     Per-repository configuration options that only apply in a
-    particular repository.  This file is not version-controlled, and
-    will not get transferred during a "clone" operation.  Options in
+    particular repository. This file is not version-controlled, and
+    will not get transferred during a "clone" operation. Options in
     this file override options in all other configuration files.
     On Unix, most of this file will be ignored if it doesn't belong
-    to a trusted user or to a trusted group.  See the documentation
+    to a trusted user or to a trusted group. See the documentation
     for the trusted section below for more details.
 
 SYNTAX
@@ -82,10 +82,10 @@
     green=
        eggs
 
-Each line contains one entry.  If the lines that follow are indented,
+Each line contains one entry. If the lines that follow are indented,
 they are treated as continuations of that entry.
 
-Leading whitespace is removed from values.  Empty lines are skipped.
+Leading whitespace is removed from values. Empty lines are skipped.
 
 The optional values can contain format strings which refer to other
 values in the same section, or values in a special DEFAULT section.
@@ -107,12 +107,12 @@
 
   Filters consist of a filter pattern followed by a filter command.
   Filter patterns are globs by default, rooted at the repository
-  root.  For example, to match any file ending in ".txt" in the root
-  directory only, use the pattern "*.txt".  To match any file ending
+  root. For example, to match any file ending in ".txt" in the root
+  directory only, use the pattern "*.txt". To match any file ending
   in ".c" anywhere in the repository, use the pattern "**.c".
 
   The filter command can start with a specifier, either "pipe:" or
-  "tempfile:".  If no specifier is given, "pipe:" is used by default.
+  "tempfile:". If no specifier is given, "pipe:" is used by default.
 
   A "pipe:" command must accept data on stdin and return the
   transformed data on stdout.
@@ -129,9 +129,9 @@
     # can safely omit "pipe:", because it's the default)
     *.gz = gzip
 
-  A "tempfile:" command is a template.  The string INFILE is replaced
+  A "tempfile:" command is a template. The string INFILE is replaced
   with the name of a temporary file that contains the data to be
-  filtered by the command.  The string OUTFILE is replaced with the
+  filtered by the command. The string OUTFILE is replaced with the
   name of an empty temporary file, where the filtered data must be
   written by the command.
 
@@ -192,22 +192,22 @@
 email::
   Settings for extensions that send email messages.
   from;;
-    Optional.  Email address to use in "From" header and SMTP envelope
+    Optional. Email address to use in "From" header and SMTP envelope
     of outgoing messages.
   to;;
-    Optional.  Comma-separated list of recipients' email addresses.
+    Optional. Comma-separated list of recipients' email addresses.
   cc;;
-    Optional.  Comma-separated list of carbon copy recipients'
+    Optional. Comma-separated list of carbon copy recipients'
     email addresses.
   bcc;;
-    Optional.  Comma-separated list of blind carbon copy
-    recipients' email addresses.  Cannot be set interactively.
+    Optional. Comma-separated list of blind carbon copy
+    recipients' email addresses. Cannot be set interactively.
   method;;
-    Optional.  Method to use to send email messages.  If value is
+    Optional. Method to use to send email messages. If value is
     "smtp" (default), use SMTP (see section "[smtp]" for
-    configuration).  Otherwise, use as name of program to run that
+    configuration). Otherwise, use as name of program to run that
     acts like sendmail (takes "-f" option for sender, list of
-    recipients on command line, message on stdin).  Normally, setting
+    recipients on command line, message on stdin). Normally, setting
     this to "sendmail" or "/usr/sbin/sendmail" is enough to use
     sendmail to send messages.
 
@@ -281,6 +281,7 @@
     myHtmlTool.priority = 1
 
   Supported arguments:
+
   priority;;
     The priority in which to evaluate this tool.
     Default: 0.
@@ -297,10 +298,10 @@
     launching external tool.
     Default: True
   binary;;
-    This tool can merge binary files.  Defaults to False, unless tool
+    This tool can merge binary files. Defaults to False, unless tool
     was selected by file pattern match.
   symlink;;
-    This tool can merge symlinks.  Defaults to False, even if tool was
+    This tool can merge symlinks. Defaults to False, even if tool was
     selected by file pattern match.
   checkconflicts;;
     Check whether there are conflicts even though the tool reported
@@ -313,18 +314,18 @@
   fixeol;;
     Attempt to fix up EOL changes caused by the merge tool.
     Default: False
-  gui:;
+  gui;;
     This tool requires a graphical interface to run. Default: False
   regkey;;
     Windows registry key which describes install location of this tool.
     Mercurial will search for this key first under HKEY_CURRENT_USER and
-    then under HKEY_LOCAL_MACHINE.  Default: None
+    then under HKEY_LOCAL_MACHINE. Default: None
   regname;;
-    Name of value to read from specified registry key.  Defaults to the
+    Name of value to read from specified registry key. Defaults to the
     unnamed (default) value.
   regappend;;
     String to append to the value read from the registry, typically the
-    executable name of the tool.  Default: None
+    executable name of the tool. Default: None
 
 hooks::
   Commands or Python functions that get automatically executed by
@@ -342,24 +343,24 @@
     incoming.autobuild = /my/build/hook
 
   Most hooks are run with environment variables set that give added
-  useful information.  For each hook below, the environment variables
+  useful information. For each hook below, the environment variables
   it is passed are listed with names of the form "$HG_foo".
 
   changegroup;;
     Run after a changegroup has been added via push, pull or
-    unbundle. ID of the first new changeset is in $HG_NODE.  URL from
+    unbundle. ID of the first new changeset is in $HG_NODE. URL from
     which changes came is in $HG_URL.
   commit;;
     Run after a changeset has been created in the local repository.
-    ID of the newly created changeset is in $HG_NODE.  Parent
+    ID of the newly created changeset is in $HG_NODE. Parent
     changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
   incoming;;
     Run after a changeset has been pulled, pushed, or unbundled into
-    the local repository.  The ID of the newly arrived changeset is in
-    $HG_NODE.  URL that was source of changes came is in $HG_URL.
+    the local repository. The ID of the newly arrived changeset is in
+    $HG_NODE. URL that was source of changes came is in $HG_URL.
   outgoing;;
-    Run after sending changes from local repository to another.  ID of
-    first changeset sent is in $HG_NODE.  Source of operation is in
+    Run after sending changes from local repository to another. ID of
+    first changeset sent is in $HG_NODE. Source of operation is in
     $HG_SOURCE; see "preoutgoing" hook for description.
   post-<command>;;
     Run after successful invocations of the associated command. The
@@ -371,56 +372,56 @@
     the command doesn't execute and Mercurial returns the failure code.
   prechangegroup;;
     Run before a changegroup is added via push, pull or unbundle.
-    Exit status 0 allows the changegroup to proceed.  Non-zero status
-    will cause the push, pull or unbundle to fail.  URL from which
+    Exit status 0 allows the changegroup to proceed. Non-zero status
+    will cause the push, pull or unbundle to fail. URL from which
     changes will come is in $HG_URL.
   precommit;;
-    Run before starting a local commit.  Exit status 0 allows the
-    commit to proceed.  Non-zero status will cause the commit to fail.
+    Run before starting a local commit. Exit status 0 allows the
+    commit to proceed. Non-zero status will cause the commit to fail.
     Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
   preoutgoing;;
     Run before collecting changes to send from the local repository to
-    another.  Non-zero status will cause failure.  This lets you
-    prevent pull over http or ssh.  Also prevents against local pull,
+    another. Non-zero status will cause failure. This lets you
+    prevent pull over http or ssh. Also prevents against local pull,
     push (outbound) or bundle commands, but not effective, since you
-    can just copy files instead then.  Source of operation is in
-    $HG_SOURCE.  If "serve", operation is happening on behalf of
-    remote ssh or http repository.  If "push", "pull" or "bundle",
+    can just copy files instead then. Source of operation is in
+    $HG_SOURCE. If "serve", operation is happening on behalf of
+    remote ssh or http repository. If "push", "pull" or "bundle",
     operation is happening on behalf of repository on same system.
   pretag;;
-    Run before creating a tag.  Exit status 0 allows the tag to be
-    created.  Non-zero status will cause the tag to fail.  ID of
-    changeset to tag is in $HG_NODE.  Name of tag is in $HG_TAG.  Tag
+    Run before creating a tag. Exit status 0 allows the tag to be
+    created. Non-zero status will cause the tag to fail. ID of
+    changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag
     is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0.
   pretxnchangegroup;;
     Run after a changegroup has been added via push, pull or unbundle,
-    but before the transaction has been committed.  Changegroup is
-    visible to hook program.  This lets you validate incoming changes
-    before accepting them.  Passed the ID of the first new changeset
-    in $HG_NODE.  Exit status 0 allows the transaction to commit.
+    but before the transaction has been committed. Changegroup is
+    visible to hook program. This lets you validate incoming changes
+    before accepting them. Passed the ID of the first new changeset
+    in $HG_NODE. Exit status 0 allows the transaction to commit.
     Non-zero status will cause the transaction to be rolled back and
-    the push, pull or unbundle will fail.  URL that was source of
+    the push, pull or unbundle will fail. URL that was source of
     changes is in $HG_URL.
   pretxncommit;;
     Run after a changeset has been created but the transaction not yet
-    committed.  Changeset is visible to hook program.  This lets you
-    validate commit message and changes.  Exit status 0 allows the
-    commit to proceed.  Non-zero status will cause the transaction to
-    be rolled back.  ID of changeset is in $HG_NODE.  Parent changeset
+    committed. Changeset is visible to hook program. This lets you
+    validate commit message and changes. Exit status 0 allows the
+    commit to proceed. Non-zero status will cause the transaction to
+    be rolled back. ID of changeset is in $HG_NODE. Parent changeset
     IDs are in $HG_PARENT1 and $HG_PARENT2.
   preupdate;;
-    Run before updating the working directory.  Exit status 0 allows
-    the update to proceed.  Non-zero status will prevent the update.
-    Changeset ID of first new parent is in $HG_PARENT1.  If merge, ID
+    Run before updating the working directory. Exit status 0 allows
+    the update to proceed. Non-zero status will prevent the update.
+    Changeset ID of first new parent is in $HG_PARENT1. If merge, ID
     of second new parent is in $HG_PARENT2.
   tag;;
-    Run after a tag is created.  ID of tagged changeset is in
-    $HG_NODE.  Name of tag is in $HG_TAG.  Tag is local if
+    Run after a tag is created. ID of tagged changeset is in
+    $HG_NODE. Name of tag is in $HG_TAG. Tag is local if
     $HG_LOCAL=1, in repo if $HG_LOCAL=0.
   update;;
-    Run after updating the working directory.  Changeset ID of first
-    new parent is in $HG_PARENT1.  If merge, ID of second new parent
-    is in $HG_PARENT2.  If update succeeded, $HG_ERROR=0.  If update
+    Run after updating the working directory. Changeset ID of first
+    new parent is in $HG_PARENT1. If merge, ID of second new parent
+    is in $HG_PARENT2. If update succeeded, $HG_ERROR=0. If update
     failed (e.g. because conflicts not resolved), $HG_ERROR=1.
 
   Note: it is generally better to use standard hooks rather than the
@@ -438,10 +439,10 @@
 
     hookname = python:modulename.submodule.callable
 
-  Python hooks are run within the Mercurial process.  Each hook is
+  Python hooks are run within the Mercurial process. Each hook is
   called with at least three keyword arguments: a ui object (keyword
   "ui"), a repository object (keyword "repo"), and a "hooktype"
-  keyword that tells what kind of hook is used.  Arguments listed as
+  keyword that tells what kind of hook is used. Arguments listed as
   environment variables above are passed as keyword arguments, with no
   "HG_" prefix, and names in lower case.
 
@@ -455,68 +456,68 @@
     Host name and (optional) port of the proxy server, for example
     "myproxy:8000".
   no;;
-    Optional.  Comma-separated list of host names that should bypass
+    Optional. Comma-separated list of host names that should bypass
     the proxy.
   passwd;;
-    Optional.  Password to authenticate with at the proxy server.
+    Optional. Password to authenticate with at the proxy server.
   user;;
-    Optional.  User name to authenticate with at the proxy server.
+    Optional. User name to authenticate with at the proxy server.
 
 smtp::
   Configuration for extensions that need to send email messages.
   host;;
     Host name of mail server, e.g. "mail.example.com".
   port;;
-    Optional.  Port to connect to on mail server.  Default: 25.
+    Optional. Port to connect to on mail server. Default: 25.
   tls;;
-    Optional.  Whether to connect to mail server using TLS.  True or
-    False.  Default: False.
+    Optional. Whether to connect to mail server using TLS. True or
+    False. Default: False.
   username;;
-    Optional.  User name to authenticate to SMTP server with.
+    Optional. User name to authenticate to SMTP server with.
     If username is specified, password must also be specified.
     Default: none.
   password;;
-    Optional.  Password to authenticate to SMTP server with.
+    Optional. Password to authenticate to SMTP server with.
     If username is specified, password must also be specified.
     Default: none.
   local_hostname;;
-    Optional.  It's the hostname that the sender can use to identify itself
+    Optional. It's the hostname that the sender can use to identify itself
     to the MTA.
 
 paths::
-  Assigns symbolic names to repositories.  The left side is the
+  Assigns symbolic names to repositories. The left side is the
   symbolic name, and the right gives the directory or URL that is the
-  location of the repository.  Default paths can be declared by
+  location of the repository. Default paths can be declared by
   setting the following entries.
   default;;
     Directory or URL to use when pulling if no source is specified.
     Default is set to repository from which the current repository
     was cloned.
   default-push;;
-    Optional.  Directory or URL to use when pushing if no destination
+    Optional. Directory or URL to use when pushing if no destination
     is specified.
 
 server::
   Controls generic server settings.
   uncompressed;;
     Whether to allow clients to clone a repo using the uncompressed
-    streaming protocol.  This transfers about 40% more data than a
+    streaming protocol. This transfers about 40% more data than a
     regular clone, but uses less memory and CPU on both server and
-    client.  Over a LAN (100Mbps or better) or a very fast WAN, an
+    client. Over a LAN (100Mbps or better) or a very fast WAN, an
     uncompressed streaming clone is a lot faster (~10x) than a regular
-    clone.  Over most WAN connections (anything slower than about
+    clone. Over most WAN connections (anything slower than about
     6Mbps), uncompressed streaming is slower, because of the extra
-    data transfer overhead.  Default is False.
+    data transfer overhead. Default is False.
 
 trusted::
   For security reasons, Mercurial will not use the settings in
   the .hg/hgrc file from a repository if it doesn't belong to a
-  trusted user or to a trusted group.  The main exception is the
+  trusted user or to a trusted group. The main exception is the
   web interface, which automatically uses some safe settings, since
   it's common to serve repositories from different users.
 
-  This section specifies what users and groups are trusted.  The
-  current user is always trusted.  To trust everybody, list a user
+  This section specifies what users and groups are trusted. The
+  current user is always trusted. To trust everybody, list a user
   or a group with name "*".
 
   users;;
@@ -532,12 +533,12 @@
     the hg archive command or downloaded via hgweb.
     Default is true.
   debug;;
-    Print debugging information.  True or False.  Default is False.
+    Print debugging information. True or False. Default is False.
   editor;;
-    The editor to use during a commit.  Default is $EDITOR or "vi".
+    The editor to use during a commit. Default is $EDITOR or "vi".
   fallbackencoding;;
     Encoding to try if it's not possible to decode the changelog using
-    UTF-8.  Default is ISO-8859-1.
+    UTF-8. Default is ISO-8859-1.
   ignore;;
     A file to read per-user ignore patterns from. This file should be in
     the same format as a repository-wide .hgignore file. This option
@@ -546,7 +547,7 @@
     "ignore.other = ~/.hgignore2". For details of the ignore file
     format, see the hgignore(5) man page.
   interactive;;
-    Allow to prompt the user.  True or False.  Default is True.
+    Allow to prompt the user. True or False. Default is True.
   logtemplate;;
     Template string for commands that print changesets.
   merge;;
@@ -563,18 +564,19 @@
         fail to merge
 
     See the merge-tools section for more information on configuring tools.
+
   patch;;
     command to use to apply patches. Look for 'gpatch' or 'patch' in PATH if
     unset.
   quiet;;
-    Reduce the amount of output printed.  True or False.  Default is False.
+    Reduce the amount of output printed. True or False. Default is False.
   remotecmd;;
     remote command to use for clone/push/pull operations. Default is 'hg'.
   report_untrusted;;
     Warn if a .hg/hgrc file is ignored due to not being owned by a
-    trusted user or group.  True or False.  Default is True.
+    trusted user or group. True or False. Default is True.
   slash;;
-    Display paths using a slash ("/") as the path separator.  This only
+    Display paths using a slash ("/") as the path separator. This only
     makes a difference on systems where the default path separator is not
     the slash character (e.g. Windows uses the backslash character ("\")).
     Default is False.
@@ -582,7 +584,7 @@
     command to use for SSH connections. Default is 'ssh'.
   strict;;
     Require exact command names, instead of allowing unambiguous
-    abbreviations.  True or False.  Default is False.
+    abbreviations. True or False. Default is False.
   style;;
     Name of style to use for command output.
   timeout;;
@@ -591,12 +593,12 @@
   username;;
     The committer of a changeset created when running "commit".
     Typically a person's name and email address, e.g. "Fred Widget
-    <fred@example.com>".  Default is $EMAIL or username@hostname.
+    <fred@example.com>". Default is $EMAIL or username@hostname.
     If the username in hgrc is empty, it has to be specified manually or
     in a different hgrc file (e.g. $HOME/.hgrc, if the admin set "username ="
     in the system hgrc).
   verbose;;
-    Increase the amount of output printed.  True or False.  Default is False.
+    Increase the amount of output printed. True or False. Default is False.
 
 
 web::
@@ -617,9 +619,9 @@
   allowpull;;
     Whether to allow pulling from the repository. Default is true.
   allow_push;;
-    Whether to allow pushing to the repository.  If empty or not set,
-    push is not allowed.  If the special value "*", any remote user
-    can push, including unauthenticated users.  Otherwise, the remote
+    Whether to allow pushing to the repository. If empty or not set,
+    push is not allowed. If the special value "*", any remote user
+    can push, including unauthenticated users. Otherwise, the remote
     user must have been authenticated, and the authenticated user name
     must be present in this list (separated by whitespace or ",").
     The contents of the allow_push list are examined after the
@@ -635,11 +637,11 @@
     Name or email address of the person in charge of the repository.
     Defaults to ui.username or $EMAIL or "unknown" if unset or empty.
   deny_push;;
-    Whether to deny pushing to the repository.  If empty or not set,
-    push is not denied.  If the special value "*", all remote users
-    are denied push.  Otherwise, unauthenticated users are all denied,
+    Whether to deny pushing to the repository. If empty or not set,
+    push is not denied. If the special value "*", all remote users
+    are denied push. Otherwise, unauthenticated users are all denied,
     and any authenticated user name present in this list (separated by
-    whitespace or ",") is also denied.  The contents of the deny_push
+    whitespace or ",") is also denied. The contents of the deny_push
     list are examined before the allow_push list.
   description;;
     Textual description of the repository's purpose or contents.
@@ -666,7 +668,7 @@
     Prefix path to serve from. Default is '' (server root).
   push_ssl;;
     Whether to require that inbound pushes be transported over SSL to
-    prevent password sniffing.  Default is true.
+    prevent password sniffing. Default is true.
   staticurl;;
     Base URL to use for static files. If unset, static files (e.g.
     the hgicon.png favicon) will be served by the CGI script itself.
--- a/hgext/highlight.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/hgext/highlight.py	Sat Apr 12 21:34:01 2008 +0200
@@ -15,23 +15,15 @@
 [web]
 pygments_style = <style>
 
-The default is 'colorful'.  If this is changed the corresponding CSS
-file should be re-generated by running
-
-# pygmentize -f html -S <newstyle>
-
+The default is 'colorful'.
 
 -- Adam Hupp <adam@hupp.org>
-
-
 """
 
 from mercurial import demandimport
-demandimport.ignore.extend(['pkgutil',
-                            'pkg_resources',
-                            '__main__',])
+demandimport.ignore.extend(['pkgutil', 'pkg_resources', '__main__',])
 
-from mercurial.hgweb.hgweb_mod import hgweb
+from mercurial.hgweb import webcommands, webutil, common
 from mercurial import util
 from mercurial.templatefilters import filters
 
@@ -40,10 +32,11 @@
 from pygments.lexers import guess_lexer, guess_lexer_for_filename, TextLexer
 from pygments.formatters import HtmlFormatter
 
-SYNTAX_CSS = ('\n<link rel="stylesheet" href="#staticurl#highlight.css" '
+SYNTAX_CSS = ('\n<link rel="stylesheet" href="{url}highlightcss" '
               'type="text/css" />')
 
-def pygmentize(self, tmpl, fctx, field):
+def pygmentize(field, fctx, style, tmpl):
+
     # append a <link ...> to the syntax highlighting css
     old_header = ''.join(tmpl('header'))
     if SYNTAX_CSS not in old_header:
@@ -54,7 +47,6 @@
     if util.binary(text):
         return
 
-    style = self.config("web", "pygments_style", "colorful")
     # To get multi-line strings right, we can't format line-by-line
     try:
         lexer = guess_lexer_for_filename(fctx.path(), text,
@@ -79,20 +71,30 @@
     newl = oldl.replace('line|escape', 'line|colorize')
     tmpl.cache[field] = newl
 
-def filerevision_highlight(self, tmpl, fctx):
-    pygmentize(self, tmpl, fctx, 'fileline')
+web_filerevision = webcommands._filerevision
+web_annotate = webcommands.annotate
 
-    return realrevision(self, tmpl, fctx)
+def filerevision_highlight(web, tmpl, fctx):
+    style = web.config('web', 'pygments_style', 'colorful')
+    pygmentize('fileline', fctx, style, tmpl)
+    return web_filerevision(web, tmpl, fctx)
 
-def fileannotate_highlight(self, tmpl, fctx):
-    pygmentize(self, tmpl, fctx, 'annotateline')
+def annotate_highlight(web, req, tmpl):
+    fctx = webutil.filectx(web.repo, req)
+    style = web.config('web', 'pygments_style', 'colorful')
+    pygmentize('annotateline', fctx, style, tmpl)
+    return web_annotate(web, req, tmpl)
 
-    return realannotate(self, tmpl, fctx)
+def generate_css(web, req, tmpl):
+    pg_style = web.config('web', 'pygments_style', 'colorful')
+    fmter = HtmlFormatter(style = pg_style)
+    req.respond(common.HTTP_OK, 'text/css')
+    return ['/* pygments_style = %s */\n\n' % pg_style, fmter.get_style_defs('')]
+
 
 # monkeypatch in the new version
-# should be safer than overriding the method in a derived class
-# and then patching the class
-realrevision = hgweb.filerevision
-hgweb.filerevision = filerevision_highlight
-realannotate = hgweb.fileannotate
-hgweb.fileannotate = fileannotate_highlight
+
+webcommands._filerevision = filerevision_highlight
+webcommands.annotate = annotate_highlight
+webcommands.highlightcss = generate_css
+webcommands.__all__.append('highlightcss')
--- a/hgext/keyword.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/hgext/keyword.py	Sat Apr 12 21:34:01 2008 +0200
@@ -100,52 +100,8 @@
     '''Returns hgdate in cvs-like UTC format.'''
     return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
 
-
 # make keyword tools accessible
-kwtools = {'templater': None, 'hgcmd': None}
-
-# store originals of monkeypatches
-_patchfile_init = patch.patchfile.__init__
-_patch_diff = patch.diff
-_dispatch_parse = dispatch._parse
-
-def _kwpatchfile_init(self, ui, fname, missing=False):
-    '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
-    rejects or conflicts due to expanded keywords in working dir.'''
-    _patchfile_init(self, ui, fname, missing=missing)
-    # shrink keywords read from working dir
-    kwt = kwtools['templater']
-    self.lines = kwt.shrinklines(self.fname, self.lines)
-
-def _kw_diff(repo, node1=None, node2=None, files=None, match=util.always,
-             fp=None, changes=None, opts=None):
-    '''Monkeypatch patch.diff to avoid expansion except when
-    comparing against working dir.'''
-    if node2 is not None:
-        kwtools['templater'].matcher = util.never
-    elif node1 is not None and node1 != repo.changectx().node():
-        kwtools['templater'].restrict = True
-    _patch_diff(repo, node1=node1, node2=node2, files=files, match=match,
-                fp=fp, changes=changes, opts=opts)
-
-def _kwweb_changeset(web, req, tmpl):
-    '''Wraps webcommands.changeset turning off keyword expansion.'''
-    kwtools['templater'].matcher = util.never
-    return web.changeset(tmpl, web.changectx(req))
-
-def _kwweb_filediff(web, req, tmpl):
-    '''Wraps webcommands.filediff turning off keyword expansion.'''
-    kwtools['templater'].matcher = util.never
-    return web.filediff(tmpl, web.filectx(req))
-
-def _kwdispatch_parse(ui, args):
-    '''Monkeypatch dispatch._parse to obtain running hg command.'''
-    cmd, func, args, options, cmdoptions = _dispatch_parse(ui, args)
-    kwtools['hgcmd'] = cmd
-    return cmd, func, args, options, cmdoptions
-
-# dispatch._parse is run before reposetup, so wrap it here
-dispatch._parse = _kwdispatch_parse
+kwtools = {'templater': None, 'hgcmd': '', 'inc': [], 'exc': ['.hg*']}
 
 
 class kwtemplater(object):
@@ -163,15 +119,16 @@
         'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
     }
 
-    def __init__(self, ui, repo, inc, exc):
+    def __init__(self, ui, repo):
         self.ui = ui
         self.repo = repo
-        self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1]
+        self.matcher = util.matcher(repo.root,
+                                    inc=kwtools['inc'], exc=kwtools['exc'])[1]
         self.restrict = kwtools['hgcmd'] in restricted.split()
 
         kwmaps = self.ui.configitems('keywordmaps')
         if kwmaps: # override default templates
-            kwmaps = [(k, templater.parsestring(v, quoted=False))
+            kwmaps = [(k, templater.parsestring(v, False))
                       for (k, v) in kwmaps]
             self.templates = dict(kwmaps)
         escaped = map(re.escape, self.templates.keys())
@@ -212,7 +169,7 @@
         Caveat: localrepository._link fails on Windows.'''
         return self.matcher(path) and not islink(path)
 
-    def overwrite(self, node=None, expand=True, files=None):
+    def overwrite(self, node, expand, files):
         '''Overwrites selected files expanding/shrinking keywords.'''
         ctx = self.repo.changectx(node)
         mf = ctx.manifest()
@@ -271,9 +228,9 @@
     Subclass of filelog to hook into its read, add, cmp methods.
     Keywords are "stored" unexpanded, and processed on reading.
     '''
-    def __init__(self, opener, path):
+    def __init__(self, opener, kwt, path):
         super(kwfilelog, self).__init__(opener, path)
-        self.kwt = kwtools['templater']
+        self.kwt = kwt
         self.path = path
 
     def read(self, node):
@@ -284,7 +241,7 @@
     def add(self, text, meta, tr, link, p1=None, p2=None):
         '''Removes keyword substitutions when adding to filelog.'''
         text = self.kwt.shrink(self.path, text)
-        return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2)
+        return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
 
     def cmp(self, node, text):
         '''Removes keyword substitutions for comparison.'''
@@ -315,7 +272,7 @@
     try:
         wlock = repo.wlock()
         lock = repo.lock()
-        kwt.overwrite(expand=expand, files=clean)
+        kwt.overwrite(None, expand, clean)
     finally:
         del wlock, lock
 
@@ -345,7 +302,7 @@
     branchname = 'demobranch'
     tmpdir = tempfile.mkdtemp('', 'kwdemo.')
     ui.note(_('creating temporary repo at %s\n') % tmpdir)
-    repo = localrepo.localrepository(ui, path=tmpdir, create=True)
+    repo = localrepo.localrepository(ui, tmpdir, True)
     ui.setconfig('keyword', fn, '')
     if args or opts.get('rcfile'):
         kwstatus = 'custom'
@@ -367,6 +324,7 @@
         ui.readconfig(repo.join('hgrc'))
     if not opts.get('default'):
         kwmaps = dict(ui.configitems('keywordmaps')) or kwtemplater.templates
+    uisetup(ui)
     reposetup(ui, repo)
     for k, v in ui.configitems('extensions'):
         if k.endswith('keyword'):
@@ -448,39 +406,50 @@
     _kwfwrite(ui, repo, False, *pats, **opts)
 
 
+def uisetup(ui):
+    '''Collects [keyword] config in kwtools.
+    Monkeypatches dispatch._parse if needed.'''
+
+    for pat, opt in ui.configitems('keyword'):
+        if opt != 'ignore':
+            kwtools['inc'].append(pat)
+        else:
+            kwtools['exc'].append(pat)
+
+    if kwtools['inc']:
+        def kwdispatch_parse(ui, args):
+            '''Monkeypatch dispatch._parse to obtain running hg command.'''
+            cmd, func, args, options, cmdoptions = dispatch_parse(ui, args)
+            kwtools['hgcmd'] = cmd
+            return cmd, func, args, options, cmdoptions
+
+        dispatch_parse = dispatch._parse
+        dispatch._parse = kwdispatch_parse
+
 def reposetup(ui, repo):
     '''Sets up repo as kwrepo for keyword substitution.
     Overrides file method to return kwfilelog instead of filelog
     if file matches user configuration.
     Wraps commit to overwrite configured files with updated
     keyword substitutions.
-    This is done for local repos only, and only if there are
-    files configured at all for keyword substitution.'''
+    Monkeypatches patch and webcommands.'''
 
     try:
-        if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
+        if (not repo.local() or not kwtools['inc']
+            or kwtools['hgcmd'] in nokwcommands.split()
             or '.hg' in util.splitpath(repo.root)
             or repo._url.startswith('bundle:')):
             return
     except AttributeError:
         pass
 
-    inc, exc = [], ['.hg*']
-    for pat, opt in ui.configitems('keyword'):
-        if opt != 'ignore':
-            inc.append(pat)
-        else:
-            exc.append(pat)
-    if not inc:
-        return
-
-    kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)
+    kwtools['templater'] = kwt = kwtemplater(ui, repo)
 
     class kwrepo(repo.__class__):
         def file(self, f):
             if f[0] == '/':
                 f = f[1:]
-            return kwfilelog(self.sopener, f)
+            return kwfilelog(self.sopener, kwt, f)
 
         def wread(self, filename):
             data = super(kwrepo, self).wread(filename)
@@ -512,28 +481,59 @@
                     else:
                         _p2 = hex(_p2)
 
-                node = super(kwrepo,
-                             self).commit(files=files, text=text, user=user,
-                                          date=date, match=match, force=force,
-                                          force_editor=force_editor,
-                                          p1=p1, p2=p2, extra=extra,
-                                          empty_ok=empty_ok)
+                n = super(kwrepo, self).commit(files, text, user, date, match,
+                                               force, force_editor, p1, p2,
+                                               extra, empty_ok)
 
                 # restore commit hooks
                 for name, cmd in commithooks.iteritems():
                     ui.setconfig('hooks', name, cmd)
-                if node is not None:
-                    kwt.overwrite(node=node)
-                    repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
-                return node
+                if n is not None:
+                    kwt.overwrite(n, True, None)
+                    repo.hook('commit', node=n, parent1=_p1, parent2=_p2)
+                return n
             finally:
                 del wlock, lock
 
+    # monkeypatches
+    def kwpatchfile_init(self, ui, fname, missing=False):
+        '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
+        rejects or conflicts due to expanded keywords in working dir.'''
+        patchfile_init(self, ui, fname, missing)
+        # shrink keywords read from working dir
+        self.lines = kwt.shrinklines(self.fname, self.lines)
+
+    def kw_diff(repo, node1=None, node2=None, files=None, match=util.always,
+                fp=None, changes=None, opts=None):
+        '''Monkeypatch patch.diff to avoid expansion except when
+        comparing against working dir.'''
+        if node2 is not None:
+            kwt.matcher = util.never
+        elif node1 is not None and node1 != repo.changectx().node():
+            kwt.restrict = True
+        patch_diff(repo, node1, node2, files, match, fp, changes, opts)
+
+    def kwweb_changeset(web, req, tmpl):
+        '''Wraps webcommands.changeset turning off keyword expansion.'''
+        kwt.matcher = util.never
+        return webcommands_changeset(web, req, tmpl)
+
+    def kwweb_filediff(web, req, tmpl):
+        '''Wraps webcommands.filediff turning off keyword expansion.'''
+        kwt.matcher = util.never
+        return webcommands_filediff(web, req, tmpl)
+
     repo.__class__ = kwrepo
-    patch.patchfile.__init__ = _kwpatchfile_init
-    patch.diff = _kw_diff
-    webcommands.changeset = webcommands.rev = _kwweb_changeset
-    webcommands.filediff = webcommands.diff = _kwweb_filediff
+
+    patchfile_init = patch.patchfile.__init__
+    patch_diff = patch.diff
+    webcommands_changeset = webcommands.changeset
+    webcommands_filediff = webcommands.filediff
+
+    patch.patchfile.__init__ = kwpatchfile_init
+    patch.diff = kw_diff
+    webcommands.changeset = webcommands.rev = kwweb_changeset
+    webcommands.filediff = webcommands.diff = kwweb_filediff
 
 
 cmdtable = {
--- a/hgext/mq.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/hgext/mq.py	Sat Apr 12 21:34:01 2008 +0200
@@ -662,14 +662,14 @@
         finally:
             del wlock
 
-    def strip(self, repo, rev, update=True, backup="all"):
+    def strip(self, repo, rev, update=True, backup="all", force=None):
         wlock = lock = None
         try:
             wlock = repo.wlock()
             lock = repo.lock()
 
             if update:
-                self.check_localchanges(repo, refresh=False)
+                self.check_localchanges(repo, force=force, refresh=False)
                 urev = self.qparents(repo, rev)
                 hg.clean(repo, urev)
                 repo.dirstate.write()
@@ -2043,7 +2043,7 @@
     elif opts['nobackup']:
         backup = 'none'
     update = repo.dirstate.parents()[0] != revlog.nullid
-    repo.mq.strip(repo, rev, backup=backup, update=update)
+    repo.mq.strip(repo, rev, backup=backup, update=update, force=opts['force'])
     return 0
 
 def select(ui, repo, *args, **opts):
@@ -2352,7 +2352,8 @@
          _('hg qseries [-ms]')),
     "^strip":
         (strip,
-         [('b', 'backup', None, _('bundle unrelated changesets')),
+         [('f', 'force', None, _('force removal with local changes')),
+          ('b', 'backup', None, _('bundle unrelated changesets')),
           ('n', 'nobackup', None, _('no backups'))],
          _('hg strip [-f] [-b] [-n] REV')),
     "qtop": (top, [] + seriesopts, _('hg qtop [-s]')),
--- a/hgext/pager.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/hgext/pager.py	Sat Apr 12 21:34:01 2008 +0200
@@ -10,26 +10,56 @@
 #   [extension]
 #   hgext.pager =
 #
-# To set the pager that should be used, set the application variable:
-#
-#   [pager]
-#   pager = LESS='FSRX' less
-#
-# If no pager is set, the pager extensions uses the environment
-# variable $PAGER. If neither pager.pager, nor $PAGER is set, no pager
-# is used.
-#
-# If you notice "BROKEN PIPE" error messages, you can disable them
-# by setting:
-#
-#   [pager]
-#   quiet = True
+# Run "hg help pager" to get info on configuration.
+
+'''browse command output with external pager
+
+To set the pager that should be used, set the application variable:
+
+  [pager]
+  pager = LESS='FSRX' less
+
+If no pager is set, the pager extensions uses the environment
+variable $PAGER. If neither pager.pager, nor $PAGER is set, no pager
+is used.
+
+If you notice "BROKEN PIPE" error messages, you can disable them
+by setting:
+
+  [pager]
+  quiet = True
+
+You can disable the pager for certain commands by adding them to the
+pager.ignore list:
+
+  [pager]
+  ignore = version, help, update
+
+You can also enable the pager only for certain commands using pager.attend:
+
+  [pager]
+  attend = log
+
+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
+'''
 
 import sys, os, signal
+from mercurial import dispatch
 
 def uisetup(ui):
-    p = ui.config("pager", "pager", os.environ.get("PAGER"))
-    if p and sys.stdout.isatty() and '--debugger' not in sys.argv:
-        if ui.configbool('pager', 'quiet'):
-            signal.signal(signal.SIGPIPE, signal.SIG_DFL)
-        sys.stderr = sys.stdout = os.popen(p, "wb")
+    def pagecmd(ui, options, cmd, cmdfunc):
+        p = ui.config("pager", "pager", os.environ.get("PAGER"))
+        if p and sys.stdout.isatty() and '--debugger' not in sys.argv:
+            attend = ui.configlist('pager', 'attend')
+            if (cmd in attend or
+                (cmd not in ui.configlist('pager', 'ignore') and not attend)):
+                sys.stderr = sys.stdout = os.popen(p, "wb")
+                if ui.configbool('pager', 'quiet'):
+                    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+        return oldrun(ui, options, cmd, cmdfunc)
+
+    oldrun = dispatch._runcommand
+    dispatch._runcommand = pagecmd
--- a/hgext/patchbomb.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/hgext/patchbomb.py	Sat Apr 12 21:34:01 2008 +0200
@@ -64,9 +64,9 @@
 #
 # That should be all.  Now your patchbomb is on its way out.
 
-import os, errno, socket, tempfile
+import os, errno, socket, tempfile, cStringIO
 import email.MIMEMultipart, email.MIMEText, email.MIMEBase
-import email.Utils, email.Encoders
+import email.Utils, email.Encoders, email.Generator
 from mercurial import cmdutil, commands, hg, mail, patch, util
 from mercurial.i18n import _
 from mercurial.node import bin
@@ -407,8 +407,9 @@
                 fp = os.popen(os.environ['PAGER'], 'w')
             else:
                 fp = ui
+            generator = email.Generator.Generator(fp, mangle_from_=False)
             try:
-                fp.write(m.as_string(0))
+                generator.flatten(m, 0)
                 fp.write('\n')
             except IOError, inst:
                 if inst.errno != errno.EPIPE:
@@ -418,9 +419,10 @@
         elif opts.get('mbox'):
             ui.status('Writing ', m['Subject'], ' ...\n')
             fp = open(opts.get('mbox'), 'In-Reply-To' in m and 'ab+' or 'wb+')
+            generator = email.Generator.Generator(fp, mangle_from_=True)
             date = util.datestr(start_time, '%a %b %d %H:%M:%S %Y')
             fp.write('From %s %s\n' % (sender_addr, date))
-            fp.write(m.as_string(0))
+            generator.flatten(m, 0)
             fp.write('\n\n')
             fp.close()
         else:
@@ -429,7 +431,10 @@
             ui.status('Sending ', m['Subject'], ' ...\n')
             # Exim does not remove the Bcc field
             del m['Bcc']
-            sendmail(sender, to + bcc + cc, m.as_string(0))
+            fp = cStringIO.StringIO()
+            generator = email.Generator.Generator(fp, mangle_from_=False)
+            generator.flatten(m, 0)
+            sendmail(sender, to + bcc + cc, fp.getvalue())
 
 cmdtable = {
     "email":
--- a/hgext/win32text.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/hgext/win32text.py	Sat Apr 12 21:34:01 2008 +0200
@@ -1,4 +1,4 @@
-# win32text.py - LF <-> CRLF translation utilities for Windows users
+# win32text.py - LF <-> CRLF/CR translation utilities for Windows/Mac users
 #
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
@@ -9,65 +9,94 @@
 # hgext.win32text =
 # [encode]
 # ** = cleverencode:
+# # or ** = macencode:
 # [decode]
 # ** = cleverdecode:
+# # or ** = macdecode:
 #
-# If not doing conversion, to make sure you do not commit CRLF by accident:
+# If not doing conversion, to make sure you do not commit CRLF/CR by accident:
 #
 # [hooks]
 # pretxncommit.crlf = python:hgext.win32text.forbidcrlf
+# # or pretxncommit.cr = python:hgext.win32text.forbidcr
 #
-# To do the same check on a server to prevent CRLF from being pushed or pulled:
+# To do the same check on a server to prevent CRLF/CR from being pushed or
+# pulled:
 #
 # [hooks]
 # pretxnchangegroup.crlf = python:hgext.win32text.forbidcrlf
+# # or pretxnchangegroup.cr = python:hgext.win32text.forbidcr
 
 from mercurial.i18n import gettext as _
 from mercurial.node import bin, short
+from mercurial import util
 import re
 
 # regexp for single LF without CR preceding.
 re_single_lf = re.compile('(^|[^\r])\n', re.MULTILINE)
 
-def dumbdecode(s, cmd, ui=None, repo=None, filename=None, **kwargs):
-    # warn if already has CRLF in repository.
+newlinestr = {'\r\n': 'CRLF', '\r': 'CR'}
+filterstr = {'\r\n': 'clever', '\r': 'mac'}
+
+def checknewline(s, newline, ui=None, repo=None, filename=None):
+    # warn if already has 'newline' in repository.
     # it might cause unexpected eol conversion.
     # see issue 302:
     #   http://www.selenic.com/mercurial/bts/issue302
-    if '\r\n' in s and ui and filename and repo:
-        ui.warn(_('WARNING: %s already has CRLF line endings\n'
+    if newline in s and ui and filename and repo:
+        ui.warn(_('WARNING: %s already has %s line endings\n'
                   'and does not need EOL conversion by the win32text plugin.\n'
                   'Before your next commit, please reconsider your '
                   'encode/decode settings in \nMercurial.ini or %s.\n') %
-                (filename, repo.join('hgrc')))
+                (filename, newlinestr[newline], repo.join('hgrc')))
+
+def dumbdecode(s, cmd, **kwargs):
+    checknewline(s, '\r\n', **kwargs)
     # replace single LF to CRLF
     return re_single_lf.sub('\\1\r\n', s)
 
 def dumbencode(s, cmd):
     return s.replace('\r\n', '\n')
 
-def clevertest(s, cmd):
-    if '\0' in s: return False
-    return True
+def macdumbdecode(s, cmd, **kwargs):
+    checknewline(s, '\r', **kwargs)
+    return s.replace('\n', '\r')
+
+def macdumbencode(s, cmd):
+    return s.replace('\r', '\n')
 
 def cleverdecode(s, cmd, **kwargs):
-    if clevertest(s, cmd):
+    if not util.binary(s):
         return dumbdecode(s, cmd, **kwargs)
     return s
 
 def cleverencode(s, cmd):
-    if clevertest(s, cmd):
+    if not util.binary(s):
         return dumbencode(s, cmd)
     return s
 
+def macdecode(s, cmd, **kwargs):
+    if not util.binary(s):
+        return macdumbdecode(s, cmd, **kwargs)
+    return s
+
+def macencode(s, cmd):
+    if not util.binary(s):
+        return macdumbencode(s, cmd)
+    return s
+
 _filters = {
     'dumbdecode:': dumbdecode,
     'dumbencode:': dumbencode,
     'cleverdecode:': cleverdecode,
     'cleverencode:': cleverencode,
+    'macdumbdecode:': macdumbdecode,
+    'macdumbencode:': macdumbencode,
+    'macdecode:': macdecode,
+    'macencode:': macencode,
     }
 
-def forbidcrlf(ui, repo, hooktype, node, **kwargs):
+def forbidnewline(ui, repo, hooktype, node, newline, **kwargs):
     halt = False
     for rev in xrange(repo.changelog.rev(bin(node)), repo.changelog.count()):
         c = repo.changectx(rev)
@@ -75,29 +104,38 @@
             if f not in c:
                 continue
             data = c[f].data()
-            if '\0' not in data and '\r\n' in data:
+            if not util.binary(data) and newline in data:
                 if not halt:
                     ui.warn(_('Attempt to commit or push text file(s) '
-                              'using CRLF line endings\n'))
+                              'using %s line endings\n') %
+                              newlinestr[newline])
                 ui.warn(_('in %s: %s\n') % (short(c.node()), f))
                 halt = True
     if halt and hooktype == 'pretxnchangegroup':
+        crlf = newlinestr[newline].lower()
+        filter = filterstr[newline]
         ui.warn(_('\nTo prevent this mistake in your local repository,\n'
                   'add to Mercurial.ini or .hg/hgrc:\n'
                   '\n'
                   '[hooks]\n'
-                  'pretxncommit.crlf = python:hgext.win32text.forbidcrlf\n'
+                  'pretxncommit.%s = python:hgext.win32text.forbid%s\n'
                   '\n'
                   'and also consider adding:\n'
                   '\n'
                   '[extensions]\n'
                   'hgext.win32text =\n'
                   '[encode]\n'
-                  '** = cleverencode:\n'
+                  '** = %sencode:\n'
                   '[decode]\n'
-                  '** = cleverdecode:\n'))
+                  '** = %sdecode:\n') % (crlf, crlf, filter, filter))
     return halt
 
+def forbidcrlf(ui, repo, hooktype, node, **kwargs):
+    return forbidnewline(ui, repo, hooktype, node, '\r\n', **kwargs)
+
+def forbidcr(ui, repo, hooktype, node, **kwargs):
+    return forbidnewline(ui, repo, hooktype, node, '\r', **kwargs)
+
 def reposetup(ui, repo):
     if not repo.local():
         return
--- a/mercurial/archival.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/archival.py	Sat Apr 12 21:34:01 2008 +0200
@@ -52,7 +52,8 @@
         def _write_gzip_header(self):
             self.fileobj.write('\037\213')             # magic header
             self.fileobj.write('\010')                 # compression method
-            fname = self.filename[:-3]
+            # Python 2.6 deprecates self.filename
+            fname = getattr(self, 'name', None) or self.filename
             flags = 0
             if fname:
                 flags = gzip.FNAME
--- a/mercurial/commands.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/commands.py	Sat Apr 12 21:34:01 2008 +0200
@@ -13,6 +13,7 @@
 import difflib, patch, time, help, mdiff, tempfile
 import version, socket
 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
+import merge as merge_
 
 # Commands start here, listed alphabetically
 
@@ -53,11 +54,11 @@
     New files are ignored if they match any of the patterns in .hgignore. As
     with add, these changes take effect at the next commit.
 
-    Use the -s option to detect renamed files.  With a parameter > 0,
+    Use the -s option to detect renamed files. With a parameter > 0,
     this compares every removed file with every added file and records
-    those similar enough as renames.  This option takes a percentage
+    those similar enough as renames. This option takes a percentage
     between 0 (disabled) and 100 (files must be identical) as its
-    parameter.  Detecting renamed files this way can be expensive.
+    parameter. Detecting renamed files this way can be expensive.
     """
     try:
         sim = float(opts.get('similarity') or 0)
@@ -134,7 +135,7 @@
     By default, the revision used is the parent of the working
     directory; use "-r" to specify a different revision.
 
-    To specify the type of archive to create, use "-t".  Valid
+    To specify the type of archive to create, use "-t". Valid
     types are:
 
     "files" (default): a directory full of files
@@ -148,7 +149,7 @@
     using a format string; see "hg help export" for details.
 
     Each member added to an archive file has a directory prefix
-    prepended.  Use "-p" to specify a format string for the prefix.
+    prepended. Use "-p" to specify a format string for the prefix.
     The default is the basename of the archive, with suffixes removed.
     '''
 
@@ -174,17 +175,17 @@
 def backout(ui, repo, node=None, rev=None, **opts):
     '''reverse effect of earlier changeset
 
-    Commit the backed out changes as a new changeset.  The new
+    Commit the backed out changes as a new changeset. The new
     changeset is a child of the backed out changeset.
 
     If you back out a changeset other than the tip, a new head is
-    created.  This head will be the new tip and you should merge this
+    created. This head will be the new tip and you should merge this
     backout changeset with another head (current one by default).
 
     The --merge option remembers the parent of the working directory
     before starting the backout, then merges the new head with that
-    changeset afterwards.  This saves you from doing the merge by
-    hand.  The result of this merge is not committed, as for a normal
+    changeset afterwards. This saves you from doing the merge by
+    hand. The result of this merge is not committed, as for a normal
     merge.
 
     See 'hg help dates' for a list of formats valid for -d/--date.
@@ -369,7 +370,7 @@
     """list repository named branches
 
     List the repository's named branches, indicating which ones are
-    inactive.  If active is specified, only show active branches.
+    inactive. If active is specified, only show active branches.
 
     A branch is considered active if it contains unmerged heads.
 
@@ -404,7 +405,7 @@
 
     If no destination repository is specified the destination is
     assumed to have all the nodes specified by one or more --base
-    parameters.  To create a bundle containing all changesets, use
+    parameters. To create a bundle containing all changesets, use
     --all (or --base null).
 
     The bundle file can then be transferred using conventional means and
@@ -469,7 +470,7 @@
     or tip if no revision is checked out.
 
     Output may be to a file, in which case the name of the file is
-    given using a format string.  The formatting rules are the same as
+    given using a format string. The formatting rules are the same as
     for the export command, with the following additions:
 
     %s   basename of file being printed
@@ -501,20 +502,22 @@
 
     For efficiency, hardlinks are used for cloning whenever the source
     and destination are on the same filesystem (note this applies only
-    to the repository data, not to the checked out files).  Some
+    to the repository data, not to the checked out files). Some
     filesystems, such as AFS, implement hardlinking incorrectly, but
-    do not report errors.  In these cases, use the --pull option to
+    do not report errors. In these cases, use the --pull option to
     avoid hardlinking.
 
-    You can safely clone repositories and checked out files using full
-    hardlinks with
+    In some cases, you can clone repositories and checked out files
+    using full hardlinks with
 
       $ cp -al REPO REPOCLONE
 
-    which is the fastest way to clone. However, the operation is not
-    atomic (making sure REPO is not modified during the operation is
-    up to you) and you have to make sure your editor breaks hardlinks
-    (Emacs and most Linux Kernel tools do so).
+    This is the fastest way to clone, but it is not always safe.  The
+    operation is not atomic (making sure REPO is not modified during
+    the operation is up to you) and you have to make sure your editor
+    breaks hardlinks (Emacs and most Linux Kernel tools do so).  Also,
+    this is not compatible with certain extensions that place their
+    metadata under the .hg directory, such as mq.
 
     If you use the -r option to clone up to a specific revision, no
     subsequent revisions will be present in the cloned repository.
@@ -571,12 +574,12 @@
 def copy(ui, repo, *pats, **opts):
     """mark files as copied for the next commit
 
-    Mark dest as having copies of source files.  If dest is a
-    directory, copies are put in that directory.  If dest is a file,
+    Mark dest as having copies of source files. If dest is a
+    directory, copies are put in that directory. If dest is a file,
     there can only be one source.
 
     By default, this command copies the contents of files as they
-    stand in the working directory.  If invoked with --after, the
+    stand in the working directory. If invoked with --after, the
     operation is recorded, but no copying is performed.
 
     This command takes effect in the next commit. To undo a copy
@@ -963,7 +966,7 @@
     as it will compare the merge changeset against its first parent only.
 
     Output may be to a file, in which case the name of the file is
-    given using a format string.  The formatting rules are as follows:
+    given using a format string. The formatting rules are as follows:
 
     %%   literal "%" character
     %H   changeset hash (40 bytes of hexadecimal)
@@ -997,13 +1000,13 @@
 
     Search revisions of files for a regular expression.
 
-    This command behaves differently than Unix grep.  It only accepts
-    Python/Perl regexps.  It searches repository history, not the
-    working directory.  It always prints the revision number in which
+    This command behaves differently than Unix grep. It only accepts
+    Python/Perl regexps. It searches repository history, not the
+    working directory. It always prints the revision number in which
     a match appears.
 
     By default, grep only prints output for the first revision of a
-    file in which it finds a match.  To get it to print every revision
+    file in which it finds a match. To get it to print every revision
     that contains a change in match status ("-" for a match that
     becomes a non-match, or "+" for a non-match that becomes a match),
     use the --all flag.
@@ -1047,6 +1050,9 @@
             self.colstart = colstart
             self.colend = colend
 
+        def __hash__(self):
+            return hash((self.linenum, self.line))
+
         def __eq__(self, other):
             return self.line == other.line
 
@@ -1173,7 +1179,7 @@
     are the usual targets for update and merge operations.
 
     Branch heads are changesets that have a given branch tag, but have
-    no child changesets with that tag.  They are usually where
+    no child changesets with that tag. They are usually where
     development on the given branch takes place.
     """
     if opts['rev']:
@@ -1466,15 +1472,15 @@
     If there are outstanding changes in the working directory, import
     will abort unless given the -f flag.
 
-    You can import a patch straight from a mail message.  Even patches
+    You can import a patch straight from a mail message. Even patches
     as attachments work (body part must be type text/plain or
-    text/x-patch to be used).  From and Subject headers of email
-    message are used as default committer and commit message.  All
+    text/x-patch to be used). From and Subject headers of email
+    message are used as default committer and commit message. All
     text/plain body parts before first diff are added to commit
     message.
 
     If the imported patch was generated by hg export, user and description
-    from patch override values from message headers and body.  Values
+    from patch override values from message headers and body. Values
     given on command line with -m and -u override these.
 
     If --exact is specified, import will set the working directory
@@ -1643,7 +1649,7 @@
 def init(ui, dest=".", **opts):
     """create a new repository in the given directory
 
-    Initialize a new repository in the given directory.  If the given
+    Initialize a new repository in the given directory. If the given
     directory does not exist, it is created.
 
     If no directory is given, the current directory is used.
@@ -1661,7 +1667,7 @@
     Print all files under Mercurial control whose names match the
     given patterns.
 
-    This command searches the entire repository by default.  To search
+    This command searches the entire repository by default. To search
     just the current directory and its subdirectories, use
     "--include .".
 
@@ -1703,7 +1709,7 @@
     project.
 
     File history is shown without following rename or copy history of
-    files.  Use -f/--follow with a file name to follow history across
+    files. Use -f/--follow with a file name to follow history across
     renames and copies. --follow without a file name will only show
     ancestors or descendants of the starting revision. --follow-first
     only follows the first parent of merge revisions.
@@ -1862,7 +1868,7 @@
 
     If no revision is specified, the working directory's parent is a
     head revision, and the repository contains exactly one other head,
-    the other head is merged with by default.  Otherwise, an explicit
+    the other head is merged with by default. Otherwise, an explicit
     revision to merge with must be provided.
     """
 
@@ -1973,7 +1979,7 @@
     definition of available names.
 
     Path names are defined in the [paths] section of /etc/mercurial/hgrc
-    and $HOME/.hgrc.  If run inside a repository, .hg/hgrc is used, too.
+    and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
     """
     if search:
         for name, path in ui.configitems("paths"):
@@ -2214,12 +2220,12 @@
 def rename(ui, repo, *pats, **opts):
     """rename files; equivalent of copy + remove
 
-    Mark dest as copies of sources; mark sources for deletion.  If
-    dest is a directory, copies are put in that directory.  If dest is
+    Mark dest as copies of sources; mark sources for deletion. If
+    dest is a directory, copies are put in that directory. If dest is
     a file, there can only be one source.
 
     By default, this command copies the contents of files as they
-    stand in the working directory.  If invoked with --after, the
+    stand in the working directory. If invoked with --after, the
     operation is recorded, but no copying is performed.
 
     This command takes effect in the next commit. To undo a rename
@@ -2231,6 +2237,35 @@
     finally:
         del wlock
 
+def resolve(ui, repo, *pats, **opts):
+    """resolve file merges from a branch merge or update
+
+    This command will attempt to resolve unresolved merges from the
+    last update or merge command. This will use the local file
+    revision preserved at the last update or merge to cleanly retry
+    the file merge attempt. With no file or options specified, this
+    command will attempt to resolve all unresolved files.
+    """
+
+    if len([x for x in opts if opts[x]]) > 1:
+        raise util.Abort(_("too many options specified"))
+
+    ms = merge_.mergestate(repo)
+    mf = util.matcher(repo.root, "", pats, [], [])[1]
+
+    for f in ms:
+        if mf(f):
+            if opts.get("list"):
+                ui.write("%s %s\n" % (ms[f].upper(), f))
+            elif opts.get("mark"):
+                ms.mark(f, "r")
+            elif opts.get("unmark"):
+                ms.mark(f, "u")
+            else:
+                wctx = repo.workingctx()
+                mctx = wctx.parents()[-1]
+                ms.resolve(f, wctx, mctx)
+
 def revert(ui, repo, *pats, **opts):
     """restore individual files or dirs to an earlier state
 
@@ -2249,13 +2284,13 @@
     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
+    Revert modifies the working directory. It does not commit any
+    changes, or change the parent of the working directory. If you
     revert to a revision other than the parent of the working
     directory, the reverted files will thus appear modified
     afterwards.
 
-    If a file has been deleted, it is restored.  If the executable
+    If a file has been deleted, it is restored. If the executable
     mode of a file was changed, it is reset.
 
     If names are given, all files matching the names are reverted.
@@ -2491,7 +2526,7 @@
     Start a local HTTP repository browser and pull server.
 
     By default, the server logs accesses to stdout and errors to
-    stderr.  Use the "-A" and "-E" options to log to files.
+    stderr. Use the "-A" and "-E" options to log to files.
     """
 
     if opts["stdio"]:
@@ -2530,8 +2565,17 @@
             if port == ':80':
                 port = ''
 
-            ui.status(_('listening at http://%s%s/%s (%s:%d)\n') %
-                      (self.httpd.fqaddr, port, prefix, self.httpd.addr, self.httpd.port))
+            bindaddr = self.httpd.addr
+            if bindaddr == '0.0.0.0':
+                bindaddr = '*'
+            elif ':' in bindaddr: # IPv6
+                bindaddr = '[%s]' % bindaddr
+
+            fqaddr = self.httpd.fqaddr
+            if ':' in fqaddr:
+                fqaddr = '[%s]' % fqaddr
+            ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
+                      (fqaddr, port, prefix, bindaddr, self.httpd.port))
 
         def run(self):
             self.httpd.serve_forever()
@@ -2543,10 +2587,10 @@
 def status(ui, repo, *pats, **opts):
     """show changed files in the working directory
 
-    Show status of files in the repository.  If names are given, only
-    files that match are shown.  Files that are clean or ignored or
+    Show status of files in the repository. If names are given, only
+    files that match are shown. Files that are clean or ignored or
     source of a copy/move operation, are not listed unless -c (clean),
-    -i (ignored), -C (copies) or -A is given.  Unless options described
+    -i (ignored), -C (copies) or -A is given. Unless options described
     with "show only ..." are given, the options -mardu are used.
 
     Option -q/--quiet hides untracked (unknown and ignored) files
@@ -2646,7 +2690,7 @@
     To facilitate version control, distribution, and merging of tags,
     they are stored as a file named ".hgtags" which is managed
     similarly to other project files and can be hand-edited if
-    necessary.  The file '.hg/localtags' is used for local tags (not
+    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.
@@ -3182,6 +3226,12 @@
            _('forcibly copy over an existing managed file')),
          ] + walkopts + dryrunopts,
          _('hg rename [OPTION]... SOURCE... DEST')),
+    "resolve":
+        (resolve,
+         [('l', 'list', None, _('list state of files needing merge')),
+          ('m', 'mark', None, _('mark files as resolved')),
+          ('u', 'unmark', None, _('unmark files as resolved'))],
+          ('hg resolve [OPTION] [FILES...]')),
     "revert":
         (revert,
          [('a', 'all', None, _('revert all changes when no arguments given')),
--- a/mercurial/context.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/context.py	Sat Apr 12 21:34:01 2008 +0200
@@ -34,6 +34,12 @@
     def __repr__(self):
         return "<changectx %s>" % str(self)
 
+    def __hash__(self):
+        try:
+            return hash(self._rev)
+        except AttributeError:
+            return id(self)
+
     def __eq__(self, other):
         try:
             return self._rev == other._rev
@@ -210,6 +216,12 @@
     def __repr__(self):
         return "<filectx %s>" % str(self)
 
+    def __hash__(self):
+        try:
+            return hash((self._path, self._fileid))
+        except AttributeError:
+            return id(self)
+
     def __eq__(self, other):
         try:
             return (self._path == other._path
--- a/mercurial/filemerge.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/filemerge.py	Sat Apr 12 21:34:01 2008 +0200
@@ -5,7 +5,7 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-from node import nullrev
+from node import nullrev, short
 from i18n import _
 import util, os, tempfile, simplemerge, re, filecmp
 
@@ -99,13 +99,14 @@
             if newdata != data:
                 open(file, "wb").write(newdata)
 
-def filemerge(repo, fw, fd, fo, wctx, mctx):
+def filemerge(repo, mynode, orig, fcd, fco, fca):
     """perform a 3-way merge in the working directory
 
-    fw = original filename in the working directory
-    fd = destination filename in the working directory
-    fo = filename in other parent
-    wctx, mctx = working and merge changecontexts
+    mynode = parent node before merge
+    orig = original local filename before merge
+    fco = other file context
+    fca = ancestor file context
+    fcd = local file context for current/destination file
     """
 
     def temp(prefix, ctx):
@@ -123,23 +124,21 @@
         except IOError:
             return False
 
-    fco = mctx.filectx(fo)
-    if not fco.cmp(wctx.filectx(fd).data()): # files identical?
+    if not fco.cmp(fcd.data()): # files identical?
         return None
 
     ui = repo.ui
-    fcm = wctx.filectx(fw)
-    fca = fcm.ancestor(fco) or repo.filectx(fw, fileid=nullrev)
-    binary = isbin(fcm) or isbin(fco) or isbin(fca)
-    symlink = fcm.islink() or fco.islink()
-    tool, toolpath = _picktool(repo, ui, fw, binary, symlink)
+    fd = fcd.path()
+    binary = isbin(fcd) or isbin(fco) or isbin(fca)
+    symlink = fcd.islink() or fco.islink()
+    tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
     ui.debug(_("picked tool '%s' for %s (binary %s symlink %s)\n") %
-               (tool, fw, binary, symlink))
+               (tool, fd, binary, symlink))
 
     if not tool:
         tool = "internal:local"
         if ui.prompt(_(" no tool found to merge %s\n"
-                       "keep (l)ocal or take (o)ther?") % fw,
+                       "keep (l)ocal or take (o)ther?") % fd,
                      _("[lo]"), _("l")) != _("l"):
             tool = "internal:other"
     if tool == "internal:local":
@@ -158,11 +157,12 @@
     back = a + ".orig"
     util.copyfile(a, back)
 
-    if fw != fo:
-        repo.ui.status(_("merging %s and %s\n") % (fw, fo))
+    if orig != fco.path():
+        repo.ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
     else:
-        repo.ui.status(_("merging %s\n") % fw)
-    repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcm, fco, fca))
+        repo.ui.status(_("merging %s\n") % fd)
+
+    repo.ui.debug(_("my %s other %s ancestor %s\n") % (fcd, fco, fca))
 
     # do we attempt to simplemerge first?
     if _toolbool(ui, tool, "premerge", not (binary or symlink)):
@@ -176,9 +176,9 @@
         util.copyfile(back, a) # restore from backup and try again
 
     env = dict(HG_FILE=fd,
-               HG_MY_NODE=str(wctx.parents()[0]),
-               HG_OTHER_NODE=str(mctx),
-               HG_MY_ISLINK=fcm.islink(),
+               HG_MY_NODE=short(mynode),
+               HG_OTHER_NODE=str(fco.changectx()),
+               HG_MY_ISLINK=fcd.islink(),
                HG_OTHER_ISLINK=fco.islink(),
                HG_BASE_ISLINK=fca.islink())
 
@@ -194,7 +194,7 @@
         r = util.system(toolpath + ' ' + args, cwd=repo.root, environ=env)
 
     if not r and _toolbool(ui, tool, "checkconflicts"):
-        if re.match("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcm.data()):
+        if re.match("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data()):
             r = 1
 
     if not r and _toolbool(ui, tool, "checkchanged"):
--- a/mercurial/hg.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/hg.py	Sat Apr 12 21:34:01 2008 +0200
@@ -16,7 +16,7 @@
     return (os.path.isfile(util.drop_scheme('file', path)) and
             bundlerepo or localrepo)
 
-def parseurl(url, revs):
+def parseurl(url, revs=[]):
     '''parse url#branch, returning url, branch + revs'''
 
     if '#' not in url:
@@ -69,6 +69,15 @@
     '''return default destination of clone if none is given'''
     return os.path.basename(os.path.normpath(source))
 
+def localpath(path):
+    if path.startswith('file://localhost/'):
+        return path[16:]
+    if path.startswith('file://'):
+        return path[7:]
+    if path.startswith('file:'):
+        return path[5:]
+    return path
+
 def clone(ui, source, dest=None, pull=False, rev=None, update=True,
           stream=False):
     """Make a copy of an existing repository.
@@ -100,7 +109,8 @@
     rev: revision to clone up to (implies pull=True)
 
     update: update working directory after clone completes, if
-    destination is local repository
+    destination is local repository (True means update to default rev,
+    anything else is treated as a revision)
     """
 
     if isinstance(source, str):
@@ -116,15 +126,6 @@
         dest = defaultdest(source)
         ui.status(_("destination directory: %s\n") % dest)
 
-    def localpath(path):
-        if path.startswith('file://localhost/'):
-            return path[16:]
-        if path.startswith('file://'):
-            return path[7:]
-        if path.startswith('file:'):
-            return path[5:]
-        return path
-
     dest = localpath(dest)
     source = localpath(source)
 
@@ -244,7 +245,9 @@
 
             if update:
                 dest_repo.ui.status(_("updating working directory\n"))
-                if not checkout:
+                if update is not True:
+                    checkout = update
+                elif not checkout:
                     try:
                         checkout = dest_repo.lookup("default")
                     except:
@@ -271,15 +274,7 @@
     stats = _merge.update(repo, node, False, False, None)
     _showstats(repo, stats)
     if stats[3]:
-        repo.ui.status(_("There are unresolved merges with"
-                         " locally modified files.\n"))
-        if stats[1]:
-            repo.ui.status(_("You can finish the partial merge using:\n"))
-        else:
-            repo.ui.status(_("You can redo the full merge using:\n"))
-        # len(pl)==1, otherwise _merge.update() would have raised util.Abort:
-        repo.ui.status(_("  hg update %s\n  hg update %s\n")
-                       % (pl[0].rev(), repo.changectx(node).rev()))
+        repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
     return stats[3] > 0
 
 def clean(repo, node, show_stats=True):
@@ -294,11 +289,7 @@
     _showstats(repo, stats)
     if stats[3]:
         pl = repo.parents()
-        repo.ui.status(_("There are unresolved merges,"
-                         " you can redo the full merge using:\n"
-                         "  hg update -C %s\n"
-                         "  hg merge %s\n")
-                       % (pl[0].rev(), pl[1].rev()))
+        repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
     elif remind:
         repo.ui.status(_("(branch merge, don't forget to commit)\n"))
     return stats[3] > 0
--- a/mercurial/hgweb/hgweb_mod.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/hgweb/hgweb_mod.py	Sat Apr 12 21:34:01 2008 +0200
@@ -6,16 +6,15 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import os, mimetypes, re, mimetools, cStringIO
-from mercurial.node import hex, nullid, short
+import os, mimetypes
+from mercurial.node import hex, nullid
 from mercurial.repo import RepoError
-from mercurial import mdiff, ui, hg, util, archival, patch, hook
+from mercurial import mdiff, ui, hg, util, patch, hook
 from mercurial import revlog, templater, templatefilters, changegroup
-from common import get_mtime, style_map, paritygen, countgen, get_contact
-from common import ErrorResponse
+from common import get_mtime, style_map, paritygen, countgen, ErrorResponse
 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
 from request import wsgirequest
-import webcommands, protocol
+import webcommands, protocol, webutil
 
 shortcuts = {
     'cl': [('cmd', ['changelog']), ('rev', None)],
@@ -32,54 +31,6 @@
     'static': [('cmd', ['static']), ('file', None)]
 }
 
-def _up(p):
-    if p[0] != "/":
-        p = "/" + p
-    if p[-1] == "/":
-        p = p[:-1]
-    up = os.path.dirname(p)
-    if up == "/":
-        return "/"
-    return up + "/"
-
-def revnavgen(pos, pagelen, limit, nodefunc):
-    def seq(factor, limit=None):
-        if limit:
-            yield limit
-            if limit >= 20 and limit <= 40:
-                yield 50
-        else:
-            yield 1 * factor
-            yield 3 * factor
-        for f in seq(factor * 10):
-            yield f
-
-    def nav(**map):
-        l = []
-        last = 0
-        for f in seq(1, pagelen):
-            if f < pagelen or f <= last:
-                continue
-            if f > limit:
-                break
-            last = f
-            if pos + f < limit:
-                l.append(("+%d" % f, hex(nodefunc(pos + f).node())))
-            if pos - f >= 0:
-                l.insert(0, ("-%d" % f, hex(nodefunc(pos - f).node())))
-
-        try:
-            yield {"label": "(0)", "node": hex(nodefunc('0').node())}
-
-            for label, node in l:
-                yield {"label": label, "node": node}
-
-            yield {"label": "tip", "node": "tip"}
-        except RepoError:
-            pass
-
-    return nav
-
 class hgweb(object):
     def __init__(self, repo, name=None):
         if isinstance(repo, str):
@@ -226,17 +177,8 @@
         try:
 
             tmpl = self.templater(req)
-            try:
-                ctype = tmpl('mimetype', encoding=self.encoding)
-                ctype = templater.stringify(ctype)
-            except KeyError:
-                # old templates with inline HTTP headers?
-                if 'mimetype' in tmpl:
-                    raise
-                header = tmpl('header', encoding=self.encoding)
-                header_file = cStringIO.StringIO(templater.stringify(header))
-                msg = mimetools.Message(header_file, 0)
-                ctype = msg['content-type']
+            ctype = tmpl('mimetype', encoding=self.encoding)
+            ctype = templater.stringify(ctype)
 
             if cmd == '':
                 req.form['cmd'] = [tmpl.cache['default']]
@@ -291,13 +233,7 @@
         # some functions for the templater
 
         def header(**map):
-            header = tmpl('header', encoding=self.encoding, **map)
-            if 'mimetype' not in tmpl:
-                # old template with inline HTTP headers
-                header_file = cStringIO.StringIO(templater.stringify(header))
-                msg = mimetools.Message(header_file, 0)
-                header = header_file.read()
-            yield header
+            yield tmpl('header', encoding=self.encoding, **map)
 
         def footer(**map):
             yield tmpl("footer", **map)
@@ -355,54 +291,6 @@
         if len(files) > self.maxfiles:
             yield tmpl("fileellipses")
 
-    def siblings(self, siblings=[], hiderev=None, **args):
-        siblings = [s for s in siblings if s.node() != nullid]
-        if len(siblings) == 1 and siblings[0].rev() == hiderev:
-            return
-        for s in siblings:
-            d = {'node': hex(s.node()), 'rev': s.rev()}
-            if hasattr(s, 'path'):
-                d['file'] = s.path()
-            d.update(args)
-            yield d
-
-    def renamelink(self, fl, node):
-        r = fl.renamed(node)
-        if r:
-            return [dict(file=r[0], node=hex(r[1]))]
-        return []
-
-    def nodetagsdict(self, node):
-        return [{"name": i} for i in self.repo.nodetags(node)]
-
-    def nodebranchdict(self, ctx):
-        branches = []
-        branch = ctx.branch()
-        # If this is an empty repo, ctx.node() == nullid,
-        # ctx.branch() == 'default', but branchtags() is
-        # an empty dict. Using dict.get avoids a traceback.
-        if self.repo.branchtags().get(branch) == ctx.node():
-            branches.append({"name": branch})
-        return branches
-
-    def nodeinbranch(self, ctx):
-        branches = []
-        branch = ctx.branch()
-        if branch != 'default' and self.repo.branchtags().get(branch) != ctx.node():
-            branches.append({"name": branch})
-        return branches
-
-    def nodebranchnodefault(self, ctx):
-        branches = []
-        branch = ctx.branch()
-        if branch != 'default':
-            branches.append({"name": branch})
-        return branches
-
-    def showtag(self, tmpl, t1, node=nullid, **args):
-        for t in self.repo.nodetags(node):
-            yield tmpl(t1, tag=t, **args)
-
     def diff(self, tmpl, node1, node2, files):
         def filterfiles(filters, files):
             l = [x for x in files if x in filters]
@@ -470,514 +358,12 @@
             yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, f,
                                           opts=diffopts), f, tn)
 
-    def changelog(self, tmpl, ctx, shortlog=False):
-        def changelist(limit=0,**map):
-            cl = self.repo.changelog
-            l = [] # build a list in forward order for efficiency
-            for i in xrange(start, end):
-                ctx = self.repo.changectx(i)
-                n = ctx.node()
-                showtags = self.showtag(tmpl, 'changelogtag', n)
-
-                l.insert(0, {"parity": parity.next(),
-                             "author": ctx.user(),
-                             "parent": self.siblings(ctx.parents(), i - 1),
-                             "child": self.siblings(ctx.children(), i + 1),
-                             "changelogtag": showtags,
-                             "desc": ctx.description(),
-                             "date": ctx.date(),
-                             "files": self.listfilediffs(tmpl, ctx.files(), n),
-                             "rev": i,
-                             "node": hex(n),
-                             "tags": self.nodetagsdict(n),
-                             "inbranch": self.nodeinbranch(ctx),
-                             "branches": self.nodebranchdict(ctx)})
-
-            if limit > 0:
-                l = l[:limit]
-
-            for e in l:
-                yield e
-
-        maxchanges = shortlog and self.maxshortchanges or self.maxchanges
-        cl = self.repo.changelog
-        count = cl.count()
-        pos = ctx.rev()
-        start = max(0, pos - maxchanges + 1)
-        end = min(count, start + maxchanges)
-        pos = end - 1
-        parity = paritygen(self.stripecount, offset=start-end)
-
-        changenav = revnavgen(pos, maxchanges, count, self.repo.changectx)
-
-        return tmpl(shortlog and 'shortlog' or 'changelog',
-                    changenav=changenav,
-                    node=hex(cl.tip()),
-                    rev=pos, changesets=count,
-                    entries=lambda **x: changelist(limit=0,**x),
-                    latestentry=lambda **x: changelist(limit=1,**x),
-                    archives=self.archivelist("tip"))
-
-    def search(self, tmpl, query):
-
-        def changelist(**map):
-            cl = self.repo.changelog
-            count = 0
-            qw = query.lower().split()
-
-            def revgen():
-                for i in xrange(cl.count() - 1, 0, -100):
-                    l = []
-                    for j in xrange(max(0, i - 100), i + 1):
-                        ctx = self.repo.changectx(j)
-                        l.append(ctx)
-                    l.reverse()
-                    for e in l:
-                        yield e
-
-            for ctx in revgen():
-                miss = 0
-                for q in qw:
-                    if not (q in ctx.user().lower() or
-                            q in ctx.description().lower() or
-                            q in " ".join(ctx.files()).lower()):
-                        miss = 1
-                        break
-                if miss:
-                    continue
-
-                count += 1
-                n = ctx.node()
-                showtags = self.showtag(tmpl, 'changelogtag', n)
-
-                yield tmpl('searchentry',
-                           parity=parity.next(),
-                           author=ctx.user(),
-                           parent=self.siblings(ctx.parents()),
-                           child=self.siblings(ctx.children()),
-                           changelogtag=showtags,
-                           desc=ctx.description(),
-                           date=ctx.date(),
-                           files=self.listfilediffs(tmpl, ctx.files(), n),
-                           rev=ctx.rev(),
-                           node=hex(n),
-                           tags=self.nodetagsdict(n),
-                           inbranch=self.nodeinbranch(ctx),
-                           branches=self.nodebranchdict(ctx))
-
-                if count >= self.maxchanges:
-                    break
-
-        cl = self.repo.changelog
-        parity = paritygen(self.stripecount)
-
-        return tmpl('search',
-                    query=query,
-                    node=hex(cl.tip()),
-                    entries=changelist,
-                    archives=self.archivelist("tip"))
-
-    def changeset(self, tmpl, ctx):
-        n = ctx.node()
-        showtags = self.showtag(tmpl, 'changesettag', n)
-        parents = ctx.parents()
-        p1 = parents[0].node()
-
-        files = []
-        parity = paritygen(self.stripecount)
-        for f in ctx.files():
-            files.append(tmpl("filenodelink",
-                              node=hex(n), file=f,
-                              parity=parity.next()))
-
-        def diff(**map):
-            yield self.diff(tmpl, p1, n, None)
-
-        return tmpl('changeset',
-                    diff=diff,
-                    rev=ctx.rev(),
-                    node=hex(n),
-                    parent=self.siblings(parents),
-                    child=self.siblings(ctx.children()),
-                    changesettag=showtags,
-                    author=ctx.user(),
-                    desc=ctx.description(),
-                    date=ctx.date(),
-                    files=files,
-                    archives=self.archivelist(hex(n)),
-                    tags=self.nodetagsdict(n),
-                    branch=self.nodebranchnodefault(ctx),
-                    inbranch=self.nodeinbranch(ctx),
-                    branches=self.nodebranchdict(ctx))
-
-    def filelog(self, tmpl, fctx):
-        f = fctx.path()
-        fl = fctx.filelog()
-        count = fl.count()
-        pagelen = self.maxshortchanges
-        pos = fctx.filerev()
-        start = max(0, pos - pagelen + 1)
-        end = min(count, start + pagelen)
-        pos = end - 1
-        parity = paritygen(self.stripecount, offset=start-end)
-
-        def entries(limit=0, **map):
-            l = []
-
-            for i in xrange(start, end):
-                ctx = fctx.filectx(i)
-                n = fl.node(i)
-
-                l.insert(0, {"parity": parity.next(),
-                             "filerev": i,
-                             "file": f,
-                             "node": hex(ctx.node()),
-                             "author": ctx.user(),
-                             "date": ctx.date(),
-                             "rename": self.renamelink(fl, n),
-                             "parent": self.siblings(fctx.parents()),
-                             "child": self.siblings(fctx.children()),
-                             "desc": ctx.description()})
-
-            if limit > 0:
-                l = l[:limit]
-
-            for e in l:
-                yield e
-
-        nodefunc = lambda x: fctx.filectx(fileid=x)
-        nav = revnavgen(pos, pagelen, count, nodefunc)
-        return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav,
-                    entries=lambda **x: entries(limit=0, **x),
-                    latestentry=lambda **x: entries(limit=1, **x))
-
-    def filerevision(self, tmpl, fctx):
-        f = fctx.path()
-        text = fctx.data()
-        fl = fctx.filelog()
-        n = fctx.filenode()
-        parity = paritygen(self.stripecount)
-
-        if util.binary(text):
-            mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
-            text = '(binary:%s)' % mt
-
-        def lines():
-            for lineno, t in enumerate(text.splitlines(1)):
-                yield {"line": t,
-                       "lineid": "l%d" % (lineno + 1),
-                       "linenumber": "% 6d" % (lineno + 1),
-                       "parity": parity.next()}
-
-        return tmpl("filerevision",
-                    file=f,
-                    path=_up(f),
-                    text=lines(),
-                    rev=fctx.rev(),
-                    node=hex(fctx.node()),
-                    author=fctx.user(),
-                    date=fctx.date(),
-                    desc=fctx.description(),
-                    branch=self.nodebranchnodefault(fctx),
-                    parent=self.siblings(fctx.parents()),
-                    child=self.siblings(fctx.children()),
-                    rename=self.renamelink(fl, n),
-                    permissions=fctx.manifest().flags(f))
-
-    def fileannotate(self, tmpl, fctx):
-        f = fctx.path()
-        n = fctx.filenode()
-        fl = fctx.filelog()
-        parity = paritygen(self.stripecount)
-
-        def annotate(**map):
-            last = None
-            if util.binary(fctx.data()):
-                mt = (mimetypes.guess_type(fctx.path())[0]
-                      or 'application/octet-stream')
-                lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
-                                    '(binary:%s)' % mt)])
-            else:
-                lines = enumerate(fctx.annotate(follow=True, linenumber=True))
-            for lineno, ((f, targetline), l) in lines:
-                fnode = f.filenode()
-                name = self.repo.ui.shortuser(f.user())
-
-                if last != fnode:
-                    last = fnode
-
-                yield {"parity": parity.next(),
-                       "node": hex(f.node()),
-                       "rev": f.rev(),
-                       "author": name,
-                       "file": f.path(),
-                       "targetline": targetline,
-                       "line": l,
-                       "lineid": "l%d" % (lineno + 1),
-                       "linenumber": "% 6d" % (lineno + 1)}
-
-        return tmpl("fileannotate",
-                    file=f,
-                    annotate=annotate,
-                    path=_up(f),
-                    rev=fctx.rev(),
-                    node=hex(fctx.node()),
-                    author=fctx.user(),
-                    date=fctx.date(),
-                    desc=fctx.description(),
-                    rename=self.renamelink(fl, n),
-                    branch=self.nodebranchnodefault(fctx),
-                    parent=self.siblings(fctx.parents()),
-                    child=self.siblings(fctx.children()),
-                    permissions=fctx.manifest().flags(f))
-
-    def manifest(self, tmpl, ctx, path):
-        mf = ctx.manifest()
-        node = ctx.node()
-
-        files = {}
-        parity = paritygen(self.stripecount)
-
-        if path and path[-1] != "/":
-            path += "/"
-        l = len(path)
-        abspath = "/" + path
-
-        for f, n in mf.items():
-            if f[:l] != path:
-                continue
-            remain = f[l:]
-            if "/" in remain:
-                short = remain[:remain.index("/") + 1] # bleah
-                files[short] = (f, None)
-            else:
-                short = os.path.basename(remain)
-                files[short] = (f, n)
-
-        if not files:
-            raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
-
-        def filelist(**map):
-            fl = files.keys()
-            fl.sort()
-            for f in fl:
-                full, fnode = files[f]
-                if not fnode:
-                    continue
-
-                fctx = ctx.filectx(full)
-                yield {"file": full,
-                       "parity": parity.next(),
-                       "basename": f,
-                       "date": fctx.changectx().date(),
-                       "size": fctx.size(),
-                       "permissions": mf.flags(full)}
-
-        def dirlist(**map):
-            fl = files.keys()
-            fl.sort()
-            for f in fl:
-                full, fnode = files[f]
-                if fnode:
-                    continue
-
-                yield {"parity": parity.next(),
-                       "path": "%s%s" % (abspath, f),
-                       "basename": f[:-1]}
-
-        return tmpl("manifest",
-                    rev=ctx.rev(),
-                    node=hex(node),
-                    path=abspath,
-                    up=_up(abspath),
-                    upparity=parity.next(),
-                    fentries=filelist,
-                    dentries=dirlist,
-                    archives=self.archivelist(hex(node)),
-                    tags=self.nodetagsdict(node),
-                    inbranch=self.nodeinbranch(ctx),
-                    branches=self.nodebranchdict(ctx))
-
-    def tags(self, tmpl):
-        i = self.repo.tagslist()
-        i.reverse()
-        parity = paritygen(self.stripecount)
-
-        def entries(notip=False,limit=0, **map):
-            count = 0
-            for k, n in i:
-                if notip and k == "tip":
-                    continue
-                if limit > 0 and count >= limit:
-                    continue
-                count = count + 1
-                yield {"parity": parity.next(),
-                       "tag": k,
-                       "date": self.repo.changectx(n).date(),
-                       "node": hex(n)}
-
-        return tmpl("tags",
-                    node=hex(self.repo.changelog.tip()),
-                    entries=lambda **x: entries(False,0, **x),
-                    entriesnotip=lambda **x: entries(True,0, **x),
-                    latestentry=lambda **x: entries(True,1, **x))
-
-    def summary(self, tmpl):
-        i = self.repo.tagslist()
-        i.reverse()
-
-        def tagentries(**map):
-            parity = paritygen(self.stripecount)
-            count = 0
-            for k, n in i:
-                if k == "tip": # skip tip
-                    continue;
-
-                count += 1
-                if count > 10: # limit to 10 tags
-                    break;
-
-                yield tmpl("tagentry",
-                           parity=parity.next(),
-                           tag=k,
-                           node=hex(n),
-                           date=self.repo.changectx(n).date())
-
-
-        def branches(**map):
-            parity = paritygen(self.stripecount)
-
-            b = self.repo.branchtags()
-            l = [(-self.repo.changelog.rev(n), n, t) for t, n in b.items()]
-            l.sort()
-
-            for r,n,t in l:
-                ctx = self.repo.changectx(n)
-
-                yield {'parity': parity.next(),
-                       'branch': t,
-                       'node': hex(n),
-                       'date': ctx.date()}
-
-        def changelist(**map):
-            parity = paritygen(self.stripecount, offset=start-end)
-            l = [] # build a list in forward order for efficiency
-            for i in xrange(start, end):
-                ctx = self.repo.changectx(i)
-                n = ctx.node()
-                hn = hex(n)
-
-                l.insert(0, tmpl(
-                   'shortlogentry',
-                    parity=parity.next(),
-                    author=ctx.user(),
-                    desc=ctx.description(),
-                    date=ctx.date(),
-                    rev=i,
-                    node=hn,
-                    tags=self.nodetagsdict(n),
-                    inbranch=self.nodeinbranch(ctx),
-                    branches=self.nodebranchdict(ctx)))
-
-            yield l
-
-        cl = self.repo.changelog
-        count = cl.count()
-        start = max(0, count - self.maxchanges)
-        end = min(count, start + self.maxchanges)
-
-        return tmpl("summary",
-                    desc=self.config("web", "description", "unknown"),
-                    owner=get_contact(self.config) or "unknown",
-                    lastchange=cl.read(cl.tip())[2],
-                    tags=tagentries,
-                    branches=branches,
-                    shortlog=changelist,
-                    node=hex(cl.tip()),
-                    archives=self.archivelist("tip"))
-
-    def filediff(self, tmpl, fctx):
-        n = fctx.node()
-        path = fctx.path()
-        parents = fctx.parents()
-        p1 = parents and parents[0].node() or nullid
-
-        def diff(**map):
-            yield self.diff(tmpl, p1, n, [path])
-
-        return tmpl("filediff",
-                    file=path,
-                    node=hex(n),
-                    rev=fctx.rev(),
-                    branch=self.nodebranchnodefault(fctx),
-                    parent=self.siblings(parents),
-                    child=self.siblings(fctx.children()),
-                    diff=diff)
-
     archive_specs = {
         'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
         'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
         'zip': ('application/zip', 'zip', '.zip', None),
         }
 
-    def archive(self, tmpl, req, key, type_):
-        reponame = re.sub(r"\W+", "-", os.path.basename(self.reponame))
-        cnode = self.repo.lookup(key)
-        arch_version = key
-        if cnode == key or key == 'tip':
-            arch_version = short(cnode)
-        name = "%s-%s" % (reponame, arch_version)
-        mimetype, artype, extension, encoding = self.archive_specs[type_]
-        headers = [
-            ('Content-Type', mimetype),
-            ('Content-Disposition', 'attachment; filename=%s%s' %
-                (name, extension))
-        ]
-        if encoding:
-            headers.append(('Content-Encoding', encoding))
-        req.header(headers)
-        req.respond(HTTP_OK)
-        archival.archive(self.repo, req, cnode, artype, prefix=name)
-
-    # add tags to things
-    # tags -> list of changesets corresponding to tags
-    # find tag, changeset, file
-
-    def cleanpath(self, path):
-        path = path.lstrip('/')
-        return util.canonpath(self.repo.root, '', path)
-
-    def changectx(self, req):
-        if 'node' in req.form:
-            changeid = req.form['node'][0]
-        elif 'manifest' in req.form:
-            changeid = req.form['manifest'][0]
-        else:
-            changeid = self.repo.changelog.count() - 1
-
-        try:
-            ctx = self.repo.changectx(changeid)
-        except RepoError:
-            man = self.repo.manifest
-            mn = man.lookup(changeid)
-            ctx = self.repo.changectx(man.linkrev(mn))
-
-        return ctx
-
-    def filectx(self, req):
-        path = self.cleanpath(req.form['file'][0])
-        if 'node' in req.form:
-            changeid = req.form['node'][0]
-        else:
-            changeid = req.form['filenode'][0]
-        try:
-            ctx = self.repo.changectx(changeid)
-            fctx = ctx.filectx(path)
-        except RepoError:
-            fctx = self.repo.filectx(path, fileid=changeid)
-
-        return fctx
-
     def check_perm(self, req, op, default):
         '''check permission for operation based on user auth.
         return true if op allowed, else false.
--- a/mercurial/hgweb/hgwebdir_mod.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/hgweb/hgwebdir_mod.py	Sat Apr 12 21:34:01 2008 +0200
@@ -6,7 +6,7 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import os, mimetools, cStringIO
+import os
 from mercurial.i18n import gettext as _
 from mercurial.repo import RepoError
 from mercurial import ui, hg, util, templater, templatefilters
@@ -81,17 +81,8 @@
 
                 virtual = req.env.get("PATH_INFO", "").strip('/')
                 tmpl = self.templater(req)
-                try:
-                    ctype = tmpl('mimetype', encoding=util._encoding)
-                    ctype = templater.stringify(ctype)
-                except KeyError:
-                    # old templates with inline HTTP headers?
-                    if 'mimetype' in tmpl:
-                        raise
-                    header = tmpl('header', encoding=util._encoding)
-                    header_file = cStringIO.StringIO(templater.stringify(header))
-                    msg = mimetools.Message(header_file, 0)
-                    ctype = msg['content-type']
+                ctype = tmpl('mimetype', encoding=util._encoding)
+                ctype = templater.stringify(ctype)
 
                 # a static file
                 if virtual.startswith('static/') or 'static' in req.form:
@@ -257,13 +248,7 @@
     def templater(self, req):
 
         def header(**map):
-            header = tmpl('header', encoding=util._encoding, **map)
-            if 'mimetype' not in tmpl:
-                # old template with inline HTTP headers
-                header_file = cStringIO.StringIO(templater.stringify(header))
-                msg = mimetools.Message(header_file, 0)
-                header = header_file.read()
-            yield header
+            yield tmpl('header', encoding=util._encoding, **map)
 
         def footer(**map):
             yield tmpl("footer", **map)
--- a/mercurial/hgweb/server.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/hgweb/server.py	Sat Apr 12 21:34:01 2008 +0200
@@ -268,12 +268,7 @@
 
             self.addr, self.port = self.socket.getsockname()[0:2]
             self.prefix = prefix
-
             self.fqaddr = socket.getfqdn(address)
-            try:
-                socket.getaddrbyhost(self.fqaddr)
-            except:
-                fqaddr = address
 
     class IPv6HTTPServer(MercurialHTTPServer):
         address_family = getattr(socket, 'AF_INET6', None)
--- a/mercurial/hgweb/webcommands.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/hgweb/webcommands.py	Sat Apr 12 21:34:01 2008 +0200
@@ -5,10 +5,14 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-import os, mimetypes
-from mercurial import revlog, util
+import os, mimetypes, re
+import webutil
+from mercurial import revlog, archival
+from mercurial.node import short, hex, nullid
+from mercurial.util import binary
 from mercurial.repo import RepoError
-from common import staticfile, ErrorResponse, HTTP_OK, HTTP_NOT_FOUND
+from common import paritygen, staticfile, get_contact, ErrorResponse
+from common import HTTP_OK, HTTP_NOT_FOUND
 
 # __all__ is populated with the allowed commands. Be sure to add to it if
 # you're adding a new command, or the new command won't work.
@@ -26,17 +30,17 @@
         return changelog(web, req, tmpl)
 
 def rawfile(web, req, tmpl):
-    path = web.cleanpath(req.form.get('file', [''])[0])
+    path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
     if not path:
-        content = web.manifest(tmpl, web.changectx(req), path)
+        content = manifest(web, req, tmpl)
         req.respond(HTTP_OK, web.ctype)
         return content
 
     try:
-        fctx = web.filectx(req)
+        fctx = webutil.filectx(web.repo, req)
     except revlog.LookupError, inst:
         try:
-            content = web.manifest(tmpl, web.changectx(req), path)
+            content = manifest(web, req, tmpl)
             req.respond(HTTP_OK, web.ctype)
             return content
         except ErrorResponse:
@@ -45,28 +49,120 @@
     path = fctx.path()
     text = fctx.data()
     mt = mimetypes.guess_type(path)[0]
-    if mt is None or util.binary(text):
+    if mt is None or binary(text):
         mt = mt or 'application/octet-stream'
 
     req.respond(HTTP_OK, mt, path, len(text))
     return [text]
 
+def _filerevision(web, tmpl, fctx):
+    f = fctx.path()
+    text = fctx.data()
+    fl = fctx.filelog()
+    n = fctx.filenode()
+    parity = paritygen(web.stripecount)
+
+    if binary(text):
+        mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
+        text = '(binary:%s)' % mt
+
+    def lines():
+        for lineno, t in enumerate(text.splitlines(1)):
+            yield {"line": t,
+                   "lineid": "l%d" % (lineno + 1),
+                   "linenumber": "% 6d" % (lineno + 1),
+                   "parity": parity.next()}
+
+    return tmpl("filerevision",
+                file=f,
+                path=webutil.up(f),
+                text=lines(),
+                rev=fctx.rev(),
+                node=hex(fctx.node()),
+                author=fctx.user(),
+                date=fctx.date(),
+                desc=fctx.description(),
+                branch=webutil.nodebranchnodefault(fctx),
+                parent=webutil.siblings(fctx.parents()),
+                child=webutil.siblings(fctx.children()),
+                rename=webutil.renamelink(fctx),
+                permissions=fctx.manifest().flags(f))
+
 def file(web, req, tmpl):
-    path = web.cleanpath(req.form.get('file', [''])[0])
+    path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
     if path:
         try:
-            return web.filerevision(tmpl, web.filectx(req))
+            return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
         except revlog.LookupError, inst:
             pass
 
     try:
-        return web.manifest(tmpl, web.changectx(req), path)
+        return manifest(web, req, tmpl)
     except ErrorResponse:
         raise inst
 
+def _search(web, tmpl, query):
+
+    def changelist(**map):
+        cl = web.repo.changelog
+        count = 0
+        qw = query.lower().split()
+
+        def revgen():
+            for i in xrange(cl.count() - 1, 0, -100):
+                l = []
+                for j in xrange(max(0, i - 100), i + 1):
+                    ctx = web.repo.changectx(j)
+                    l.append(ctx)
+                l.reverse()
+                for e in l:
+                    yield e
+
+        for ctx in revgen():
+            miss = 0
+            for q in qw:
+                if not (q in ctx.user().lower() or
+                        q in ctx.description().lower() or
+                        q in " ".join(ctx.files()).lower()):
+                    miss = 1
+                    break
+            if miss:
+                continue
+
+            count = 1
+            n = ctx.node()
+            showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
+
+            yield tmpl('searchentry',
+                       parity=parity.next(),
+                       author=ctx.user(),
+                       parent=webutil.siblings(ctx.parents()),
+                       child=webutil.siblings(ctx.children()),
+                       changelogtag=showtags,
+                       desc=ctx.description(),
+                       date=ctx.date(),
+                       files=web.listfilediffs(tmpl, ctx.files(), n),
+                       rev=ctx.rev(),
+                       node=hex(n),
+                       tags=webutil.nodetagsdict(web.repo, n),
+                       inbranch=webutil.nodeinbranch(web.repo, ctx),
+                       branches=webutil.nodebranchdict(web.repo, ctx))
+
+            if count >= web.maxchanges:
+                break
+
+    cl = web.repo.changelog
+    parity = paritygen(web.stripecount)
+
+    return tmpl('search',
+                query=query,
+                node=hex(cl.tip()),
+                entries=changelist,
+                archives=web.archivelist("tip"))
+
 def changelog(web, req, tmpl, shortlog = False):
     if 'node' in req.form:
-        ctx = web.changectx(req)
+        ctx = webutil.changectx(web.repo, req)
     else:
         if 'rev' in req.form:
             hi = req.form['rev'][0]
@@ -75,47 +171,400 @@
         try:
             ctx = web.repo.changectx(hi)
         except RepoError:
-            return web.search(tmpl, hi) # XXX redirect to 404 page?
+            return _search(web, tmpl, hi) # XXX redirect to 404 page?
+
+    def changelist(limit=0, **map):
+        cl = web.repo.changelog
+        l = [] # build a list in forward order for efficiency
+        for i in xrange(start, end):
+            ctx = web.repo.changectx(i)
+            n = ctx.node()
+            showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
+
+            l.insert(0, {"parity": parity.next(),
+                         "author": ctx.user(),
+                         "parent": webutil.siblings(ctx.parents(), i - 1),
+                         "child": webutil.siblings(ctx.children(), i + 1),
+                         "changelogtag": showtags,
+                         "desc": ctx.description(),
+                         "date": ctx.date(),
+                         "files": web.listfilediffs(tmpl, ctx.files(), n),
+                         "rev": i,
+                         "node": hex(n),
+                         "tags": webutil.nodetagsdict(web.repo, n),
+                         "inbranch": webutil.nodeinbranch(web.repo, ctx),
+                         "branches": webutil.nodebranchdict(web.repo, ctx)
+                        })
 
-    return web.changelog(tmpl, ctx, shortlog = shortlog)
+        if limit > 0:
+            l = l[:limit]
+
+        for e in l:
+            yield e
+
+    maxchanges = shortlog and web.maxshortchanges or web.maxchanges
+    cl = web.repo.changelog
+    count = cl.count()
+    pos = ctx.rev()
+    start = max(0, pos - maxchanges + 1)
+    end = min(count, start + maxchanges)
+    pos = end - 1
+    parity = paritygen(web.stripecount, offset=start-end)
+
+    changenav = webutil.revnavgen(pos, maxchanges, count, web.repo.changectx)
+
+    return tmpl(shortlog and 'shortlog' or 'changelog',
+                changenav=changenav,
+                node=hex(ctx.node()),
+                rev=pos, changesets=count,
+                entries=lambda **x: changelist(limit=0,**x),
+                latestentry=lambda **x: changelist(limit=1,**x),
+                archives=web.archivelist("tip"))
 
 def shortlog(web, req, tmpl):
     return changelog(web, req, tmpl, shortlog = True)
 
 def changeset(web, req, tmpl):
-    return web.changeset(tmpl, web.changectx(req))
+    ctx = webutil.changectx(web.repo, req)
+    n = ctx.node()
+    showtags = webutil.showtag(web.repo, tmpl, 'changesettag', n)
+    parents = ctx.parents()
+    p1 = parents[0].node()
+
+    files = []
+    parity = paritygen(web.stripecount)
+    for f in ctx.files():
+        files.append(tmpl("filenodelink",
+                          node=hex(n), file=f,
+                          parity=parity.next()))
+
+    diffs = web.diff(tmpl, p1, n, None)
+    return tmpl('changeset',
+                diff=diffs,
+                rev=ctx.rev(),
+                node=hex(n),
+                parent=webutil.siblings(parents),
+                child=webutil.siblings(ctx.children()),
+                changesettag=showtags,
+                author=ctx.user(),
+                desc=ctx.description(),
+                date=ctx.date(),
+                files=files,
+                archives=web.archivelist(hex(n)),
+                tags=webutil.nodetagsdict(web.repo, n),
+                branch=webutil.nodebranchnodefault(ctx),
+                inbranch=webutil.nodeinbranch(web.repo, ctx),
+                branches=webutil.nodebranchdict(web.repo, ctx))
 
 rev = changeset
 
 def manifest(web, req, tmpl):
-    return web.manifest(tmpl, web.changectx(req),
-                        web.cleanpath(req.form['path'][0]))
+    ctx = webutil.changectx(web.repo, req)
+    path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
+    mf = ctx.manifest()
+    node = ctx.node()
+
+    files = {}
+    parity = paritygen(web.stripecount)
+
+    if path and path[-1] != "/":
+        path += "/"
+    l = len(path)
+    abspath = "/" + path
+
+    for f, n in mf.items():
+        if f[:l] != path:
+            continue
+        remain = f[l:]
+        if "/" in remain:
+            short = remain[:remain.index("/") + 1] # bleah
+            files[short] = (f, None)
+        else:
+            short = os.path.basename(remain)
+            files[short] = (f, n)
+
+    if not files:
+        raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
+
+    def filelist(**map):
+        fl = files.keys()
+        fl.sort()
+        for f in fl:
+            full, fnode = files[f]
+            if not fnode:
+                continue
+
+            fctx = ctx.filectx(full)
+            yield {"file": full,
+                   "parity": parity.next(),
+                   "basename": f,
+                   "date": fctx.changectx().date(),
+                   "size": fctx.size(),
+                   "permissions": mf.flags(full)}
+
+    def dirlist(**map):
+        fl = files.keys()
+        fl.sort()
+        for f in fl:
+            full, fnode = files[f]
+            if fnode:
+                continue
+
+            yield {"parity": parity.next(),
+                   "path": "%s%s" % (abspath, f),
+                   "basename": f[:-1]}
+
+    return tmpl("manifest",
+                rev=ctx.rev(),
+                node=hex(node),
+                path=abspath,
+                up=webutil.up(abspath),
+                upparity=parity.next(),
+                fentries=filelist,
+                dentries=dirlist,
+                archives=web.archivelist(hex(node)),
+                tags=webutil.nodetagsdict(web.repo, node),
+                inbranch=webutil.nodeinbranch(web.repo, ctx),
+                branches=webutil.nodebranchdict(web.repo, ctx))
 
 def tags(web, req, tmpl):
-    return web.tags(tmpl)
+    i = web.repo.tagslist()
+    i.reverse()
+    parity = paritygen(web.stripecount)
+
+    def entries(notip=False,limit=0, **map):
+        count = 0
+        for k, n in i:
+            if notip and k == "tip":
+                continue
+            if limit > 0 and count >= limit:
+                continue
+            count = count + 1
+            yield {"parity": parity.next(),
+                   "tag": k,
+                   "date": web.repo.changectx(n).date(),
+                   "node": hex(n)}
+
+    return tmpl("tags",
+                node=hex(web.repo.changelog.tip()),
+                entries=lambda **x: entries(False,0, **x),
+                entriesnotip=lambda **x: entries(True,0, **x),
+                latestentry=lambda **x: entries(True,1, **x))
 
 def summary(web, req, tmpl):
-    return web.summary(tmpl)
+    i = web.repo.tagslist()
+    i.reverse()
+
+    def tagentries(**map):
+        parity = paritygen(web.stripecount)
+        count = 0
+        for k, n in i:
+            if k == "tip": # skip tip
+                continue
+
+            count = 1
+            if count > 10: # limit to 10 tags
+                break
+
+            yield tmpl("tagentry",
+                       parity=parity.next(),
+                       tag=k,
+                       node=hex(n),
+                       date=web.repo.changectx(n).date())
+
+    def branches(**map):
+        parity = paritygen(web.stripecount)
+
+        b = web.repo.branchtags()
+        l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.items()]
+        l.sort()
+
+        for r,n,t in l:
+            ctx = web.repo.changectx(n)
+            yield {'parity': parity.next(),
+                   'branch': t,
+                   'node': hex(n),
+                   'date': ctx.date()}
+
+    def changelist(**map):
+        parity = paritygen(web.stripecount, offset=start-end)
+        l = [] # build a list in forward order for efficiency
+        for i in xrange(start, end):
+            ctx = web.repo.changectx(i)
+            n = ctx.node()
+            hn = hex(n)
+
+            l.insert(0, tmpl(
+               'shortlogentry',
+                parity=parity.next(),
+                author=ctx.user(),
+                desc=ctx.description(),
+                date=ctx.date(),
+                rev=i,
+                node=hn,
+                tags=webutil.nodetagsdict(web.repo, n),
+                inbranch=webutil.nodeinbranch(web.repo, ctx),
+                branches=webutil.nodebranchdict(web.repo, ctx)))
+
+        yield l
+
+    cl = web.repo.changelog
+    count = cl.count()
+    start = max(0, count - web.maxchanges)
+    end = min(count, start + web.maxchanges)
+
+    return tmpl("summary",
+                desc=web.config("web", "description", "unknown"),
+                owner=get_contact(web.config) or "unknown",
+                lastchange=cl.read(cl.tip())[2],
+                tags=tagentries,
+                branches=branches,
+                shortlog=changelist,
+                node=hex(cl.tip()),
+                archives=web.archivelist("tip"))
 
 def filediff(web, req, tmpl):
-    return web.filediff(tmpl, web.filectx(req))
+    fctx = webutil.filectx(web.repo, req)
+    n = fctx.node()
+    path = fctx.path()
+    parents = fctx.parents()
+    p1 = parents and parents[0].node() or nullid
+
+    diffs = web.diff(tmpl, p1, n, [path])
+    return tmpl("filediff",
+                file=path,
+                node=hex(n),
+                rev=fctx.rev(),
+                date=fctx.date(),
+                desc=fctx.description(),
+                author=fctx.user(),
+                rename=webutil.renamelink(fctx),
+                branch=webutil.nodebranchnodefault(fctx),
+                parent=webutil.siblings(parents),
+                child=webutil.siblings(fctx.children()),
+                diff=diffs)
 
 diff = filediff
 
 def annotate(web, req, tmpl):
-    return web.fileannotate(tmpl, web.filectx(req))
+    fctx = webutil.filectx(web.repo, req)
+    f = fctx.path()
+    n = fctx.filenode()
+    fl = fctx.filelog()
+    parity = paritygen(web.stripecount)
+
+    def annotate(**map):
+        last = None
+        if binary(fctx.data()):
+            mt = (mimetypes.guess_type(fctx.path())[0]
+                  or 'application/octet-stream')
+            lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
+                                '(binary:%s)' % mt)])
+        else:
+            lines = enumerate(fctx.annotate(follow=True, linenumber=True))
+        for lineno, ((f, targetline), l) in lines:
+            fnode = f.filenode()
+            name = web.repo.ui.shortuser(f.user())
+
+            if last != fnode:
+                last = fnode
+
+            yield {"parity": parity.next(),
+                   "node": hex(f.node()),
+                   "rev": f.rev(),
+                   "author": name,
+                   "file": f.path(),
+                   "targetline": targetline,
+                   "line": l,
+                   "lineid": "l%d" % (lineno + 1),
+                   "linenumber": "% 6d" % (lineno + 1)}
+
+    return tmpl("fileannotate",
+                file=f,
+                annotate=annotate,
+                path=webutil.up(f),
+                rev=fctx.rev(),
+                node=hex(fctx.node()),
+                author=fctx.user(),
+                date=fctx.date(),
+                desc=fctx.description(),
+                rename=webutil.renamelink(fctx),
+                branch=webutil.nodebranchnodefault(fctx),
+                parent=webutil.siblings(fctx.parents()),
+                child=webutil.siblings(fctx.children()),
+                permissions=fctx.manifest().flags(f))
 
 def filelog(web, req, tmpl):
-    return web.filelog(tmpl, web.filectx(req))
+    fctx = webutil.filectx(web.repo, req)
+    f = fctx.path()
+    fl = fctx.filelog()
+    count = fl.count()
+    pagelen = web.maxshortchanges
+    pos = fctx.filerev()
+    start = max(0, pos - pagelen + 1)
+    end = min(count, start + pagelen)
+    pos = end - 1
+    parity = paritygen(web.stripecount, offset=start-end)
+
+    def entries(limit=0, **map):
+        l = []
+
+        for i in xrange(start, end):
+            ctx = fctx.filectx(i)
+            n = fl.node(i)
+
+            l.insert(0, {"parity": parity.next(),
+                         "filerev": i,
+                         "file": f,
+                         "node": hex(ctx.node()),
+                         "author": ctx.user(),
+                         "date": ctx.date(),
+                         "rename": webutil.renamelink(fctx),
+                         "parent": webutil.siblings(fctx.parents()),
+                         "child": webutil.siblings(fctx.children()),
+                         "desc": ctx.description()})
+
+        if limit > 0:
+            l = l[:limit]
+
+        for e in l:
+            yield e
+
+    nodefunc = lambda x: fctx.filectx(fileid=x)
+    nav = webutil.revnavgen(pos, pagelen, count, nodefunc)
+    return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav,
+                entries=lambda **x: entries(limit=0, **x),
+                latestentry=lambda **x: entries(limit=1, **x))
+
 
 def archive(web, req, tmpl):
     type_ = req.form['type'][0]
     allowed = web.configlist("web", "allow_archive")
-    if (type_ in web.archives and (type_ in allowed or
+    key = req.form['node'][0]
+
+    if not (type_ in web.archives and (type_ in allowed or
         web.configbool("web", "allow" + type_, False))):
-        web.archive(tmpl, req, req.form['node'][0], type_)
-        return []
-    raise ErrorResponse(HTTP_NOT_FOUND, 'unsupported archive type: %s' % type_)
+        msg = 'Unsupported archive type: %s' % type_
+        raise ErrorResponse(HTTP_NOT_FOUND, msg)
+
+    reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
+    cnode = web.repo.lookup(key)
+    arch_version = key
+    if cnode == key or key == 'tip':
+        arch_version = short(cnode)
+    name = "%s-%s" % (reponame, arch_version)
+    mimetype, artype, extension, encoding = web.archive_specs[type_]
+    headers = [
+        ('Content-Type', mimetype),
+        ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
+    ]
+    if encoding:
+        headers.append(('Content-Encoding', encoding))
+    req.header(headers)
+    req.respond(HTTP_OK)
+    archival.archive(web.repo, req, cnode, artype, prefix=name)
+    return []
+
 
 def static(web, req, tmpl):
     fname = req.form['file'][0]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/hgweb/webutil.py	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,143 @@
+# hgweb/webutil.py - utility library for the web interface.
+#
+# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
+# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms
+# of the GNU General Public License, incorporated herein by reference.
+
+import os
+from mercurial.node import hex, nullid
+from mercurial.repo import RepoError
+from mercurial import util
+
+def up(p):
+    if p[0] != "/":
+        p = "/" + p
+    if p[-1] == "/":
+        p = p[:-1]
+    up = os.path.dirname(p)
+    if up == "/":
+        return "/"
+    return up + "/"
+
+def revnavgen(pos, pagelen, limit, nodefunc):
+    def seq(factor, limit=None):
+        if limit:
+            yield limit
+            if limit >= 20 and limit <= 40:
+                yield 50
+        else:
+            yield 1 * factor
+            yield 3 * factor
+        for f in seq(factor * 10):
+            yield f
+
+    def nav(**map):
+        l = []
+        last = 0
+        for f in seq(1, pagelen):
+            if f < pagelen or f <= last:
+                continue
+            if f > limit:
+                break
+            last = f
+            if pos + f < limit:
+                l.append(("+%d" % f, hex(nodefunc(pos + f).node())))
+            if pos - f >= 0:
+                l.insert(0, ("-%d" % f, hex(nodefunc(pos - f).node())))
+
+        try:
+            yield {"label": "(0)", "node": hex(nodefunc('0').node())}
+
+            for label, node in l:
+                yield {"label": label, "node": node}
+
+            yield {"label": "tip", "node": "tip"}
+        except RepoError:
+            pass
+
+    return nav
+
+def siblings(siblings=[], hiderev=None, **args):
+    siblings = [s for s in siblings if s.node() != nullid]
+    if len(siblings) == 1 and siblings[0].rev() == hiderev:
+        return
+    for s in siblings:
+        d = {'node': hex(s.node()), 'rev': s.rev()}
+        if hasattr(s, 'path'):
+            d['file'] = s.path()
+        d.update(args)
+        yield d
+
+def renamelink(fctx):
+    r = fctx.renamed()
+    if r:
+        return [dict(file=r[0], node=hex(r[1]))]
+    return []
+
+def nodetagsdict(repo, node):
+    return [{"name": i} for i in repo.nodetags(node)]
+
+def nodebranchdict(repo, ctx):
+    branches = []
+    branch = ctx.branch()
+    # If this is an empty repo, ctx.node() == nullid,
+    # ctx.branch() == 'default', but branchtags() is
+    # an empty dict. Using dict.get avoids a traceback.
+    if repo.branchtags().get(branch) == ctx.node():
+        branches.append({"name": branch})
+    return branches
+
+def nodeinbranch(repo, ctx):
+    branches = []
+    branch = ctx.branch()
+    if branch != 'default' and repo.branchtags().get(branch) != ctx.node():
+        branches.append({"name": branch})
+    return branches
+
+def nodebranchnodefault(ctx):
+    branches = []
+    branch = ctx.branch()
+    if branch != 'default':
+        branches.append({"name": branch})
+    return branches
+
+def showtag(repo, tmpl, t1, node=nullid, **args):
+    for t in repo.nodetags(node):
+        yield tmpl(t1, tag=t, **args)
+
+def cleanpath(repo, path):
+    path = path.lstrip('/')
+    return util.canonpath(repo.root, '', path)
+
+def changectx(repo, req):
+    if 'node' in req.form:
+        changeid = req.form['node'][0]
+    elif 'manifest' in req.form:
+        changeid = req.form['manifest'][0]
+    else:
+        changeid = repo.changelog.count() - 1
+
+    try:
+        ctx = repo.changectx(changeid)
+    except RepoError:
+        man = repo.manifest
+        mn = man.lookup(changeid)
+        ctx = repo.changectx(man.linkrev(mn))
+
+    return ctx
+
+def filectx(repo, req):
+    path = cleanpath(repo, req.form['file'][0])
+    if 'node' in req.form:
+        changeid = req.form['node'][0]
+    else:
+        changeid = req.form['filenode'][0]
+    try:
+        ctx = repo.changectx(changeid)
+        fctx = ctx.filectx(path)
+    except RepoError:
+        fctx = repo.filectx(path, fileid=changeid)
+
+    return fctx
--- a/mercurial/keepalive.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/keepalive.py	Sat Apr 12 21:34:01 2008 +0200
@@ -19,6 +19,8 @@
 
 # Modified by Benoit Boissinot:
 #  - fix for digest auth (inspired from urllib2.py @ Python v2.4)
+# Modified by Dirkjan Ochtman:
+#  - import md5 function from a local util module
 
 """An HTTP handler for urllib2 that supports HTTP 1.1 and keepalive.
 
@@ -450,7 +452,7 @@
     keepalive_handler.close_all()
 
 def continuity(url):
-    import md5
+    from util import md5
     format = '%25s: %s'
 
     # first fetch the file with the normal http handler
--- a/mercurial/localrepo.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/localrepo.py	Sat Apr 12 21:34:01 2008 +0200
@@ -476,6 +476,9 @@
     def wjoin(self, f):
         return os.path.join(self.root, f)
 
+    def rjoin(self, f):
+        return os.path.join(self.root, util.pconvert(f))
+
     def file(self, f):
         if f[0] == '/':
             f = f[1:]
--- a/mercurial/manifest.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/manifest.py	Sat Apr 12 21:34:01 2008 +0200
@@ -8,7 +8,7 @@
 from node import bin, hex, nullid
 from revlog import revlog, RevlogError
 from i18n import _
-import array, struct, mdiff
+import array, struct, mdiff, parsers
 
 class manifestdict(dict):
     def __init__(self, mapping=None, flags=None):
@@ -39,14 +39,7 @@
 
     def parse(self, lines):
         mfdict = manifestdict()
-        fdict = mfdict._flags
-        for l in lines.splitlines():
-            f, n = l.split('\0')
-            if len(n) > 40:
-                fdict[f] = n[40:]
-                mfdict[f] = bin(n[:40])
-            else:
-                mfdict[f] = bin(n)
+        parsers.parse_manifest(mfdict, mfdict._flags, lines)
         return mfdict
 
     def readdelta(self, node):
--- a/mercurial/mdiff.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/mdiff.py	Sat Apr 12 21:34:01 2008 +0200
@@ -6,7 +6,7 @@
 # of the GNU General Public License, incorporated herein by reference.
 
 from i18n import _
-import bdiff, mpatch, re, struct, util, md5
+import bdiff, mpatch, re, struct, util
 
 def splitnewlines(text):
     '''like str.splitlines, but only split on newlines.'''
@@ -80,7 +80,7 @@
     if not opts.text and (util.binary(a) or util.binary(b)):
         def h(v):
             # md5 is used instead of sha1 because md5 is supposedly faster
-            return md5.new(v).digest()
+            return util.md5(v).digest()
         if a and b and len(a) == len(b) and h(a) == h(b):
             return ""
         l = ['Binary file %s has changed\n' % fn1]
--- a/mercurial/merge.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/merge.py	Sat Apr 12 21:34:01 2008 +0200
@@ -5,9 +5,66 @@
 # This software may be used and distributed according to the terms
 # of the GNU General Public License, incorporated herein by reference.
 
-from node import nullid, nullrev
+from node import nullid, nullrev, hex, bin
 from i18n import _
-import errno, util, os, filemerge, copies
+import errno, util, os, filemerge, copies, shutil
+
+class mergestate(object):
+    '''track 3-way merge state of individual files'''
+    def __init__(self, repo):
+        self._repo = repo
+        self._read()
+    def reset(self, node):
+        self._state = {}
+        self._local = node
+        shutil.rmtree(self._repo.join("merge"), True)
+    def _read(self):
+        self._state = {}
+        try:
+            f = self._repo.opener("merge/state")
+            self._local = bin(f.readline()[:-1])
+            for l in f:
+                bits = l[:-1].split("\0")
+                self._state[bits[0]] = bits[1:]
+        except IOError, err:
+            if err.errno != errno.ENOENT:
+                raise
+    def _write(self):
+        f = self._repo.opener("merge/state", "w")
+        f.write(hex(self._local) + "\n")
+        for d, v in self._state.items():
+            f.write("\0".join([d] + v) + "\n")
+    def add(self, fcl, fco, fca, fd, flags):
+        hash = util.sha1(fcl.path()).hexdigest()
+        self._repo.opener("merge/" + hash, "w").write(fcl.data())
+        self._state[fd] = ['u', hash, fcl.path(), fca.path(),
+                           hex(fca.filenode()), fco.path(), flags]
+        self._write()
+    def __contains__(self, dfile):
+        return dfile in self._state
+    def __getitem__(self, dfile):
+        return self._state[dfile][0]
+    def __iter__(self):
+        l = self._state.keys()
+        l.sort()
+        for f in l:
+            yield f
+    def mark(self, dfile, state):
+        self._state[dfile][0] = state
+        self._write()
+    def resolve(self, dfile, wctx, octx):
+        if self[dfile] == 'r':
+            return 0
+        state, hash, lfile, afile, anode, ofile, flags = self._state[dfile]
+        f = self._repo.opener("merge/" + hash)
+        self._repo.wwrite(dfile, f.read(), flags)
+        fcd = wctx[dfile]
+        fco = octx[ofile]
+        fca = self._repo.filectx(afile, fileid=anode)
+        r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca)
+        if not r:
+            self.mark(dfile, 'r')
+        return r
 
 def _checkunknown(wctx, mctx):
     "check for collisions between unknown files and files in mctx"
@@ -202,14 +259,29 @@
 
     updated, merged, removed, unresolved = 0, 0, 0, 0
     action.sort()
-    # prescan for copy/renames
+
+    ms = mergestate(repo)
+    ms.reset(wctx.parents()[0].node())
+    moves = []
+
+    # prescan for merges
     for a in action:
         f, m = a[:2]
         if m == 'm': # merge
             f2, fd, flags, move = a[2:]
-            if f != fd:
-                repo.ui.debug(_("copying %s to %s\n") % (f, fd))
-                repo.wwrite(fd, repo.wread(f), flags)
+            repo.ui.debug(_("preserving %s for resolve of %s\n") % (f, fd))
+            fcl = wctx[f]
+            fco = mctx[f2]
+            fca = fcl.ancestor(fco) or repo.filectx(f, fileid=nullrev)
+            ms.add(fcl, fco, fca, fd, flags)
+            if f != fd and move:
+                moves.append(f)
+
+    # remove renamed files after safely stored
+    for f in moves:
+        if util.lexists(repo.wjoin(f)):
+            repo.ui.debug(_("removing %s\n") % f)
+            os.unlink(repo.wjoin(f))
 
     audit_path = util.path_auditor(repo.root)
 
@@ -229,7 +301,7 @@
             removed += 1
         elif m == "m": # merge
             f2, fd, flags, move = a[2:]
-            r = filemerge.filemerge(repo, f, fd, f2, wctx, mctx)
+            r = ms.resolve(fd, wctx, mctx)
             if r > 0:
                 unresolved += 1
             else:
@@ -237,10 +309,6 @@
                     updated += 1
                 else:
                     merged += 1
-            util.set_flags(repo.wjoin(fd), flags)
-            if f != fd and move and util.lexists(repo.wjoin(f)):
-                repo.ui.debug(_("removing %s\n") % f)
-                os.unlink(repo.wjoin(f))
         elif m == "g": # get
             flags = a[2]
             repo.ui.note(_("getting %s\n") % f)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/parsers.c	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,169 @@
+/*
+ parsers.c - efficient content parsing
+
+ Copyright 2008 Matt Mackall <mpm@selenic.com> and others
+
+ This software may be used and distributed according to the terms of
+ the GNU General Public License, incorporated herein by reference.
+*/
+
+#include <Python.h>
+#include <ctype.h>
+#include <string.h>
+
+static int hexdigit(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	
+	return -1;
+}
+
+/*
+ * Turn a hex-encoded string into binary.
+ */
+static PyObject *unhexlify(const char *str, int len)
+{
+	PyObject *ret = NULL;
+	const char *c;
+	char *d;
+
+	if (len % 2) {
+		PyErr_SetString(PyExc_ValueError,
+				"input is not even in length");
+		goto bail;
+	}
+
+	ret = PyString_FromStringAndSize(NULL, len / 2);
+	if (!ret)
+		goto bail;
+
+	d = PyString_AsString(ret);
+	if (!d)
+		goto bail;
+
+	for (c = str; c < str + len;) {
+		int hi = hexdigit(*c++);
+		int lo = hexdigit(*c++);
+
+		if (hi == -1 || lo == -1) {
+			PyErr_SetString(PyExc_ValueError,
+					"input contains non-hex character");
+			goto bail;
+		}
+
+		*d++ = (hi << 4) | lo;
+	}
+	
+	goto done;
+	
+bail:
+	Py_XDECREF(ret);
+	ret = NULL;
+done:
+	return ret;
+}
+
+/*
+ * This code assumes that a manifest is stitched together with newline
+ * ('\n') characters.
+ */
+static PyObject *parse_manifest(PyObject *self, PyObject *args)
+{
+	PyObject *mfdict, *fdict;
+	char *str, *cur, *start, *zero;
+	int len;
+
+	if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
+			      &PyDict_Type, &mfdict,
+			      &PyDict_Type, &fdict,
+			      &str, &len))
+		goto quit;
+
+	for (start = cur = str, zero = NULL; cur < str + len; cur++) {
+		PyObject *file = NULL, *node = NULL;
+		PyObject *flags = NULL;
+		int nlen;
+
+		if (!*cur) {
+			zero = cur;
+			continue;
+		}
+		else if (*cur != '\n')
+			continue;
+
+		if (!zero) {
+			PyErr_SetString(PyExc_ValueError,
+					"manifest entry has no separator");
+			goto quit;
+		}
+
+		file = PyString_FromStringAndSize(start, zero - start);
+		if (!file)
+			goto bail;
+
+		nlen = cur - zero - 1;
+
+		node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen);
+		if (!node)
+			goto bail;
+
+		if (nlen > 40) {
+			PyObject *flags;
+
+			flags = PyString_FromStringAndSize(zero + 41,
+							   nlen - 40);
+			if (!flags)
+				goto bail;
+
+			if (PyDict_SetItem(fdict, file, flags) == -1)
+				goto bail;
+		}
+
+		if (PyDict_SetItem(mfdict, file, node) == -1)
+			goto bail;
+
+		start = cur + 1;
+		zero = NULL;
+
+		Py_XDECREF(flags);
+		Py_XDECREF(node);
+		Py_XDECREF(file);
+		continue;
+	bail:
+		Py_XDECREF(flags);
+		Py_XDECREF(node);
+		Py_XDECREF(file);
+		goto quit;
+	}
+
+	if (len > 0 && *(cur - 1) != '\n') {
+		PyErr_SetString(PyExc_ValueError,
+				"manifest contains trailing garbage");
+		goto quit;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+
+quit:
+	return NULL;
+}
+
+static char parsers_doc[] = "Efficient content parsing.";
+
+static PyMethodDef methods[] = {
+	{"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
+	{NULL, NULL}
+};
+
+PyMODINIT_FUNC initparsers(void)
+{
+	Py_InitModule3("parsers", methods, parsers_doc);
+}
--- a/mercurial/patch.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/patch.py	Sat Apr 12 21:34:01 2008 +0200
@@ -9,7 +9,7 @@
 from i18n import _
 from node import hex, nullid, short
 import base85, cmdutil, mdiff, util, context, revlog, diffhelpers, copies
-import cStringIO, email.Parser, os, popen2, re, sha, errno
+import cStringIO, email.Parser, os, popen2, re, errno
 import sys, tempfile, zlib
 
 class PatchError(Exception):
@@ -1120,7 +1120,7 @@
         if not text:
             return '0' * 40
         l = len(text)
-        s = sha.new('blob %d\0' % l)
+        s = util.sha1('blob %d\0' % l)
         s.update(text)
         return s.hexdigest()
 
--- a/mercurial/repair.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/repair.py	Sat Apr 12 21:34:01 2008 +0200
@@ -72,7 +72,6 @@
 def strip(ui, repo, node, backup="all"):
     cl = repo.changelog
     # TODO delete the undo files, and handle undo of merge sets
-    pp = cl.parents(node)
     striprev = cl.rev(node)
 
     # Some revisions with rev > striprev may not be descendants of striprev.
--- a/mercurial/repo.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/repo.py	Sat Apr 12 21:34:01 2008 +0200
@@ -40,3 +40,9 @@
 
     def cancopy(self):
         return self.local()
+
+    def rjoin(self, path):
+        url = self.url()
+        if url.endswith('/'):
+            return url + path
+        return url + '/' + path
--- a/mercurial/revlog.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/revlog.py	Sat Apr 12 21:34:01 2008 +0200
@@ -13,13 +13,13 @@
 from node import bin, hex, nullid, nullrev, short
 from i18n import _
 import changegroup, errno, ancestor, mdiff
-import sha, struct, util, zlib
+import struct, util, zlib
 
 _pack = struct.pack
 _unpack = struct.unpack
 _compress = zlib.compress
 _decompress = zlib.decompress
-_sha = sha.new
+_sha = util.sha1
 
 # revlog flags
 REVLOGV0 = 0
--- a/mercurial/templater.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/templater.py	Sat Apr 12 21:34:01 2008 +0200
@@ -114,7 +114,7 @@
                 v = v(**map)
             if format:
                 if not hasattr(v, '__iter__'):
-                    raise SyntaxError(_("Error expanding '%s%s'")
+                    raise SyntaxError(_("Error expanding '%s%%%s'")
                                       % (key, format))
                 lm = map.copy()
                 for i in v:
--- a/mercurial/transaction.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/transaction.py	Sat Apr 12 21:34:01 2008 +0200
@@ -96,9 +96,13 @@
     files = {}
     for l in open(file).readlines():
         f, o = l.split('\0')
-        files[f] = o
+        files[f] = int(o)
     for f in files:
         o = files[f]
-        opener(f, "a").truncate(int(o))
+        if o:
+            opener(f, "a").truncate(int(o))
+        else:
+            fn = opener(f).name
+            os.unlink(fn)
     os.unlink(file)
 
--- a/mercurial/util.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/mercurial/util.py	Sat Apr 12 21:34:01 2008 +0200
@@ -15,7 +15,9 @@
 from i18n import _
 import cStringIO, errno, getpass, re, shutil, sys, tempfile
 import os, stat, threading, time, calendar, ConfigParser, locale, glob, osutil
-import urlparse
+import imp, urlparse
+
+# Python compatibility
 
 try:
     set = set
@@ -23,6 +25,30 @@
 except NameError:
     from sets import Set as set, ImmutableSet as frozenset
 
+_md5 = None
+def md5(s):
+    global _md5
+    if _md5 is None:
+        try:
+            import hashlib
+            _md5 = hashlib.md5
+        except ImportError:
+            import md5
+            _md5 = md5.md5
+    return _md5(s)
+
+_sha1 = None
+def sha1(s):
+    global _sha1
+    if _sha1 is None:
+        try:
+            import hashlib
+            _sha1 = hashlib.sha1
+        except ImportError:
+            import sha
+            _sha1 = sha.sha
+    return _sha1(s)
+
 try:
     _encoding = os.environ.get("HGENCODING")
     if sys.platform == 'darwin' and not _encoding:
@@ -217,8 +243,8 @@
     return pipefilter(s, cmd)
 
 def binary(s):
-    """return true if a string is binary data using diff's heuristic"""
-    if s and '\0' in s[:4096]:
+    """return true if a string is binary data"""
+    if s and '\0' in s:
         return True
     return False
 
@@ -537,13 +563,29 @@
 
 _hgexecutable = None
 
+def main_is_frozen():
+    """return True if we are a frozen executable.
+
+    The code supports py2exe (most common, Windows only) and tools/freeze
+    (portable, not much used).
+    """
+    return (hasattr(sys, "frozen") or # new py2exe
+            hasattr(sys, "importers") or # old py2exe
+            imp.is_frozen("__main__")) # tools/freeze
+
 def hgexecutable():
     """return location of the 'hg' executable.
 
     Defaults to $HG or 'hg' in the search path.
     """
     if _hgexecutable is None:
-        set_hgexecutable(os.environ.get('HG') or find_exe('hg', 'hg'))
+        hg = os.environ.get('HG')
+        if hg:
+            set_hgexecutable(hg)
+        elif main_is_frozen():
+            set_hgexecutable(sys.executable)
+        else:
+            set_hgexecutable(find_exe('hg', 'hg'))
     return _hgexecutable
 
 def set_hgexecutable(path):
--- a/setup.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/setup.py	Sat Apr 12 21:34:01 2008 +0200
@@ -19,6 +19,9 @@
 import mercurial.version
 
 extra = {}
+scripts = ['hg']
+if os.name == 'nt':
+    scripts.append('contrib/win32/hg.bat')
 
 # simplified version of distutils.ccompiler.CCompiler.has_function
 # that actually removes its temporary files.
@@ -88,10 +91,11 @@
 cmdclass = {'install_data': install_package_data}
 
 ext_modules=[
-    Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
+    Extension('mercurial.base85', ['mercurial/base85.c']),
     Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
-    Extension('mercurial.base85', ['mercurial/base85.c']),
-    Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'])
+    Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
+    Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
+    Extension('mercurial.parsers', ['mercurial/parsers.c']),
     ]
 
 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert']
@@ -118,7 +122,7 @@
       url='http://selenic.com/mercurial',
       description='Scalable distributed SCM',
       license='GNU GPL',
-      scripts=['hg'],
+      scripts=scripts,
       packages=packages,
       ext_modules=ext_modules,
       data_files=[(os.path.join('mercurial', root),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/changeset.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,71 @@
+{header}
+<title>{repo|escape}: {node|short}</title>
+</head>
+<body>
+<div class="container">
+<div class="menu">
+<div class="logo">
+<a href="http://www.selenic.com/mercurial/">
+<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+</div>
+<ul>
+ <li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
+ <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
+</ul>
+<ul>
+ <li class="active">changeset</li>
+ <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">browse</a></li>
+</ul>
+<ul>
+ {archives%archiveentry}</ul>
+</ul>
+</div>
+
+<div class="main">
+
+<h2>{repo|escape}</h2>
+<h3>changeset {rev}:{node|short} {changesettag}</h3>
+
+<form class="search" action="{url}log">
+{sessionvars%hiddenformentry}
+<p><input name="rev" id="search1" type="text" size="30"></p>
+</form>
+
+<div class="description">{desc|strip|escape|addbreaks}</div>
+
+<table id="changesetEntry">
+<tr>
+ <th class="author">author</th>
+ <td class="author">{author|obfuscate}</td>
+</tr>
+<tr>
+ <th class="date">date</th>
+ <td class="date">{date|date} ({date|age} ago)</td></tr>
+<tr>
+ <th class="author">parents</th>
+ <td class="author">{parent%changesetparent}</td>
+</tr>
+<tr>
+ <th class="author">children</th>
+ <td class="author">{child%changesetchild}</td>
+</tr>
+<tr>
+ <th class="files">files</th>
+ <td class="files">{files}</td></tr>
+</tr>
+</table>
+<tr>
+
+<div class="overflow">
+<table class="bigtable">
+<tr>
+ <th class="lineno">line</th>
+ <th class="source">diff</th>
+</tr>
+</table>
+{diff}
+</div>
+</div>
+{footer}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/error.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,39 @@
+{header}
+<title>{repo|escape}: error</title>
+</head>
+<body>
+
+<div class="content">
+<div class="menu">
+<div class="logo">
+<a href="http://www.selenic.com/mercurial/">
+<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+</div>
+<ul>
+<li><a href="{url}log{sessionvars%urlparameter}">log</a></li>
+<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
+</ul>
+</div>
+
+<div class="main">
+
+<h2>{repo|escape}</h2>
+<h3>error</h3>
+
+<form class="search" action="{url}log">
+{sessionvars%hiddenformentry}
+<p><input name="rev" id="search1" type="text" size="30"></p>
+</form>
+
+<div class="description">
+<p>
+An error occurred while processing your request:
+</p>
+<p>
+{error|escape}
+</p>
+</div>
+</div>
+</div>
+
+{footer}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/fileannotate.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,76 @@
+{header}
+<title>{repo|escape}: {file|escape} annotate</title>
+</head>
+<body>
+
+<div class="container">
+<div class="menu">
+<div class="logo">
+<a href="http://www.selenic.com/mercurial/">
+<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+</div>
+<ul>
+<li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li>
+<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
+</ul>
+
+<ul>
+<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
+<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
+</ul>
+<ul>
+<li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
+<li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
+<li class="active">annotate</li>
+<li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file log</a></li>
+<li><a href="{url}raw-annotate/{node|short}/{file|urlescape}">raw</a></li>
+</ul>
+</div>
+
+<div class="main">
+<h2>{repo|escape}</h2>
+<h3>annotate {file|escape} @ {rev}:{node|short}</h2>
+
+<form class="search" action="{url}log">
+{sessionvars%hiddenformentry}
+<p><input name="rev" id="search1" type="text" size="30"></p>
+</form>
+
+<div class="description">{desc|strip|escape|addbreaks}</div>
+
+<table id="changesetEntry">
+<tr>
+ <th class="author">author</th>
+ <td class="author">{author|obfuscate}</td>
+</tr>
+<tr>
+ <th class="date">date</th>
+ <td class="date">{date|date} ({date|age} ago)</td>
+</tr>
+<tr>
+ <th class="author">parents</th>
+ <td class="author">{parent%filerevparent}</td>
+</tr>
+<tr>
+ <th class="author">children</th>
+ <td class="author">{child%filerevchild}</td>
+</tr>
+{changesettag}
+</table>
+
+<br/>
+
+<div class="overflow">
+<table class="bigtable">
+<tr>
+ <th class="annotate">rev</th>
+ <th class="lineno">line</th>
+ <th class="line">source</th>
+</tr>
+{annotate%annotateline}
+</table>
+</div>
+</div>
+</div>
+
+{footer}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/filediff.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,74 @@
+{header}
+<title>{repo|escape}: {file|escape} diff</title>
+</head>
+<body>
+
+<div class="container">
+<div class="menu">
+<div class="logo">
+<a href="http://www.selenic.com/mercurial/">
+<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+</div>
+<ul>
+<li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li>
+<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
+</ul>
+<ul>
+<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
+<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
+</ul>
+<ul>
+<li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
+<li class="active">diff</li>
+<li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
+<li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file log</a></li>
+<li><a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a></li>
+</ul>
+</div>
+
+<div class="main">
+<h2>{repo|escape}</h2>
+<h3>diff {file|escape} @ {rev}:{node|short}</h3>
+
+<form class="search" action="{url}log">
+{sessionvars%hiddenformentry}
+<p><input name="rev" id="search1" type="text" size="30"></p>
+</form>
+
+<div class="description">{desc|strip|escape|addbreaks}</div>
+
+<table id="changesetEntry">
+<tr>
+ <th>author</th>
+ <td>{author|obfuscate}</td>
+</tr>
+<tr>
+ <th>date</th>
+ <td>{date|date} ({date|age} ago)</td>
+</tr>
+<tr>
+ <th>parents</th>
+ <td>{parent%filerevparent}</td>
+</tr>
+<tr>
+ <th>children</th>
+ <td>{child%filerevchild}</td>
+</tr>
+{changesettag}
+</table>
+
+<div class="overflow">
+<table class="bigtable">
+<tr>
+ <th class="lineno">line</th>
+ <th class="source">diff</th>
+</tr>
+<table>
+{diff}
+</div>
+</div>	
+</div>
+
+{footer}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/filelog.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,58 @@
+{header}
+<title>{repo|escape}: {file|escape} history</title>
+<link rel="alternate" type="application/atom+xml"
+   href="{url}atom-log/tip/{file|urlescape}" title="Atom feed for {repo|escape}:{file}">
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log/tip/{file|urlescape}" title="RSS feed for {repo|escape}:{file}">
+</head>
+</head>
+<body>
+
+<div class="container">
+<div class="menu">
+<div class="logo">
+<a href="http://www.selenic.com/mercurial/">
+<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+</div>
+<ul>
+<li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li>
+<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
+</ul>
+<ul>
+<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
+<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
+</ul>
+<ul>
+<li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
+<li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
+<li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
+<li class="active">file log</li>
+<li><a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a></li>
+</ul>
+</div>
+
+<div class="main">
+
+<h2>{repo|escape}</h2>
+<h3>log {file|escape}</h3>
+
+<form class="search" action="{url}log">
+{sessionvars%hiddenformentry}
+<p><input name="rev" id="search1" type="text" size="30"></p>
+</form>
+
+<div class="navigate">{nav%filenaventry}</div>
+
+<table class="bigtable">
+ <tr> 
+  <th class="age">age</td>
+  <th class="author">author</td>
+  <th class="description">description</td>
+ </tr>
+{entries%filelogentry}
+</table>
+
+</div>
+</div>
+
+{footer}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/filelogentry.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,5 @@
+ <tr class="parity{parity}">
+  <td class="age">{date|age}</td>
+  <td class="author">{author|person}</td>
+  <td class="description"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape}</a></td>
+ </tr>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/filerevision.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,73 @@
+{header}
+<title>{repo|escape}: {node|short} {file|escape}</title>
+</head>
+<body>
+
+<div class="container">
+<div class="menu">
+<div class="logo">
+<a href="http://www.selenic.com/mercurial/">
+<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+</div>
+<ul>
+<li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li>
+<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
+</ul>
+<ul>
+<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
+<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
+</ul>
+<ul>
+<li class="active">file</li>
+<li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
+<li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
+<li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file log</a></li>
+<li><a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a></li>
+</ul>
+</div>
+
+<div class="main">
+
+<h2>{repo|escape}</h2>
+<h3>view {file|escape} @ {rev}:{node|short}</h3>
+
+<form class="search" action="{url}log">
+{sessionvars%hiddenformentry}
+<p><input name="rev" id="search1" type="text" size="30"></p>
+</form>
+
+<div class="description">{desc|strip|escape|addbreaks}</div>
+
+<table id="changesetEntry">
+<tr>
+ <th class="author">author</th>
+ <td class="author">{author|obfuscate}</td>
+</tr>
+<tr>
+ <th class="date">date</th>
+ <td class="date">{date|date} ({date|age} ago)</td>
+</tr>
+<tr>
+ <th class="author">parents</th>
+ <td class="author">{parent%filerevparent}</td>
+</tr>
+<tr>
+ <th class="author">children</th>
+ <td class="author">{child%filerevchild}</td>
+</tr>
+{changesettag}
+</table>
+
+<div class="overflow">
+<table class="bigtable">
+<tr>
+ <th class="lineno">line</th>
+ <th class="source">source</th>
+</tr>
+{text%fileline}
+</table>
+</div>
+</div>
+</div>
+
+{footer}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/footer.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,4 @@
+{motd}
+
+</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/header.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,7 @@
+<!-- quirksmode -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<link rel="icon" href="{staticurl}hgicon.png" type="image/png">
+<meta name="robots" content="index, nofollow" />
+<link rel="stylesheet" href="{staticurl}style-coal.css" type="text/css" />
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/index.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,19 @@
+{header}
+<title>Mercurial repositories index</title>
+</head>
+<body>
+
+<h2>Mercurial Repositories</h2>
+
+<table>
+    <tr>
+        <td><a href="?sort={sort_name}">Name</a></td>
+        <td><a href="?sort={sort_description}">Description</a></td>
+        <td><a href="?sort={sort_contact}">Contact</a></td>
+        <td><a href="?sort={sort_lastchange}">Last change</a></td>
+        <td>&nbsp;</td>
+    <tr>
+    {entries%indexentry}
+</table>
+
+{footer}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/manifest.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,51 @@
+{header}
+<title>{repo|escape}: {node|short} {path|escape}</title>
+</head>
+<body>
+
+<div class="container">
+<div class="menu">
+<div class="logo">
+<a href="http://www.selenic.com/mercurial/">
+<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+</div>
+<ul>
+<li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li>
+<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
+</ul>
+<ul>
+<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
+<li class="active">browse</li>
+</ul>
+<ul>
+{archives%archiveentry}
+</ul>
+</div>
+
+<div class="main">
+
+<h2>{repo|escape}</h2>
+<h3>directory {path|escape} @ {rev}:{node|short} {tags%changelogtag}</h3>
+
+<form class="search" action="{url}log">
+{sessionvars%hiddenformentry}
+<p><input name="rev" id="search1" type="text" size="30"></p>
+</form>
+
+<table class="bigtable">
+<tr>
+  <th class="name">name</th>
+  <th class="size">size</th>
+  <th class="permissions">permissions</th>
+</tr>
+<tr class="fileline parity{upparity}">
+  <td class="name"><a href="{url}file/{node|short}{up|urlescape}{sessionvars%urlparameter}">[up]</a></td>
+  <td class="size"></td>
+  <td class="permissions">drwxr-xr-x</td>
+</tr>
+{dentries%direntry}
+{fentries%fileentry}
+</table>
+</div>
+</div>
+{footer}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/map	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,69 @@
+default = 'shortlog'
+
+mimetype = 'text/html; charset={encoding}'
+header = header.tmpl
+footer = footer.tmpl
+search = search.tmpl
+
+changelog = shortlog.tmpl
+shortlog = shortlog.tmpl
+shortlogentry = shortlogentry.tmpl
+
+naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
+navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
+filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
+filedifflink = '<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
+filenodelink = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
+fileellipses = '...'
+changelogentry = shortlogentry.tmpl
+searchentry = shortlogentry.tmpl
+changeset = changeset.tmpl
+manifest = manifest.tmpl
+
+direntry = '<tr class="fileline parity{parity}"><td class="name"><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}"><img src="{staticurl}coal-folder.png"> {basename|escape}/</a><td class="size"></td><td class="permissions">drwxr-xr-x</td></tr>'
+fileentry = '<tr class="fileline parity{parity}"><td class="filename"><a href="{url}file/{node|short}/{file|urlescape}#l1{sessionvars%urlparameter}"><img src="{staticurl}coal-file.png"> {basename|escape}</a></td><td class="size">{size}</td><td class="permissions">{permissions|permissions}</td></tr>'
+
+filerevision = filerevision.tmpl
+fileannotate = fileannotate.tmpl
+filediff = filediff.tmpl
+filelog = filelog.tmpl
+fileline = '<tr class="parity{parity}"><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source">{line|escape}</td></tr>'
+filelogentry = filelogentry.tmpl
+
+annotateline = '<tr class="parity{parity}"><td class="annotate"><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#{targetline}">{author|obfuscate}@{rev}</a></td><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source">{line|escape}</td></tr>'
+
+diffblock = '<table class="bigtable parity{parity}">{lines}</table>'
+difflineplus = '<tr><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source plusline">{line|escape}</td></tr>'
+difflineminus = '<tr><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source minusline">{line|escape}</td></tr>'
+difflineat = '<tr><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source atline">{line|escape}</td></tr>'
+diffline = '<tr><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source">{line|escape}</td></tr>'
+
+changelogparent = '<tr><th class="parent">parent {rev}:</th><td class="parent"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
+
+changesetparent = '<a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a> '
+
+filerevparent = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a> '
+filerevchild = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a> '
+
+filerename = '{file|escape}@'
+filelogrename = '<tr><th>base:</th><td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}@{node|short}</a></td></tr>'
+fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
+changesetchild = '<a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
+changelogchild = '<tr><th class="child">child</th><td class="child"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
+fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
+tags = tags.tmpl
+tagentry = '<tr class="tagEntry parity{parity}"><td><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{tag|escape}</a></td><td class="node">{node|short}</td></tr>'
+changelogtag = '<tr><th class="tag">tag:</th><td class="tag">{tag|escape}</td></tr>'
+changelogtag = '<span class="tag">{name|escape}</span> '
+changesettag = '<span class="tag">{tag|escape}</span> '
+filediffparent = '<tr><th class="parent">parent {rev}:</th><td class="parent"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
+filelogparent = '<tr><th>parent {rev}:</th><td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
+filediffchild = '<tr><th class="child">child {rev}:</th><td class="child"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
+filelogchild = '<tr><th>child {rev}:</th><td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
+indexentry = '<tr class="parity{parity}"><td><a href="{url}{sessionvars%urlparameter}">{name|escape}</a></td><td>{description}</td><td>{contact|obfuscate}</td><td class="age">{lastchange|age} ago</td><td class="indexlinks"><a href="{url}rss-log">RSS</a> <a href="{url}atom-log">Atom</a> {archives%archiveentry}</td></tr>'
+index = index.tmpl
+archiveentry = '<li><a href="{url}archive/{node|short}{extension|urlescape}">{type|escape}</a></li>'
+notfound = notfound.tmpl
+error = error.tmpl
+urlparameter = '{separator}{name}={value|urlescape}'
+hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/notfound.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,12 @@
+{header}
+<title>Mercurial repository not found</title>
+</head>
+<body>
+
+<h2>Mercurial repository not found</h2>
+
+The specified repository "{repo|escape}" is unknown, sorry.
+
+Please go back to the main repository list page.
+
+{footer}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/search.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,40 @@
+{header}
+<title>{repo|escape}: searching for {query|escape}</title>
+</head>
+<body>
+
+<div class="container">
+<div class="menu">
+<div class="logo">
+<a href="http://www.selenic.com/mercurial/">
+<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+</div>
+<ul>
+<li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
+<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
+</ul>
+</div>
+
+<div class="main">
+
+<h2>{repo|escape}</h2>
+<h3>searching for '{query|escape}'</h3>
+
+<form class="search" action="{url}log">
+{sessionvars%hiddenformentry}
+<p><input name="rev" id="search1" type="text" size="30"></p>
+</form>
+
+<table class="bigtable">
+ <tr> 
+  <th class="age">age</td>
+  <th class="author">author</td>
+  <th class="description">description</td>
+ </tr>
+{entries}
+</table>
+
+</div>
+</div>
+
+{footer}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/shortlog.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,54 @@
+{header}
+<title>{repo|escape}: log</title>
+<link rel="alternate" type="application/atom+xml"
+   href="{url}atom-log" title="Atom feed for {repo|escape}">
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-log" title="RSS feed for {repo|escape}">
+</head>
+<body>
+
+<div class="container">
+<div class="menu">
+<div class="logo">
+<a href="http://www.selenic.com/mercurial/">
+<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+</div>
+<ul>
+<li class="active">log</li>
+<li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
+</ul>
+<ul>
+<li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
+<li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
+</ul>
+<ul>
+{archives%archiveentry}
+</ul>
+</div>
+
+<div class="main">
+
+<h2>{repo|escape}</h2>
+<h3>log</h3>
+
+<form class="search" action="{url}log">
+{sessionvars%hiddenformentry}
+<p><input name="rev" id="search1" type="text" size="30"></p>
+</form>
+
+<div class="navigate">rev {rev}: {changenav%navshortentry}</div>
+
+<table class="bigtable">
+ <tr> 
+  <th class="age">age</td>
+  <th class="author">author</td>
+  <th class="description">description</td>
+ </tr>
+{entries%shortlogentry}
+</table>
+
+<div class="navigate">rev {rev}: {changenav%navshortentry}</div>
+</div>
+</div>
+
+{footer}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/shortlogentry.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,5 @@
+ <tr class="parity{parity}">
+  <td class="age">{date|age}</td>
+  <td class="author">{author|person}</td>
+  <td class="description"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape}</a>{tags%changelogtag}</td>
+ </tr>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/coal/tags.tmpl	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,41 @@
+{header}
+<title>{repo|escape}: tags</title>
+<link rel="alternate" type="application/atom+xml"
+   href="{url}atom-tags" title="Atom feed for {repo|escape}: tags">
+<link rel="alternate" type="application/rss+xml"
+   href="{url}rss-tags" title="RSS feed for {repo|escape}: tags">
+</head>
+<body>
+
+<div class="container">
+<div class="menu">
+<div class="logo">
+<a href="http://www.selenic.com/mercurial/">
+<img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+</div>
+<ul>
+<li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
+<li class="active">tags</li>
+</ul>
+</div>
+
+<div class="main">
+<h2>{repo|escape}</h2>
+<h3>tags</h3>
+
+<form class="search" action="{url}log">
+{sessionvars%hiddenformentry}
+<p><input name="rev" id="search1" type="text" size="30"></p>
+</form>
+
+<table class="bigtable">
+<tr>
+ <th>tag</th>
+ <th>node</th>
+</tr>
+{entries%tagentry}
+</table>
+</div>
+</div>
+
+{footer}
Binary file templates/static/background.png has changed
Binary file templates/static/coal-file.png has changed
Binary file templates/static/coal-folder.png has changed
Binary file templates/static/hgicon.png has changed
Binary file templates/static/hglogo.png has changed
--- a/templates/static/highlight.css	Sat Apr 12 21:08:03 2008 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-.c { color: #808080 } /* Comment */
-.err { color: #F00000; background-color: #F0A0A0 } /* Error */
-.k { color: #008000; font-weight: bold } /* Keyword */
-.o { color: #303030 } /* Operator */
-.cm { color: #808080 } /* Comment.Multiline */
-.cp { color: #507090 } /* Comment.Preproc */
-.c1 { color: #808080 } /* Comment.Single */
-.cs { color: #cc0000; font-weight: bold } /* Comment.Special */
-.gd { color: #A00000 } /* Generic.Deleted */
-.ge { font-style: italic } /* Generic.Emph */
-.gr { color: #FF0000 } /* Generic.Error */
-.gh { color: #000080; font-weight: bold } /* Generic.Heading */
-.gi { color: #00A000 } /* Generic.Inserted */
-.go { color: #808080 } /* Generic.Output */
-.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
-.gs { font-weight: bold } /* Generic.Strong */
-.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
-.gt { color: #0040D0 } /* Generic.Traceback */
-.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
-.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
-.kp { color: #003080; font-weight: bold } /* Keyword.Pseudo */
-.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
-.kt { color: #303090; font-weight: bold } /* Keyword.Type */
-.m { color: #6000E0; font-weight: bold } /* Literal.Number */
-.s { background-color: #fff0f0 } /* Literal.String */
-.na { color: #0000C0 } /* Name.Attribute */
-.nb { color: #007020 } /* Name.Builtin */
-.nc { color: #B00060; font-weight: bold } /* Name.Class */
-.no { color: #003060; font-weight: bold } /* Name.Constant */
-.nd { color: #505050; font-weight: bold } /* Name.Decorator */
-.ni { color: #800000; font-weight: bold } /* Name.Entity */
-.ne { color: #F00000; font-weight: bold } /* Name.Exception */
-.nf { color: #0060B0; font-weight: bold } /* Name.Function */
-.nl { color: #907000; font-weight: bold } /* Name.Label */
-.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
-.nt { color: #007000 } /* Name.Tag */
-.nv { color: #906030 } /* Name.Variable */
-.ow { color: #000000; font-weight: bold } /* Operator.Word */
-.w { color: #bbbbbb } /* Text.Whitespace */
-.mf { color: #6000E0; font-weight: bold } /* Literal.Number.Float */
-.mh { color: #005080; font-weight: bold } /* Literal.Number.Hex */
-.mi { color: #0000D0; font-weight: bold } /* Literal.Number.Integer */
-.mo { color: #4000E0; font-weight: bold } /* Literal.Number.Oct */
-.sb { background-color: #fff0f0 } /* Literal.String.Backtick */
-.sc { color: #0040D0 } /* Literal.String.Char */
-.sd { color: #D04020 } /* Literal.String.Doc */
-.s2 { background-color: #fff0f0 } /* Literal.String.Double */
-.se { color: #606060; font-weight: bold; background-color: #fff0f0 } /* Literal.String.Escape */
-.sh { background-color: #fff0f0 } /* Literal.String.Heredoc */
-.si { background-color: #e0e0e0 } /* Literal.String.Interpol */
-.sx { color: #D02000; background-color: #fff0f0 } /* Literal.String.Other */
-.sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */
-.s1 { background-color: #fff0f0 } /* Literal.String.Single */
-.ss { color: #A06000 } /* Literal.String.Symbol */
-.bp { color: #007020 } /* Name.Builtin.Pseudo */
-.vc { color: #306090 } /* Name.Variable.Class */
-.vg { color: #d07000; font-weight: bold } /* Name.Variable.Global */
-.vi { color: #3030B0 } /* Name.Variable.Instance */
-.il { color: #0000D0; font-weight: bold } /* Literal.Number.Integer.Long */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/static/style-coal.css	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,156 @@
+body {
+  margin: 0;
+  padding: 0;
+  background: black url(background.png) repeat-x;
+  font-family: sans-serif;
+}
+
+.container {
+  padding-right: 150px;
+}
+
+.main {
+  position: relative;
+  background: white;
+  padding: 2em;
+  border-right: 15px solid black;
+  border-bottom: 15px solid black;
+}
+
+.overflow {
+  width: 100%;
+  overflow: auto;
+}
+
+.menu {
+  background: #999;
+  padding: 10px;
+  width: 75px;
+  margin: 0;
+  font-size: 80%;
+  text-align: left;
+  position: fixed;
+  top: 27px;
+  left: auto;
+  right: 27px;
+}
+
+.menu ul {
+  list-style: none;
+  padding: 0;
+  margin: 10px 0 0 0;
+}
+
+.menu li {
+  margin-bottom: 3px;
+  padding: 2px 4px;
+  background: white;
+  color: black;
+  font-weight: normal;
+}
+
+.menu li.active {
+  background: black;
+  color: white;
+}
+
+.menu a { color: black; display: block; }
+
+.search {
+  position: absolute;
+  top: .7em;
+  right: 2em;
+}
+
+a { text-decoration:none; }
+.age { white-space:nowrap; }
+.date { white-space:nowrap; }
+.indexlinks { white-space:nowrap; }
+.parity0 { background-color: #f5f5f5; }
+.parity1 { background-color: white; }
+.plusline { color: green; }
+.minusline { color: red; }
+.atline { color: purple; }
+
+.navigate {
+  text-align: right;
+  font-size: 60%;
+  margin: 1em 0 1em 0;
+}
+
+.tag {
+  color: #999;
+  font-size: 70%;
+  font-weight: normal;
+  margin-left: .5em;
+  vertical-align: text-baseline;
+}
+
+/* Common */
+pre { margin: 0; }
+
+h2 { font-size: 120%; border-bottom: 1px solid #999; }
+h3 {
+  margin-top: -.7em;
+  font-size: 100%;
+}
+
+/* log and tags tables */
+.bigtable {
+  border-bottom: 1px solid #999;
+  border-collapse: collapse;
+  font-size: 90%;
+  width: 100%; 
+  font-weight: normal;
+  text-align: left;
+}
+
+.bigtable td {
+  padding: 1px 4px 1px 4px;
+  vertical-align: top;
+}
+
+.bigtable th { 
+  padding: 1px 4px 1px 4px;
+  border-bottom: 1px solid #999; 
+  font-size: smaller;
+}
+.bigtable tr { border: none; }
+.bigtable .age { width: 6em; }
+.bigtable .author { width: 10em; }
+.bigtable .description { }
+.bigtable .node { width: 5em; font-family: monospace;}
+.bigtable .lineno { width: 2em; text-align: right;}
+.bigtable .lineno a { color: #999; font-size: smaller; font-family: monospace;}
+.bigtable td.source { font-family: monospace; white-space: pre; }
+.bigtable .permissions { width: 8em; text-align: left;}
+.bigtable .size { width: 5em; text-align: right; }
+.bigtable .annotate { text-align: right; padding-right: }
+.bigtable td.annotate { font-size: smaller; }
+
+.fileline { font-family: monospace; }
+.fileline img { border: 0; }
+
+/* Changeset entry */
+#changesetEntry { 
+  border-collapse: collapse;
+  font-size: 90%;
+  width: 100%;
+  margin-bottom: 1em;
+}
+
+#changesetEntry th { 
+  padding: 1px 4px 1px 4px;
+  width: 4em;
+  text-align: right;
+  font-weight: normal;
+  color: #999;
+  margin-right: .5em;
+  vertical-align: top;
+}
+
+div.description {
+  border-left: 3px solid #999;
+  margin: 1em 0 1em 0;
+  padding: .3em;
+}
--- a/tests/md5sum.py	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/md5sum.py	Sat Apr 12 21:34:01 2008 +0200
@@ -7,7 +7,11 @@
 # GPL-compatible.
 
 import sys
-import md5
+
+try:
+    from hashlib import md5
+except ImportError:
+    from md5 import md5
 
 for filename in sys.argv[1:]:
     try:
@@ -16,7 +20,7 @@
         sys.stderr.write('%s: Can\'t open: %s\n' % (filename, msg))
         sys.exit(1)
 
-    m = md5.new()
+    m = md5()
     try:
         while 1:
             data = fp.read(8192)
--- a/tests/test-add.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-add.out	Sat Apr 12 21:34:01 2008 +0200
@@ -18,9 +18,7 @@
 warning: conflicts during merge.
 merging a failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-There are unresolved merges, you can redo the full merge using:
-  hg update -C 2
-  hg merge 1
+use 'hg resolve' to retry unresolved file merges
 M a
 ? a.orig
 % should fail
--- a/tests/test-archive	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-archive	Sat Apr 12 21:34:01 2008 +0200
@@ -40,10 +40,11 @@
 gzip -dc test-$QTIP.tar.gz | tar tf - | sed "s/$QTIP/TIP/"
 
 cat > md5comp.py <<EOF
-import md5, sys
+from mercurial.util import md5
+import sys
 f1, f2 = sys.argv[1:3]
-h1 = md5.md5(file(f1, 'rb').read()).hexdigest()
-h2 = md5.md5(file(f2, 'rb').read()).hexdigest()
+h1 = md5(file(f1, 'rb').read()).hexdigest()
+h2 = md5(file(f2, 'rb').read()).hexdigest()
 print h1 == h2 or "md5 differ: " + repr((h1, h2))
 EOF
 
--- a/tests/test-churn	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-churn	Sat Apr 12 21:34:01 2008 +0200
@@ -3,6 +3,8 @@
 echo "[extensions]" >> $HGRCPATH
 echo "churn=" >> $HGRCPATH
 
+COLUMNS=80; export COLUMNS
+
 echo % create test repository
 hg init repo
 cd repo
--- a/tests/test-conflict.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-conflict.out	Sat Apr 12 21:34:01 2008 +0200
@@ -4,9 +4,7 @@
 warning: conflicts during merge.
 merging a failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-There are unresolved merges, you can redo the full merge using:
-  hg update -C 2
-  hg merge 1
+use 'hg resolve' to retry unresolved file merges
 e7fe8eb3e180+0d24b7662d3e+ tip
 <<<<<<< local
 something else
--- a/tests/test-convert-hg-source.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-convert-hg-source.out	Sat Apr 12 21:34:01 2008 +0200
@@ -1,9 +1,9 @@
 created new head
-merging baz and foo
+merging baz and foo to baz
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
-merging foo and baz
+merging foo and baz to baz
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 created new head
--- a/tests/test-convert-svn-sink.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-convert-svn-sink.out	Sat Apr 12 21:34:01 2008 +0200
@@ -265,9 +265,7 @@
 warning: conflicts during merge.
 merging b failed!
 2 files updated, 0 files merged, 0 files removed, 1 files unresolved
-There are unresolved merges, you can redo the full merge using:
-  hg update -C 2
-  hg merge 4
+use 'hg resolve' to retry unresolved file merges
 assuming destination b-hg
 initializing svn repo 'b-hg'
 initializing svn wc 'b-hg-wc'
--- a/tests/test-copy-move-merge.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-copy-move-merge.out	Sat Apr 12 21:34:01 2008 +0200
@@ -12,16 +12,16 @@
   checking for directory renames
  a: remote moved to c -> m
  a: remote moved to b -> m
-copying a to b
-copying a to c
-picked tool 'internal:merge' for a (binary False symlink False)
-merging a and b
-my a@fb3948d97f07+ other b@40da226db0f0 ancestor a@583c7b748052
+preserving a for resolve of b
+preserving a for resolve of c
+removing a
+picked tool 'internal:merge' for b (binary False symlink False)
+merging a and b to b
+my b@fb3948d97f07+ other b@40da226db0f0 ancestor a@583c7b748052
  premerge successful
-removing a
-picked tool 'internal:merge' for a (binary False symlink False)
-merging a and c
-my a@fb3948d97f07+ other c@40da226db0f0 ancestor a@583c7b748052
+picked tool 'internal:merge' for c (binary False symlink False)
+merging a and c to c
+my c@fb3948d97f07+ other c@40da226db0f0 ancestor a@583c7b748052
  premerge successful
 0 files updated, 2 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
--- a/tests/test-debugcomplete.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-debugcomplete.out	Sat Apr 12 21:34:01 2008 +0200
@@ -33,6 +33,7 @@
 recover
 remove
 rename
+resolve
 revert
 rollback
 root
@@ -79,6 +80,7 @@
 recover
 remove
 rename
+resolve
 revert
 rollback
 root
--- a/tests/test-dispatch.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-dispatch.out	Sat Apr 12 21:34:01 2008 +0200
@@ -10,7 +10,7 @@
     or tip if no revision is checked out.
 
     Output may be to a file, in which case the name of the file is
-    given using a format string.  The formatting rules are the same as
+    given using a format string. The formatting rules are the same as
     for the export command, with the following additions:
 
     %s   basename of file being printed
--- a/tests/test-double-merge.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-double-merge.out	Sat Apr 12 21:34:01 2008 +0200
@@ -10,10 +10,11 @@
   checking for directory renames
  foo: versions differ -> m
  foo: remote copied to bar -> m
-copying foo to bar
-picked tool 'internal:merge' for foo (binary False symlink False)
-merging foo and bar
-my foo@2092631ce82b+ other bar@7731dad1c2b9 ancestor foo@310fd17130da
+preserving foo for resolve of bar
+preserving foo for resolve of foo
+picked tool 'internal:merge' for bar (binary False symlink False)
+merging foo and bar to bar
+my bar@2092631ce82b+ other bar@7731dad1c2b9 ancestor foo@310fd17130da
  premerge successful
 picked tool 'internal:merge' for foo (binary False symlink False)
 merging foo
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-dumprevlog	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+CONTRIBDIR=$TESTDIR/../contrib
+
+mkdir repo-a
+cd repo-a
+hg init
+
+echo this is file a > a
+hg add a
+hg commit -m first -d '0 0'
+
+echo adding to file a >> a
+hg commit -m second -d '0 0'
+
+echo adding more to file a >> a
+hg commit -m third -d '0 0'
+
+hg verify
+
+echo dumping revlog of file a to stdout:
+python $CONTRIBDIR/dumprevlog .hg/store/data/a.i
+echo dumprevlog done
+
+# dump all revlogs to file repo.dump
+find .hg/store -name "*.i" | sort | xargs python $CONTRIBDIR/dumprevlog > ../repo.dump
+
+cd ..
+
+mkdir repo-b
+cd repo-b
+hg init
+
+echo undumping:
+python $CONTRIBDIR/undumprevlog < ../repo.dump
+echo undumping done
+
+hg verify
+
+cd ..
+
+echo comparing repos:
+hg -R repo-b incoming repo-a
+hg -R repo-a incoming repo-b
+echo comparing done
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-dumprevlog.out	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,53 @@
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 3 total revisions
+dumping revlog of file a to stdout:
+file: .hg/store/data/a.i
+node: 183d2312b35066fb6b3b449b84efc370d50993d0
+linkrev: 0
+parents: 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
+length: 15
+-start-
+this is file a
+
+-end-
+node: b1047953b6e6b633c0d8197eaa5116fbdfd3095b
+linkrev: 1
+parents: 183d2312b35066fb6b3b449b84efc370d50993d0 0000000000000000000000000000000000000000
+length: 32
+-start-
+this is file a
+adding to file a
+
+-end-
+node: 8c4fd1f7129b8cdec6c7f58bf48fb5237a4030c1
+linkrev: 2
+parents: b1047953b6e6b633c0d8197eaa5116fbdfd3095b 0000000000000000000000000000000000000000
+length: 54
+-start-
+this is file a
+adding to file a
+adding more to file a
+
+-end-
+dumprevlog done
+undumping:
+.hg/store/00changelog.i
+.hg/store/00manifest.i
+.hg/store/data/a.i
+undumping done
+checking changesets
+checking manifests
+crosschecking files in changesets and manifests
+checking files
+1 files, 3 changesets, 3 total revisions
+comparing repos:
+comparing with repo-a
+searching for changes
+no changes found
+comparing with repo-b
+searching for changes
+no changes found
+comparing done
--- a/tests/test-globalopts.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-globalopts.out	Sat Apr 12 21:34:01 2008 +0200
@@ -183,6 +183,7 @@
  recover      roll back an interrupted transaction
  remove       remove the specified files on the next commit
  rename       rename files; equivalent of copy + remove
+ resolve      resolve file merges from a branch merge or update
  revert       restore individual files or dirs to an earlier state
  rollback     roll back the last transaction
  root         print the root (top) of the current working dir
@@ -236,6 +237,7 @@
  recover      roll back an interrupted transaction
  remove       remove the specified files on the next commit
  rename       rename files; equivalent of copy + remove
+ resolve      resolve file merges from a branch merge or update
  revert       restore individual files or dirs to an earlier state
  rollback     roll back the last transaction
  root         print the root (top) of the current working dir
--- a/tests/test-help.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-help.out	Sat Apr 12 21:34:01 2008 +0200
@@ -74,6 +74,7 @@
  recover      roll back an interrupted transaction
  remove       remove the specified files on the next commit
  rename       rename files; equivalent of copy + remove
+ resolve      resolve file merges from a branch merge or update
  revert       restore individual files or dirs to an earlier state
  rollback     roll back the last transaction
  root         print the root (top) of the current working dir
@@ -123,6 +124,7 @@
  recover      roll back an interrupted transaction
  remove       remove the specified files on the next commit
  rename       rename files; equivalent of copy + remove
+ resolve      resolve file merges from a branch merge or update
  revert       restore individual files or dirs to an earlier state
  rollback     roll back the last transaction
  root         print the root (top) of the current working dir
@@ -216,10 +218,10 @@
 
 show changed files in the working directory
 
-    Show status of files in the repository.  If names are given, only
-    files that match are shown.  Files that are clean or ignored or
+    Show status of files in the repository. If names are given, only
+    files that match are shown. Files that are clean or ignored or
     source of a copy/move operation, are not listed unless -c (clean),
-    -i (ignored), -C (copies) or -A is given.  Unless options described
+    -i (ignored), -C (copies) or -A is given. Unless options described
     with "show only ..." are given, the options -mardu are used.
 
     Option -q/--quiet hides untracked (unknown and ignored) files
--- a/tests/test-highlight	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-highlight	Sat Apr 12 21:34:01 2008 +0200
@@ -5,6 +5,8 @@
 cat <<EOF >> $HGRCPATH
 [extensions]
 hgext.highlight =
+[web]
+pygments_style = friendly
 EOF
 
 hg init test
@@ -24,6 +26,28 @@
 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/annotate/tip/get-with-headers.py') \
     | sed "s/[0-9]* years ago/long ago/g"
 
+echo % hgweb highlightcss friendly
+("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/highlightcss') \
+    | head -n 4
+
+echo % errors encountered
+cat errors.log
+kill `cat hg.pid`
+
+# Change the pygments style
+cat > .hg/hgrc <<EOF
+[web]
+pygments_style = fruity
+EOF
+
+echo % hg serve again
+hg serve -p $HGPORT -d -n test --pid-file=hg.pid -A access.log -E errors.log
+cat hg.pid >> $DAEMON_PIDS
+
+echo % hgweb highlightcss fruity
+("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/highlightcss') \
+    | head -n 4
+
 echo % errors encountered
 cat errors.log
 
--- a/tests/test-highlight.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-highlight.out	Sat Apr 12 21:34:01 2008 +0200
@@ -10,7 +10,7 @@
 <meta name="robots" content="index, nofollow" />
 <link rel="stylesheet" href="/static/style.css" type="text/css" />
 
-<link rel="stylesheet" href="/static/highlight.css" type="text/css" />
+<link rel="stylesheet" href="/highlightcss" type="text/css" />
 <title>test:get-with-headers.py</title>
 </head>
 <body>
@@ -72,7 +72,7 @@
 <meta name="robots" content="index, nofollow" />
 <link rel="stylesheet" href="/static/style.css" type="text/css" />
 
-<link rel="stylesheet" href="/static/highlight.css" type="text/css" />
+<link rel="stylesheet" href="/highlightcss" type="text/css" />
 <title>test: get-with-headers.py annotate</title>
 </head>
 <body>
@@ -126,4 +126,16 @@
 </body>
 </html>
 
+% hgweb highlightcss friendly
+200 Script output follows
+
+/* pygments_style = friendly */
+
 % errors encountered
+% hg serve again
+% hgweb highlightcss fruity
+200 Script output follows
+
+/* pygments_style = fruity */
+
+% errors encountered
--- a/tests/test-issue612.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-issue612.out	Sat Apr 12 21:34:01 2008 +0200
@@ -3,7 +3,7 @@
 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
 created new head
 ? src/a.o
-merging src/a.c and source/a.c
+merging src/a.c and source/a.c to source/a.c
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 M source/a.c
--- a/tests/test-issue672.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-issue672.out	Sat Apr 12 21:34:01 2008 +0200
@@ -30,8 +30,9 @@
    1a -> 1 *
   checking for directory renames
  1a: local moved to 1 -> m
+preserving 1a for resolve of 1a
 picked tool 'internal:merge' for 1a (binary False symlink False)
-merging 1a and 1
+merging 1a and 1 to 1a
 my 1a@ac7575e3c052+ other 1@746e9549ea96 ancestor 1@81f4b099af3d
  premerge successful
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
@@ -47,11 +48,11 @@
    1a -> 1 *
   checking for directory renames
  1: remote moved to 1a -> m
-copying 1 to 1a
-picked tool 'internal:merge' for 1 (binary False symlink False)
-merging 1 and 1a
-my 1@746e9549ea96+ other 1a@ac7575e3c052 ancestor 1@81f4b099af3d
+preserving 1 for resolve of 1a
+removing 1
+picked tool 'internal:merge' for 1a (binary False symlink False)
+merging 1 and 1a to 1a
+my 1a@746e9549ea96+ other 1a@ac7575e3c052 ancestor 1@81f4b099af3d
  premerge successful
-removing 1
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mactext	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+cat > unix2mac.py <<EOF
+import sys
+
+for path in sys.argv[1:]:
+    data = file(path, 'rb').read()
+    data = data.replace('\n', '\r')
+    file(path, 'wb').write(data)
+EOF
+
+cat > print.py <<EOF
+import sys
+print(sys.stdin.read().replace('\n', '<LF>').replace('\r', '<CR>').replace('\0', '<NUL>'))
+EOF
+
+hg init
+echo '[hooks]' >> .hg/hgrc
+echo 'pretxncommit.cr = python:hgext.win32text.forbidcr' >> .hg/hgrc
+echo 'pretxnchangegroup.cr = python:hgext.win32text.forbidcr' >> .hg/hgrc
+cat .hg/hgrc
+echo
+
+echo hello > f
+hg add f
+hg ci -m 1 -d'0 0'
+echo
+
+python unix2mac.py f
+hg ci -m 2 -d'0 0'
+hg cat f | python print.py
+cat f | python print.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-mactext.out	Sat Apr 12 21:34:01 2008 +0200
@@ -0,0 +1,12 @@
+[hooks]
+pretxncommit.cr = python:hgext.win32text.forbidcr
+pretxnchangegroup.cr = python:hgext.win32text.forbidcr
+
+
+Attempt to commit or push text file(s) using CR line endings
+in dea860dc51ec: f
+transaction abort!
+rollback completed
+abort: pretxncommit.cr hook failed
+hello<LF>
+hello<CR>
--- a/tests/test-merge-commit.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-merge-commit.out	Sat Apr 12 21:34:01 2008 +0200
@@ -1,6 +1,6 @@
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
 created new head
-merging bar and foo
+merging bar and foo to bar
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 % contents of bar should be line0 line1 line2
@@ -27,6 +27,7 @@
  ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 7d3b554bfdf1
   searching for copies back to rev 1
  bar: versions differ -> m
+preserving bar for resolve of bar
 picked tool 'internal:merge' for bar (binary False symlink False)
 merging bar
 my bar@2d2f9a22c82b+ other bar@7d3b554bfdf1 ancestor bar@0a3ab4856510
@@ -49,7 +50,7 @@
 adding file changes
 added 3 changesets with 3 changes to 2 files (+1 heads)
 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-merging foo and bar
+merging foo and bar to bar
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 % contents of bar should be line0 line1 line2
@@ -76,6 +77,7 @@
  ancestor 0a3ab4856510 local 2d2f9a22c82b+ remote 96ab80c60897
   searching for copies back to rev 1
  bar: versions differ -> m
+preserving bar for resolve of bar
 picked tool 'internal:merge' for bar (binary False symlink False)
 merging bar
 my bar@2d2f9a22c82b+ other bar@96ab80c60897 ancestor bar@0a3ab4856510
--- a/tests/test-merge-local.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-merge-local.out	Sat Apr 12 21:34:01 2008 +0200
@@ -21,10 +21,7 @@
 merging zzz2_merge_bad
 merging zzz2_merge_bad failed!
 3 files updated, 1 files merged, 2 files removed, 1 files unresolved
-There are unresolved merges with locally modified files.
-You can finish the partial merge using:
-  hg update 0
-  hg update 1
+use 'hg resolve' to retry unresolved file merges
 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
 --- a/zzz1_merge_ok
 +++ b/zzz1_merge_ok
@@ -42,10 +39,7 @@
 warning: conflicts during merge.
 merging zzz2_merge_bad failed!
 3 files updated, 1 files merged, 2 files removed, 1 files unresolved
-There are unresolved merges with locally modified files.
-You can finish the partial merge using:
-  hg update 0
-  hg update 1
+use 'hg resolve' to retry unresolved file merges
 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
 --- a/zzz1_merge_ok
 +++ b/zzz1_merge_ok
--- a/tests/test-merge-remove.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-merge-remove.out	Sat Apr 12 21:34:01 2008 +0200
@@ -1,5 +1,5 @@
 created new head
-merging foo1 and foo
+merging foo1 and foo to foo1
 1 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 n   0         -2 bar
--- a/tests/test-merge-revert2.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-merge-revert2.out	Sat Apr 12 21:34:01 2008 +0200
@@ -13,10 +13,7 @@
 warning: conflicts during merge.
 merging file1 failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-There are unresolved merges with locally modified files.
-You can redo the full merge using:
-  hg update 0
-  hg update 1
+use 'hg resolve' to retry unresolved file merges
 diff -r f248da0d4c3e file1
 --- a/file1
 +++ b/file1
--- a/tests/test-merge10.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-merge10.out	Sat Apr 12 21:34:01 2008 +0200
@@ -8,7 +8,7 @@
 added 1 changesets with 1 changes to 1 files (+1 heads)
 (run 'hg heads' to see heads, 'hg merge' to merge)
 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
-merging testdir/subdir/a and testdir/a
+merging testdir/subdir/a and testdir/a to testdir/subdir/a
 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
 (branch merge, don't forget to commit)
 M testdir/subdir/a
--- a/tests/test-merge7.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-merge7.out	Sat Apr 12 21:34:01 2008 +0200
@@ -11,9 +11,7 @@
 warning: conflicts during merge.
 merging test.txt failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-There are unresolved merges, you can redo the full merge using:
-  hg update -C 1
-  hg merge 2
+use 'hg resolve' to retry unresolved file merges
 pulling from ../test-a
 searching for changes
 adding changesets
@@ -26,15 +24,14 @@
  ancestor faaea63e63a9 local 451c744aabcc+ remote a070d41e8360
   searching for copies back to rev 1
  test.txt: versions differ -> m
+preserving test.txt for resolve of test.txt
 picked tool 'internal:merge' for test.txt (binary False symlink False)
 merging test.txt
 my test.txt@451c744aabcc+ other test.txt@a070d41e8360 ancestor test.txt@faaea63e63a9
 warning: conflicts during merge.
 merging test.txt failed!
 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
-There are unresolved merges, you can redo the full merge using:
-  hg update -C 3
-  hg merge 4
+use 'hg resolve' to retry unresolved file merges
 one
 <<<<<<< local
 two-point-five
--- a/tests/test-merge9	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-merge9	Sat Apr 12 21:34:01 2008 +0200
@@ -23,9 +23,31 @@
 
 # test with the rename on the remote side
 HGMERGE=false hg merge
+hg resolve -l
 
 # test with the rename on the local side
 hg up -C 1
 HGMERGE=false hg merge
 
+echo % show unresolved
+hg resolve -l
+
+echo % unmark baz
+hg resolve -u baz
+
+echo % show
+hg resolve -l
+
+echo % re-resolve baz
+hg resolve baz
+
+echo % after
+hg resolve -l
+
+echo % resolve all
+hg resolve
+
+echo % after
+hg resolve -l
+
 true
--- a/tests/test-merge9.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-merge9.out	Sat Apr 12 21:34:01 2008 +0200
@@ -5,16 +5,33 @@
 created new head
 merging bar
 merging bar failed!
-merging foo and baz
+merging foo and baz to baz
 1 files updated, 1 files merged, 0 files removed, 1 files unresolved
-There are unresolved merges, you can redo the full merge using:
-  hg update -C 2
-  hg merge 1
+use 'hg resolve' to retry unresolved file merges
+U bar
+R baz
 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
 merging bar
 merging bar failed!
-merging baz and foo
+merging baz and foo to baz
 1 files updated, 1 files merged, 0 files removed, 1 files unresolved
-There are unresolved merges, you can redo the full merge using:
-  hg update -C 1
-  hg merge 2
+use 'hg resolve' to retry unresolved file merges
+% show unresolved
+U bar
+R baz
+% unmark baz
+% show
+U bar
+U baz
+% re-resolve baz
+merging baz and foo to baz
+% after
+U bar
+R baz
+% resolve all
+merging bar
+warning: conflicts during merge.
+merging bar failed!
+% after
+U bar
+R baz
--- a/tests/test-mq	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-mq	Sat Apr 12 21:34:01 2008 +0200
@@ -266,6 +266,14 @@
 hg strip tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
 hg unbundle .hg/strip-backup/*
 
+echo % strip with local changes, should complain
+hg up
+echo y>y
+hg add y
+hg strip tip | sed 's/\(saving bundle to \).*/\1/'
+echo % --force strip with local changes
+hg strip -f tip 2>&1 | sed 's/\(saving bundle to \).*/\1/'
+
 echo '% cd b; hg qrefresh'
 hg init refresh
 cd refresh
--- a/tests/test-mq.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-mq.out	Sat Apr 12 21:34:01 2008 +0200
@@ -250,6 +250,12 @@
 adding file changes
 added 1 changesets with 1 changes to 1 files
 (run 'hg update' to get a working copy)
+% strip with local changes, should complain
+1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+abort: local changes found
+% --force strip with local changes
+0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+saving bundle to 
 % cd b; hg qrefresh
 adding a
 foo
--- a/tests/test-rename-merge1.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-rename-merge1.out	Sat Apr 12 21:34:01 2008 +0200
@@ -19,12 +19,12 @@
  a2: divergent renames -> dr
  a: remote moved to b -> m
  b2: remote created -> g
-copying a to b
-picked tool 'internal:merge' for a (binary False symlink False)
-merging a and b
-my a@f26ec4fc3fa3+ other b@8e765a822af2 ancestor a@af1939970a1c
+preserving a for resolve of b
+removing a
+picked tool 'internal:merge' for b (binary False symlink False)
+merging a and b to b
+my b@f26ec4fc3fa3+ other b@8e765a822af2 ancestor a@af1939970a1c
  premerge successful
-removing a
 warning: detected divergent renames of a2 to:
  c2
  b2
--- a/tests/test-rename-merge2.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-rename-merge2.out	Sat Apr 12 21:34:01 2008 +0200
@@ -13,10 +13,11 @@
   checking for directory renames
  rev: versions differ -> m
  a: remote copied to b -> m
-copying a to b
-picked tool 'python ../merge' for a (binary False symlink False)
-merging a and b
-my a@e300d1c794ec+ other b@735846fee2d7 ancestor a@924404dff337
+preserving a for resolve of b
+preserving rev for resolve of rev
+picked tool 'python ../merge' for b (binary False symlink False)
+merging a and b to b
+my b@e300d1c794ec+ other b@735846fee2d7 ancestor a@924404dff337
  premerge successful
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
@@ -45,9 +46,11 @@
  a: remote is newer -> g
  b: local copied to a -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 getting a
 picked tool 'python ../merge' for b (binary False symlink False)
-merging b and a
+merging b and a to b
 my b@ac809aeed39a+ other a@f4db7e329e71 ancestor a@924404dff337
  premerge successful
 picked tool 'python ../merge' for rev (binary False symlink False)
@@ -76,12 +79,13 @@
   checking for directory renames
  rev: versions differ -> m
  a: remote moved to b -> m
-copying a to b
-picked tool 'python ../merge' for a (binary False symlink False)
-merging a and b
-my a@e300d1c794ec+ other b@e03727d2d66b ancestor a@924404dff337
+preserving a for resolve of b
+preserving rev for resolve of rev
+removing a
+picked tool 'python ../merge' for b (binary False symlink False)
+merging a and b to b
+my b@e300d1c794ec+ other b@e03727d2d66b ancestor a@924404dff337
  premerge successful
-removing a
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
 my rev@e300d1c794ec+ other rev@e03727d2d66b ancestor rev@924404dff337
@@ -107,8 +111,10 @@
   checking for directory renames
  b: local moved to a -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
-merging b and a
+merging b and a to b
 my b@ecf3cb2a4219+ other a@f4db7e329e71 ancestor a@924404dff337
  premerge successful
 picked tool 'python ../merge' for rev (binary False symlink False)
@@ -136,6 +142,7 @@
   checking for directory renames
  rev: versions differ -> m
  b: remote created -> g
+preserving rev for resolve of rev
 getting b
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
@@ -161,6 +168,7 @@
    b -> a 
   checking for directory renames
  rev: versions differ -> m
+preserving rev for resolve of rev
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
 my rev@ac809aeed39a+ other rev@97c705ade336 ancestor rev@924404dff337
@@ -187,6 +195,7 @@
  a: other deleted -> r
  rev: versions differ -> m
  b: remote created -> g
+preserving rev for resolve of rev
 removing a
 getting b
 picked tool 'python ../merge' for rev (binary False symlink False)
@@ -212,6 +221,7 @@
    b -> a 
   checking for directory renames
  rev: versions differ -> m
+preserving rev for resolve of rev
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
 my rev@ecf3cb2a4219+ other rev@97c705ade336 ancestor rev@924404dff337
@@ -231,6 +241,8 @@
   searching for copies back to rev 1
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
 my b@ec03c2ca8642+ other b@79cc6877a3b7 ancestor a@924404dff337
@@ -262,6 +274,7 @@
  a: divergent renames -> dr
  rev: versions differ -> m
  c: remote created -> g
+preserving rev for resolve of rev
 warning: detected divergent renames of a to:
  b
  c
@@ -286,6 +299,8 @@
   searching for copies back to rev 1
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
 my b@ac809aeed39a+ other b@af30c7647fc7 ancestor b@000000000000
@@ -310,6 +325,8 @@
  a: other deleted -> r
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 removing a
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
@@ -334,6 +351,8 @@
  a: remote is newer -> g
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 getting a
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
@@ -359,6 +378,8 @@
  a: other deleted -> r
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 removing a
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
@@ -383,6 +404,8 @@
  a: remote is newer -> g
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 getting a
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
@@ -407,6 +430,8 @@
   searching for copies back to rev 1
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
 my b@0b76e65c8289+ other b@735846fee2d7 ancestor b@000000000000
@@ -431,6 +456,8 @@
  b: versions differ -> m
  rev: versions differ -> m
  a: prompt recreating -> g
+preserving b for resolve of b
+preserving rev for resolve of rev
 getting a
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
@@ -455,6 +482,8 @@
   searching for copies back to rev 1
  b: versions differ -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
 merging b
 my b@0b76e65c8289+ other b@e03727d2d66b ancestor b@000000000000
@@ -483,11 +512,12 @@
   checking for directory renames
  rev: versions differ -> m
  a: remote moved to b -> m
-copying a to b
-picked tool 'python ../merge' for a (binary False symlink False)
-merging a and b
-my a@e300d1c794ec+ other b@79cc6877a3b7 ancestor a@924404dff337
+preserving a for resolve of b
+preserving rev for resolve of rev
 removing a
+picked tool 'python ../merge' for b (binary False symlink False)
+merging a and b to b
+my b@e300d1c794ec+ other b@79cc6877a3b7 ancestor a@924404dff337
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
 my rev@e300d1c794ec+ other rev@79cc6877a3b7 ancestor rev@924404dff337
@@ -513,8 +543,10 @@
   checking for directory renames
  b: local moved to a -> m
  rev: versions differ -> m
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
-merging b and a
+merging b and a to b
 my b@ec03c2ca8642+ other a@f4db7e329e71 ancestor a@924404dff337
 picked tool 'python ../merge' for rev (binary False symlink False)
 merging rev
@@ -544,8 +576,10 @@
  b: local moved to a -> m
  rev: versions differ -> m
  c: remote created -> g
+preserving b for resolve of b
+preserving rev for resolve of rev
 picked tool 'python ../merge' for b (binary False symlink False)
-merging b and a
+merging b and a to b
 my b@ecf3cb2a4219+ other a@2b958612230f ancestor a@924404dff337
  premerge successful
 getting c
--- a/tests/test-serve	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-serve	Sat Apr 12 21:34:01 2008 +0200
@@ -2,9 +2,11 @@
 
 hgserve()
 {
-    hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid -v $@ \
+    hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid -E errors.log -v $@ \
         | sed -e 's/:[0-9][0-9]*//g' -e 's/http:\/\/[^/]*\//http:\/\/localhost\//'
     cat hg.pid >> "$DAEMON_PIDS"
+    echo % errors
+    cat errors.log
     sleep 1
     kill `cat hg.pid`
     sleep 1
@@ -17,11 +19,13 @@
 echo 'accesslog = access.log' >> .hg/hgrc
 
 echo % Without -v
-hg serve -a localhost -p $HGPORT -d --pid-file=hg.pid
+hg serve -a localhost -p $HGPORT -d --pid-file=hg.pid -E errors.log
 cat hg.pid >> "$DAEMON_PIDS"
 if [ -f access.log ]; then
     echo 'access log created - .hg/hgrc respected'
 fi
+echo % errors
+cat errors.log
 
 echo % With -v
 hgserve
--- a/tests/test-serve.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-serve.out	Sat Apr 12 21:34:01 2008 +0200
@@ -1,12 +1,18 @@
 % Without -v
 access log created - .hg/hgrc respected
+% errors
 % With -v
-listening at http://localhost/ (127.0.0.1)
+listening at http://localhost/ (bound to 127.0.0.1)
+% errors
 % With --prefix foo
-listening at http://localhost/foo/ (127.0.0.1)
+listening at http://localhost/foo/ (bound to 127.0.0.1)
+% errors
 % With --prefix /foo
-listening at http://localhost/foo/ (127.0.0.1)
+listening at http://localhost/foo/ (bound to 127.0.0.1)
+% errors
 % With --prefix foo/
-listening at http://localhost/foo/ (127.0.0.1)
+listening at http://localhost/foo/ (bound to 127.0.0.1)
+% errors
 % With --prefix /foo/
-listening at http://localhost/foo/ (127.0.0.1)
+listening at http://localhost/foo/ (bound to 127.0.0.1)
+% errors
--- a/tests/test-up-local-change.out	Sat Apr 12 21:08:03 2008 +0200
+++ b/tests/test-up-local-change.out	Sat Apr 12 21:34:01 2008 +0200
@@ -23,6 +23,7 @@
    b
  a: versions differ -> m
  b: remote created -> g
+preserving a for resolve of a
 picked tool 'true' for a (binary False symlink False)
 merging a
 my a@33aaa84a386b+ other a@802f095af299 ancestor a@33aaa84a386b
@@ -60,6 +61,7 @@
    b
  a: versions differ -> m
  b: remote created -> g
+preserving a for resolve of a
 picked tool 'true' for a (binary False symlink False)
 merging a
 my a@33aaa84a386b+ other a@802f095af299 ancestor a@33aaa84a386b
@@ -113,6 +115,8 @@
   searching for copies back to rev 1
  a: versions differ -> m
  b: versions differ -> m
+preserving a for resolve of a
+preserving b for resolve of b
 picked tool 'true' for a (binary False symlink False)
 merging a
 my a@802f095af299+ other a@030602aee63d ancestor a@33aaa84a386b