changeset 24990:015adbcd92f3

merge with stable
author Matt Mackall <mpm@selenic.com>
date Sun, 10 May 2015 14:45:13 -0500
parents 3098dcd2d167 (diff) 65e8dac7b016 (current diff)
children 4169a4f83548
files tests/test-run-tests.t
diffstat 53 files changed, 857 insertions(+), 431 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Fri May 08 11:32:24 2015 -0700
+++ b/Makefile	Sun May 10 14:45:13 2015 -0500
@@ -157,6 +157,16 @@
 	N=`cd dist && echo mercurial-*.mpkg | sed 's,\.mpkg$$,,'` && hdiutil create -srcfolder dist/$$N.mpkg/ -scrub -volname "$$N" -ov packages/osx/$$N.dmg
 	rm -rf dist/mercurial-*.mpkg
 
+debian-jessie:
+	mkdir -p packages/debian-jessie
+	contrib/builddeb
+	mv debbuild/*.deb packages/debian-jessie
+	rm -rf debbuild
+
+docker-debian-jessie:
+	mkdir -p packages/debian/jessie
+	contrib/dockerdeb jessie
+
 fedora20:
 	mkdir -p packages/fedora20
 	contrib/buildrpm
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/builddeb	Sun May 10 14:45:13 2015 -0500
@@ -0,0 +1,62 @@
+#!/bin/sh -e
+#
+# Build a Mercurial debian package from the current repo
+#
+# Tested on Jessie (stable as of original script authoring.)
+
+. $(dirname $0)/packagelib.sh
+
+BUILD=1
+DEBBUILDDIR="$PWD/debbuild"
+while [ "$1" ]; do
+    case "$1" in
+    --prepare )
+        shift
+        BUILD=
+        ;;
+    --debbuilddir )
+        shift
+        DEBBUILDDIR="$1"
+        shift
+        ;;
+    * )
+        echo "Invalid parameter $1!" 1>&2
+        exit 1
+        ;;
+    esac
+done
+
+set -u
+
+rm -rf $DEBBUILDDIR
+mkdir -p $DEBBUILDDIR
+
+if [ ! -d .hg ]; then
+    echo 'You are not inside a Mercurial repository!' 1>&2
+    exit 1
+fi
+
+gethgversion
+
+cp -r $PWD/contrib/debian $DEBBUILDDIR/DEBIAN
+chmod -R 0755 $DEBBUILDDIR/DEBIAN
+
+control=$DEBBUILDDIR/DEBIAN/control
+
+# This looks like sed -i, but sed -i behaves just differently enough
+# between BSD and GNU sed that I gave up and did the dumb thing.
+sed "s/__VERSION__/$version/" < $control > $control.tmp
+mv $control.tmp $control
+
+if [ "$BUILD" ]; then
+    dpkg-deb --build $DEBBUILDDIR
+    mv $DEBBUILDDIR.deb $DEBBUILDDIR/mercurial-$version-$release.deb
+    if [ $? = 0 ]; then
+        echo
+        echo "Built packages for $version-$release:"
+        find $DEBBUILDDIR/ -type f -newer $control
+    fi
+else
+    echo "Prepared sources for $version-$release $control are in $DEBBUILDDIR - use like:"
+    echo "dpkg-deb --build $DEBBUILDDIR"
+fi
--- a/contrib/buildrpm	Fri May 08 11:32:24 2015 -0700
+++ b/contrib/buildrpm	Sun May 10 14:45:13 2015 -0500
@@ -7,6 +7,8 @@
 # - CentOS 5
 # - centOS 6
 
+. $(dirname $0)/packagelib.sh
+
 BUILD=1
 RPMBUILDDIR="$PWD/rpmbuild"
 while [ "$1" ]; do
@@ -45,25 +47,8 @@
     exit 1
 fi
 
-# build local hg and use it
-python setup.py build_py -c -d .
-HG="$PWD/hg"
-PYTHONPATH="$PWD/mercurial/pure"
-export PYTHONPATH
-
-mkdir -p $RPMBUILDDIR/SOURCES $RPMBUILDDIR/SPECS $RPMBUILDDIR/RPMS $RPMBUILDDIR/SRPMS $RPMBUILDDIR/BUILD
-
-hgversion=`$HG version | sed -ne 's/.*(version \(.*\))$/\1/p'`
+gethgversion
 
-if echo $hgversion | grep -- '-' > /dev/null 2>&1; then
-    # nightly build case, version is like 1.3.1+250-20b91f91f9ca
-    version=`echo $hgversion | cut -d- -f1`
-    release=`echo $hgversion | cut -d- -f2 | sed -e 's/+.*//'`
-else
-    # official tag, version is like 1.3.1
-    version=`echo $hgversion | sed -e 's/+.*//'`
-    release='0'
-fi
 if [ "$PYTHONVER" ]; then
     release=$release+$PYTHONVER
     RPMPYTHONVER=$PYTHONVER
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/debian/control	Sun May 10 14:45:13 2015 -0500
@@ -0,0 +1,9 @@
+Package: mercurial
+Version: __VERSION__
+Section: vcs
+Priority: optional
+Architecture: all
+Depends: python
+Conflicts: mercurial-common
+Maintainer: Mercurial Developers <mercurial-devel@selenic.com>
+Description: Mercurial (probably nightly) package built by upstream.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/docker/debian-jessie	Sun May 10 14:45:13 2015 -0500
@@ -0,0 +1,11 @@
+FROM debian:jessie
+RUN apt-get update && apt-get install -y \
+  build-essential \
+  debhelper \
+  dh-python \
+  devscripts \
+  python \
+  python-all-dev \
+  python-docutils \
+  zip \
+  unzip
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/dockerdeb	Sun May 10 14:45:13 2015 -0500
@@ -0,0 +1,39 @@
+#!/bin/bash -eu
+
+. $(dirname $0)/dockerlib.sh
+. $(dirname $0)/packagelib.sh
+
+BUILDDIR=$(dirname $0)
+export ROOTDIR=$(cd $BUILDDIR/..; pwd)
+
+checkdocker
+
+PLATFORM="debian-$1"
+shift # extra params are passed to build process
+
+initcontainer $PLATFORM
+
+DEBBUILDDIR=$ROOTDIR/packages/$PLATFORM
+contrib/builddeb --debbuilddir $DEBBUILDDIR/staged --prepare
+
+DSHARED=/mnt/shared/
+if [ $(uname) = "Darwin" ] ; then
+    $DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED -v $PWD:/mnt/hg $CONTAINER \
+            sh -c "cd /mnt/hg && make clean && make local"
+fi
+$DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED -v $PWD:/mnt/hg $CONTAINER \
+  sh -c "cd /mnt/hg && make PREFIX=$DSHARED/staged/usr install"
+$DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED $CONTAINER \
+  dpkg-deb --build $DSHARED/staged
+if [ $(uname) = "Darwin" ] ; then
+    $DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED -v $PWD:/mnt/hg $CONTAINER \
+            sh -c "cd /mnt/hg && make clean"
+fi
+
+gethgversion
+
+rm -r $DEBBUILDDIR/staged
+mv $DEBBUILDDIR/staged.deb $DEBBUILDDIR/mercurial-$version-$release.deb
+
+echo
+echo "Build complete - results can be found in $DEBBUILDDIR"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/dockerlib.sh	Sun May 10 14:45:13 2015 -0500
@@ -0,0 +1,42 @@
+#!/bin/sh -eu
+
+# This function exists to set up the DOCKER variable and verify that
+# it's the binary we expect. It also verifies that the docker service
+# is running on the system and we can talk to it.
+function checkdocker() {
+  if which docker.io >> /dev/null 2>&1 ; then
+    DOCKER=docker.io
+  elif which docker >> /dev/null 2>&1 ; then
+    DOCKER=docker
+  else
+    echo "Error: docker must be installed"
+    exit 1
+  fi
+
+  $DOCKER -h 2> /dev/null | grep -q Jansens && { echo "Error: $DOCKER is the Docking System Tray - install docker.io instead"; exit 1; }
+  $DOCKER version | grep -q "^Client version:" || { echo "Error: unexpected output from \"$DOCKER version\""; exit 1; }
+  $DOCKER version | grep -q "^Server version:" || { echo "Error: could not get docker server version - check it is running and your permissions"; exit 1; }
+}
+
+# Construct a container and leave its name in $CONTAINER for future use.
+function initcontainer() {
+  [ "$1" ] || { echo "Error: platform name must be specified"; exit 1; }
+
+  DFILE="$ROOTDIR/contrib/docker/$1"
+  [ -f "$DFILE" ] || { echo "Error: docker file $DFILE not found"; exit 1; }
+
+  CONTAINER="hg-dockerrpm-$1"
+  DBUILDUSER=build
+  (
+    cat $DFILE
+    if [ $(uname) = "Darwin" ] ; then
+        # The builder is using boot2docker on OS X, so we're going to
+        # *guess* the uid of the user inside the VM that is actually
+        # running docker. This is *very likely* to fail at some point.
+        echo RUN useradd $DBUILDUSER -u 1000
+    else
+        echo RUN groupadd $DBUILDUSER -g `id -g`
+        echo RUN useradd $DBUILDUSER -u `id -u` -g $DBUILDUSER
+    fi
+  ) | $DOCKER build --tag $CONTAINER -
+}
--- a/contrib/dockerrpm	Fri May 08 11:32:24 2015 -0700
+++ b/contrib/dockerrpm	Sun May 10 14:45:13 2015 -0500
@@ -1,36 +1,16 @@
 #!/bin/bash -e
 
+. $(dirname $0)/dockerlib.sh
+
 BUILDDIR=$(dirname $0)
-ROOTDIR=$(cd $BUILDDIR/..; pwd)
+export ROOTDIR=$(cd $BUILDDIR/..; pwd)
 
-if which docker.io >> /dev/null 2>&1 ; then
-  DOCKER=docker.io
-elif which docker >> /dev/null 2>&1 ; then
-  DOCKER=docker
-else
-  echo "Error: docker must be installed"
-  exit 1
-fi
-
-$DOCKER -h 2> /dev/null | grep -q Jansens && { echo "Error: $DOCKER is the Docking System Tray - install docker.io instead"; exit 1; }
-$DOCKER version | grep -q "^Client version:" || { echo "Error: unexpected output from \"$DOCKER version\""; exit 1; }
-$DOCKER version | grep -q "^Server version:" || { echo "Error: could not get docker server version - check it is running and your permissions"; exit 1; }
+checkdocker
 
 PLATFORM="$1"
-[ "$PLATFORM" ] || { echo "Error: platform name must be specified"; exit 1; }
 shift # extra params are passed to buildrpm
 
-DFILE="$ROOTDIR/contrib/docker/$PLATFORM"
-[ -f "$DFILE" ] || { echo "Error: docker file $DFILE not found"; exit 1; }
-
-CONTAINER="hg-dockerrpm-$PLATFORM"
-
-DBUILDUSER=build
-(
-cat $DFILE
-echo RUN groupadd $DBUILDUSER -g `id -g`
-echo RUN useradd $DBUILDUSER -u `id -u` -g $DBUILDUSER
-) | $DOCKER build --tag $CONTAINER -
+initcontainer $PLATFORM
 
 RPMBUILDDIR=$ROOTDIR/packages/$PLATFORM
 contrib/buildrpm --rpmbuilddir $RPMBUILDDIR --prepare $*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/packagelib.sh	Sun May 10 14:45:13 2015 -0500
@@ -0,0 +1,19 @@
+gethgversion() {
+    make clean
+    make local || make local PURE=--pure
+    HG="$PWD/hg"
+
+    $HG version > /dev/null || { echo 'abort: hg version failed!'; exit 1 ; }
+
+    hgversion=`$HG version | sed -ne 's/.*(version \(.*\))$/\1/p'`
+
+    if echo $hgversion | grep -- '-' > /dev/null 2>&1; then
+        # nightly build case, version is like 1.3.1+250-20b91f91f9ca
+        version=`echo $hgversion | cut -d- -f1`
+        release=`echo $hgversion | cut -d- -f2 | sed -e 's/+.*//'`
+    else
+        # official tag, version is like 1.3.1
+        version=`echo $hgversion | sed -e 's/+.*//'`
+        release='0'
+    fi
+}
--- a/contrib/revsetbenchmarks.txt	Fri May 08 11:32:24 2015 -0700
+++ b/contrib/revsetbenchmarks.txt	Sun May 10 14:45:13 2015 -0500
@@ -17,6 +17,7 @@
 # those two `roots(...)` inputs are close to what phase movement use.
 roots((tip~100::) - (tip~100::tip))
 roots((0::) - (0::tip))
+42:68 and roots(42:tip)
 ::p1(p1(tip))::
 public()
 :10000 and public()
--- a/contrib/wix/guids.wxi	Fri May 08 11:32:24 2015 -0700
+++ b/contrib/wix/guids.wxi	Sun May 10 14:45:13 2015 -0500
@@ -28,6 +28,7 @@
   <?define templates.atom.guid = {D30E14A5-8AF0-4268-8B00-00BEE9E09E39} ?>
   <?define templates.coal.guid = {B63CCAAB-4EAF-43b4-901E-4BD13F5B78FC} ?>
   <?define templates.gitweb.guid = {827334AF-1EFD-421B-962C-5660A068F612} ?>
+  <?define templates.json.guid = {F535BE7A-EC34-46E0-B9BE-013F3DBAFB19} ?>
   <?define templates.monoblue.guid = {8060A1E4-BD4C-453E-92CB-9536DC44A9E3} ?>
   <?define templates.paper.guid = {61AB1DE9-645F-46ED-8AF8-0CF02267FFBB} ?>
   <?define templates.raw.guid = {834DF8D7-9784-43A6-851D-A96CE1B3575B} ?>
--- a/contrib/wix/templates.wxs	Fri May 08 11:32:24 2015 -0700
+++ b/contrib/wix/templates.wxs	Sun May 10 14:45:13 2015 -0500
@@ -12,6 +12,7 @@
       <ComponentRef Id="templates.atom" />
       <ComponentRef Id="templates.coal" />
       <ComponentRef Id="templates.gitweb" />
+      <ComponentRef Id="templates.json" />
       <ComponentRef Id="templates.monoblue" />
       <ComponentRef Id="templates.paper" />
       <ComponentRef Id="templates.raw" />
@@ -36,6 +37,13 @@
           <File Name="map-cmdline.phases" />
         </Component>
 
+        <Directory Id="templates.jsondir" Name="json">
+          <Component Id="templates.json" Guid="$(var.templates.json.guid)" Win64='$(var.IsX64)'>
+            <File Id="json.changelist.tmpl" Name="changelist.tmpl" KeyPath="yes" />
+            <File Id="json.map"             Name="map" />
+          </Component>
+        </Directory>
+
         <Directory Id="templates.atomdir" Name="atom">
           <Component Id="templates.atom" Guid="$(var.templates.atom.guid)" Win64='$(var.IsX64)'>
             <File Id="atom.changelog.tmpl"      Name="changelog.tmpl" KeyPath="yes" />
--- a/hgext/bugzilla.py	Fri May 08 11:32:24 2015 -0700
+++ b/hgext/bugzilla.py	Sun May 10 14:45:13 2015 -0500
@@ -279,7 +279,7 @@
 
 from mercurial.i18n import _
 from mercurial.node import short
-from mercurial import cmdutil, mail, templater, util
+from mercurial import cmdutil, mail, util
 import re, time, urlparse, xmlrpclib
 
 testedwith = 'internal'
@@ -876,8 +876,6 @@
         if not mapfile and not tmpl:
             tmpl = _('changeset {node|short} in repo {root} refers '
                      'to bug {bug}.\ndetails:\n\t{desc|tabindent}')
-        if tmpl:
-            tmpl = templater.parsestring(tmpl, quoted=False)
         t = cmdutil.changeset_templater(self.ui, self.repo,
                                         False, None, tmpl, mapfile, False)
         self.ui.pushbuffer()
--- a/hgext/churn.py	Fri May 08 11:32:24 2015 -0700
+++ b/hgext/churn.py	Sun May 10 14:45:13 2015 -0500
@@ -9,7 +9,7 @@
 '''command to display statistics about repository history'''
 
 from mercurial.i18n import _
-from mercurial import patch, cmdutil, scmutil, util, templater, commands
+from mercurial import patch, cmdutil, scmutil, util, commands
 from mercurial import encoding
 import os
 import time, datetime
@@ -19,7 +19,6 @@
 testedwith = 'internal'
 
 def maketemplater(ui, repo, tmpl):
-    tmpl = templater.parsestring(tmpl, quoted=False)
     try:
         t = cmdutil.changeset_templater(ui, repo, False, None, tmpl,
                                         None, False)
--- a/hgext/hgcia.py	Fri May 08 11:32:24 2015 -0700
+++ b/hgext/hgcia.py	Sun May 10 14:45:13 2015 -0500
@@ -43,7 +43,7 @@
 
 from mercurial.i18n import _
 from mercurial.node import bin, short
-from mercurial import cmdutil, patch, templater, util, mail
+from mercurial import cmdutil, patch, util, mail
 import email.Parser
 
 import socket, xmlrpclib
@@ -206,7 +206,6 @@
                 template = self.dstemplate
             else:
                 template = self.deftemplate
-        template = templater.parsestring(template, quoted=False)
         t = cmdutil.changeset_templater(self.ui, self.repo, False, None,
                                         template, style, False)
         self.templater = t
--- a/hgext/keyword.py	Fri May 08 11:32:24 2015 -0700
+++ b/hgext/keyword.py	Sun May 10 14:45:13 2015 -0500
@@ -83,7 +83,7 @@
 '''
 
 from mercurial import commands, context, cmdutil, dispatch, filelog, extensions
-from mercurial import localrepo, match, patch, templatefilters, templater, util
+from mercurial import localrepo, match, patch, templatefilters, util
 from mercurial import scmutil, pathutil
 from mercurial.hgweb import webcommands
 from mercurial.i18n import _
@@ -191,8 +191,7 @@
 
         kwmaps = self.ui.configitems('keywordmaps')
         if kwmaps: # override default templates
-            self.templates = dict((k, templater.parsestring(v, False))
-                                  for k, v in kwmaps)
+            self.templates = dict(kwmaps)
         else:
             self.templates = _defaultkwmaps(self.ui)
 
@@ -457,9 +456,7 @@
     repo.commit(text=msg)
     ui.status(_('\n\tkeywords expanded\n'))
     ui.write(repo.wread(fn))
-    for root, dirs, files in os.walk(tmpdir):
-        for f in files:
-            util.unlinkpath(repo.vfs.reljoin(root, f))
+    repo.wvfs.rmtree(repo.root)
 
 @command('kwexpand',
     commands.walkopts,
--- a/hgext/largefiles/overrides.py	Fri May 08 11:32:24 2015 -0700
+++ b/hgext/largefiles/overrides.py	Sun May 10 14:45:13 2015 -0500
@@ -985,7 +985,7 @@
     for subpath in sorted(ctx.substate):
         sub = ctx.sub(subpath)
         submatch = match_.narrowmatcher(subpath, match)
-        sub.archive(archiver, os.path.join(prefix, repo._path) + '/', submatch)
+        sub.archive(archiver, prefix + repo._path + '/', submatch)
 
 # If a largefile is modified, the change is not reflected in its
 # standin until a commit. cmdutil.bailifchanged() raises an exception
--- a/hgext/notify.py	Fri May 08 11:32:24 2015 -0700
+++ b/hgext/notify.py	Sun May 10 14:45:13 2015 -0500
@@ -138,7 +138,7 @@
 # load. This was not a problem on Python 2.7.
 import email.Parser
 from mercurial.i18n import _
-from mercurial import patch, cmdutil, templater, util, mail
+from mercurial import patch, cmdutil, util, mail
 import fnmatch
 
 testedwith = 'internal'
@@ -190,8 +190,6 @@
                     self.ui.config('notify', 'template'))
         if not mapfile and not template:
             template = deftemplates.get(hooktype) or single_template
-        if template:
-            template = templater.parsestring(template, quoted=False)
         self.t = cmdutil.changeset_templater(self.ui, self.repo, False, None,
                                              template, mapfile, False)
 
--- a/hgext/rebase.py	Fri May 08 11:32:24 2015 -0700
+++ b/hgext/rebase.py	Sun May 10 14:45:13 2015 -0500
@@ -358,9 +358,9 @@
 
         # Keep track of the current bookmarks in order to reset them later
         currentbookmarks = repo._bookmarks.copy()
-        activebookmark = activebookmark or repo._bookmarkcurrent
+        activebookmark = activebookmark or repo._activebookmark
         if activebookmark:
-            bookmarks.unsetcurrent(repo)
+            bookmarks.deactivate(repo)
 
         extrafn = _makeextrafn(extrafns)
 
@@ -498,7 +498,7 @@
 
         if (activebookmark and
             repo['.'].node() == repo._bookmarks[activebookmark]):
-                bookmarks.setcurrent(repo, activebookmark)
+                bookmarks.activate(repo, activebookmark)
 
     finally:
         release(lock, wlock)
@@ -888,7 +888,7 @@
             repair.strip(repo.ui, repo, strippoints)
 
     if activebookmark:
-        bookmarks.setcurrent(repo, activebookmark)
+        bookmarks.activate(repo, activebookmark)
 
     clearstatus(repo)
     repo.ui.warn(_('rebase aborted\n'))
@@ -1052,7 +1052,7 @@
                 hg.update(repo, dest)
                 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
                     ui.status(_("updating bookmark %s\n")
-                              % repo._bookmarkcurrent)
+                              % repo._activebookmark)
     else:
         if opts.get('tool'):
             raise util.Abort(_('--tool can only be used with --rebase'))
--- a/hgext/shelve.py	Fri May 08 11:32:24 2015 -0700
+++ b/hgext/shelve.py	Sun May 10 14:45:13 2015 -0500
@@ -163,7 +163,7 @@
 
     # we never need the user, so we use a generic user for all shelve operations
     user = 'shelve@localhost'
-    label = repo._bookmarkcurrent or parent.branch() or 'default'
+    label = repo._activebookmark or parent.branch() or 'default'
 
     # slashes aren't allowed in filenames, therefore we rename it
     label = label.replace('/', '_')
--- a/hgext/strip.py	Fri May 08 11:32:24 2015 -0700
+++ b/hgext/strip.py	Sun May 10 14:45:13 2015 -0500
@@ -60,8 +60,8 @@
 
         marks = repo._bookmarks
         if bookmark:
-            if bookmark == repo._bookmarkcurrent:
-                bookmarks.unsetcurrent(repo)
+            if bookmark == repo._activebookmark:
+                bookmarks.deactivate(repo)
             del marks[bookmark]
             marks.write()
             ui.write(_("bookmark '%s' deleted\n") % bookmark)
--- a/mercurial/archival.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/archival.py	Sun May 10 14:45:13 2015 -0500
@@ -37,6 +37,10 @@
     prefix = util.pconvert(lpfx)
     if not prefix.endswith('/'):
         prefix += '/'
+    # Drop the leading '.' path component if present, so Windows can read the
+    # zip files (issue4634)
+    if prefix.startswith('./'):
+        prefix = prefix[2:]
     if prefix.startswith('../') or os.path.isabs(lpfx) or '/../' in prefix:
         raise util.Abort(_('archive prefix contains illegal components'))
     return prefix
--- a/mercurial/bookmarks.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/bookmarks.py	Sun May 10 14:45:13 2015 -0500
@@ -8,7 +8,7 @@
 import os
 from mercurial.i18n import _
 from mercurial.node import hex, bin
-from mercurial import encoding, error, util, obsolete, lock as lockmod
+from mercurial import encoding, util, obsolete, lock as lockmod
 import errno
 
 class bmstore(dict):
@@ -83,8 +83,8 @@
 
     def _writerepo(self, repo):
         """Factored out for extensibility"""
-        if repo._bookmarkcurrent not in self:
-            unsetcurrent(repo)
+        if repo._activebookmark not in self:
+            deactivate(repo)
 
         wlock = repo.wlock()
         try:
@@ -106,13 +106,12 @@
         for name, node in self.iteritems():
             fp.write("%s %s\n" % (hex(node), encoding.fromlocal(name)))
 
-def readcurrent(repo):
-    '''Get the current bookmark
-
-    If we use gittish branches we have a current bookmark that
-    we are on. This function returns the name of the bookmark. It
-    is stored in .hg/bookmarks.current
-    '''
+def readactive(repo):
+    """
+    Get the active bookmark. We can have an active bookmark that updates
+    itself as we commit. This function returns the name of that bookmark.
+    It is stored in .hg/bookmarks.current
+    """
     mark = None
     try:
         file = repo.vfs('bookmarks.current')
@@ -129,16 +128,16 @@
         file.close()
     return mark
 
-def setcurrent(repo, mark):
-    '''Set the name of the bookmark that we are currently on
-
-    Set the name of the bookmark that we are on (hg update <bookmark>).
+def activate(repo, mark):
+    """
+    Set the given bookmark to be 'active', meaning that this bookmark will
+    follow new commits that are made.
     The name is recorded in .hg/bookmarks.current
-    '''
+    """
     if mark not in repo._bookmarks:
         raise AssertionError('bookmark %s does not exist!' % mark)
 
-    current = repo._bookmarkcurrent
+    current = repo._activebookmark
     if current == mark:
         return
 
@@ -149,42 +148,37 @@
         file.close()
     finally:
         wlock.release()
-    repo._bookmarkcurrent = mark
+    repo._activebookmark = mark
 
-def unsetcurrent(repo):
+def deactivate(repo):
+    """
+    Unset the active bookmark in this reposiotry.
+    """
     wlock = repo.wlock()
     try:
         try:
             repo.vfs.unlink('bookmarks.current')
-            repo._bookmarkcurrent = None
+            repo._activebookmark = None
         except OSError, inst:
             if inst.errno != errno.ENOENT:
                 raise
     finally:
         wlock.release()
 
-def iscurrent(repo, mark=None, parents=None):
-    '''Tell whether the current bookmark is also active
+def isactivewdirparent(repo):
+    """
+    Tell whether the 'active' bookmark (the one that follows new commits)
+    points to one of the parents of the current working directory (wdir).
 
-    I.e., the bookmark listed in .hg/bookmarks.current also points to a
-    parent of the working directory.
-    '''
-    if not mark:
-        mark = repo._bookmarkcurrent
-    if not parents:
-        parents = [p.node() for p in repo[None].parents()]
+    While this is normally the case, it can on occasion be false; for example,
+    immediately after a pull, the active bookmark can be moved to point
+    to a place different than the wdir. This is solved by running `hg update`.
+    """
+    mark = repo._activebookmark
     marks = repo._bookmarks
+    parents = [p.node() for p in repo[None].parents()]
     return (mark in marks and marks[mark] in parents)
 
-def updatecurrentbookmark(repo, oldnode, curbranch):
-    try:
-        return update(repo, oldnode, repo.branchtip(curbranch))
-    except error.RepoLookupError:
-        if curbranch == "default": # no default branch!
-            return update(repo, oldnode, repo.lookup("tip"))
-        else:
-            raise util.Abort(_("branch %s not found") % curbranch)
-
 def deletedivergent(repo, deletefrom, bm):
     '''Delete divergent versions of bm on nodes in deletefrom.
 
@@ -207,8 +201,8 @@
     check out and where to move the active bookmark from, if needed.'''
     movemarkfrom = None
     if checkout is None:
-        curmark = repo._bookmarkcurrent
-        if iscurrent(repo):
+        curmark = repo._activebookmark
+        if isactivewdirparent(repo):
             movemarkfrom = repo['.'].node()
         elif curmark:
             ui.status(_("updating to active bookmark %s\n") % curmark)
@@ -219,7 +213,7 @@
     deletefrom = parents
     marks = repo._bookmarks
     update = False
-    cur = repo._bookmarkcurrent
+    cur = repo._activebookmark
     if not cur:
         return False
 
--- a/mercurial/bundlerepo.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/bundlerepo.py	Sun May 10 14:45:13 2015 -0500
@@ -177,11 +177,10 @@
         return manifest.manifest.revision(self, nodeorrev)
 
 class bundlefilelog(bundlerevlog, filelog.filelog):
-    def __init__(self, opener, path, bundle, linkmapper, repo):
+    def __init__(self, opener, path, bundle, linkmapper):
         filelog.filelog.__init__(self, opener, path)
         bundlerevlog.__init__(self, opener, self.indexfile, bundle,
                               linkmapper)
-        self._repo = repo
 
     def baserevision(self, nodeorrev):
         return filelog.filelog.revision(self, nodeorrev)
@@ -322,8 +321,7 @@
 
         if f in self.bundlefilespos:
             self.bundle.seek(self.bundlefilespos[f])
-            return bundlefilelog(self.svfs, f, self.bundle,
-                                 self.changelog.rev, self)
+            return bundlefilelog(self.svfs, f, self.bundle, self.changelog.rev)
         else:
             return filelog.filelog(self.svfs, f)
 
--- a/mercurial/changegroup.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/changegroup.py	Sun May 10 14:45:13 2015 -0500
@@ -283,8 +283,6 @@
         if bundlecaps is None:
             bundlecaps = set()
         self._bundlecaps = bundlecaps
-        self._changelog = repo.changelog
-        self._manifest = repo.manifest
         reorder = repo.ui.config('bundle', 'reorder', 'auto')
         if reorder == 'auto':
             reorder = None
@@ -304,7 +302,7 @@
     def fileheader(self, fname):
         return chunkheader(len(fname)) + fname
 
-    def group(self, nodelist, revlog, lookup, units=None, reorder=None):
+    def group(self, nodelist, revlog, lookup, units=None):
         """Calculate a delta group, yielding a sequence of changegroup chunks
         (strings).
 
@@ -325,7 +323,7 @@
 
         # for generaldelta revlogs, we linearize the revs; this will both be
         # much quicker and generate a much smaller bundle
-        if (revlog._generaldelta and reorder is not False) or reorder:
+        if (revlog._generaldelta and self._reorder is None) or self._reorder:
             dag = dagutil.revlogdag(revlog)
             revs = set(revlog.rev(n) for n in nodelist)
             revs = dag.linearize(revs)
@@ -347,23 +345,20 @@
             for c in self.revchunk(revlog, curr, prev, linknode):
                 yield c
 
+        if units is not None:
+            self._progress(msgbundling, None)
         yield self.close()
 
     # filter any nodes that claim to be part of the known set
-    def prune(self, revlog, missing, commonrevs, source):
+    def prune(self, revlog, missing, commonrevs):
         rr, rl = revlog.rev, revlog.linkrev
         return [n for n in missing if rl(rr(n)) not in commonrevs]
 
     def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
         '''yield a sequence of changegroup chunks (strings)'''
         repo = self._repo
-        cl = self._changelog
-        mf = self._manifest
-        reorder = self._reorder
-        progress = self._progress
-
-        # for progress output
-        msgbundling = _('bundling')
+        cl = repo.changelog
+        ml = repo.manifest
 
         clrevorder = {}
         mfs = {} # needed manifests
@@ -383,20 +378,34 @@
 
         self._verbosenote(_('uncompressed size of bundle content:\n'))
         size = 0
-        for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets'),
-                                reorder=reorder):
+        for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets')):
             size += len(chunk)
             yield chunk
         self._verbosenote(_('%8.i (changelog)\n') % size)
-        progress(msgbundling, None)
 
+        # We need to make sure that the linkrev in the changegroup refers to
+        # the first changeset that introduced the manifest or file revision.
+        # The fastpath is usually safer than the slowpath, because the filelogs
+        # are walked in revlog order.
+        #
+        # When taking the slowpath with reorder=None and the manifest revlog
+        # uses generaldelta, the manifest may be walked in the "wrong" order.
+        # Without 'clrevorder', we would get an incorrect linkrev (see fix in
+        # cc0ff93d0c0c).
+        #
+        # When taking the fastpath, we are only vulnerable to reordering
+        # of the changelog itself. The changelog never uses generaldelta, so
+        # it is only reordered when reorder=True. To handle this case, we
+        # simply take the slowpath, which already has the 'clrevorder' logic.
+        # This was also fixed in cc0ff93d0c0c.
+        fastpathlinkrev = fastpathlinkrev and not self._reorder
         # Callback for the manifest, used to collect linkrevs for filelog
         # revisions.
         # Returns the linkrev node (collected in lookupcl).
         def lookupmf(x):
             clnode = mfs[x]
-            if not fastpathlinkrev or reorder:
-                mdata = mf.readfast(x)
+            if not fastpathlinkrev:
+                mdata = ml.readfast(x)
                 for f, n in mdata.iteritems():
                     if f in changedfiles:
                         # record the first changeset introducing this filelog
@@ -407,25 +416,23 @@
                             fclnodes[n] = clnode
             return clnode
 
-        mfnodes = self.prune(mf, mfs, commonrevs, source)
+        mfnodes = self.prune(ml, mfs, commonrevs)
         size = 0
-        for chunk in self.group(mfnodes, mf, lookupmf, units=_('manifests'),
-                                reorder=reorder):
+        for chunk in self.group(mfnodes, ml, lookupmf, units=_('manifests')):
             size += len(chunk)
             yield chunk
         self._verbosenote(_('%8.i (manifests)\n') % size)
-        progress(msgbundling, None)
 
         mfs.clear()
-        needed = set(cl.rev(x) for x in clnodes)
+        clrevs = set(cl.rev(x) for x in clnodes)
 
         def linknodes(filerevlog, fname):
-            if fastpathlinkrev and not reorder:
+            if fastpathlinkrev:
                 llr = filerevlog.linkrev
                 def genfilenodes():
                     for r in filerevlog:
                         linkrev = llr(r)
-                        if linkrev in needed:
+                        if linkrev in clrevs:
                             yield filerevlog.node(r), cl.node(linkrev)
                 return dict(genfilenodes())
             return fnodes.get(fname, {})
@@ -435,15 +442,14 @@
             yield chunk
 
         yield self.close()
-        progress(msgbundling, None)
 
         if clnodes:
             repo.hook('outgoing', node=hex(clnodes[0]), source=source)
 
+    # The 'source' parameter is useful for extensions
     def generatefiles(self, changedfiles, linknodes, commonrevs, source):
         repo = self._repo
         progress = self._progress
-        reorder = self._reorder
         msgbundling = _('bundling')
 
         total = len(changedfiles)
@@ -460,18 +466,18 @@
             def lookupfilelog(x):
                 return linkrevnodes[x]
 
-            filenodes = self.prune(filerevlog, linkrevnodes, commonrevs, source)
+            filenodes = self.prune(filerevlog, linkrevnodes, commonrevs)
             if filenodes:
                 progress(msgbundling, i + 1, item=fname, unit=msgfiles,
                          total=total)
                 h = self.fileheader(fname)
                 size = len(h)
                 yield h
-                for chunk in self.group(filenodes, filerevlog, lookupfilelog,
-                                        reorder=reorder):
+                for chunk in self.group(filenodes, filerevlog, lookupfilelog):
                     size += len(chunk)
                     yield chunk
                 self._verbosenote(_('%8.i  %s\n') % (size, fname))
+        progress(msgbundling, None)
 
     def deltaparent(self, revlog, rev, p1, p2, prev):
         return prev
@@ -513,11 +519,13 @@
     version = '02'
     deltaheader = _CHANGEGROUPV2_DELTA_HEADER
 
-    def group(self, nodelist, revlog, lookup, units=None, reorder=None):
-        if (revlog._generaldelta and reorder is not True):
-            reorder = False
-        return super(cg2packer, self).group(nodelist, revlog, lookup,
-                                            units=units, reorder=reorder)
+    def __init__(self, repo, bundlecaps=None):
+        super(cg2packer, self).__init__(repo, bundlecaps)
+        if self._reorder is None:
+            # Since generaldelta is directly supported by cg2, reordering
+            # generally doesn't help, so we disable it by default (treating
+            # bundle.reorder=auto just like bundle.reorder=False).
+            self._reorder = False
 
     def deltaparent(self, revlog, rev, p1, p2, prev):
         dp = revlog.deltaparent(rev)
@@ -788,8 +796,8 @@
         if repo.ui.configbool('server', 'validate', default=False):
             # validate incoming csets have their manifests
             for cset in xrange(clstart, clend):
-                mfest = repo.changelog.read(repo.changelog.node(cset))[0]
-                mfest = repo.manifest.readdelta(mfest)
+                mfnode = repo.changelog.read(repo.changelog.node(cset))[0]
+                mfest = repo.manifest.readdelta(mfnode)
                 # store file nodes we must see
                 for f, n in mfest.iteritems():
                     needfiles.setdefault(f, set()).add(n)
--- a/mercurial/changelog.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/changelog.py	Sun May 10 14:45:13 2015 -0500
@@ -172,14 +172,6 @@
         self.rev(self.node(0))
         return self._nodecache
 
-    def hasnode(self, node):
-        """filtered version of revlog.hasnode"""
-        try:
-            i = self.rev(node)
-            return i not in self.filteredrevs
-        except KeyError:
-            return False
-
     def headrevs(self):
         if self.filteredrevs:
             try:
--- a/mercurial/cmdutil.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/cmdutil.py	Sun May 10 14:45:13 2015 -0500
@@ -1443,9 +1443,9 @@
         tmpl = ui.config('ui', 'logtemplate')
         if tmpl:
             try:
-                tmpl = templater.parsestring(tmpl)
+                tmpl = templater.unquotestring(tmpl)
             except SyntaxError:
-                tmpl = templater.parsestring(tmpl, quoted=False)
+                pass
             return tmpl, None
         else:
             style = util.expandpath(ui.config('ui', 'style', ''))
@@ -1477,9 +1477,9 @@
     t = ui.config('templates', tmpl)
     if t:
         try:
-            tmpl = templater.parsestring(t)
+            tmpl = templater.unquotestring(t)
         except SyntaxError:
-            tmpl = templater.parsestring(t, quoted=False)
+            tmpl = t
         return tmpl, None
 
     if tmpl == 'list':
@@ -2336,7 +2336,7 @@
                     return True
             return False
 
-        isdir = f in deleteddirs or f in wctx.dirs()
+        isdir = f in deleteddirs or wctx.hasdir(f)
         if f in repo.dirstate or isdir or f == '.' or insubrepo():
             continue
 
@@ -2480,13 +2480,13 @@
             # First, do a regular commit to record all changes in the working
             # directory (if there are any)
             ui.callhooks = False
-            currentbookmark = repo._bookmarkcurrent
+            currentbookmark = repo._activebookmark
             try:
-                repo._bookmarkcurrent = None
+                repo._activebookmark = None
                 opts['message'] = 'temporary amend commit for %s' % old
                 node = commit(ui, repo, commitfunc, pats, opts)
             finally:
-                repo._bookmarkcurrent = currentbookmark
+                repo._activebookmark = currentbookmark
                 ui.callhooks = True
             ctx = repo[node]
 
@@ -2721,8 +2721,8 @@
         edittext.append(_("HG: branch merge"))
     if ctx.branch():
         edittext.append(_("HG: branch '%s'") % ctx.branch())
-    if bookmarks.iscurrent(repo):
-        edittext.append(_("HG: bookmark '%s'") % repo._bookmarkcurrent)
+    if bookmarks.isactivewdirparent(repo):
+        edittext.append(_("HG: bookmark '%s'") % repo._activebookmark)
     edittext.extend([_("HG: subrepo %s") % s for s in subs])
     edittext.extend([_("HG: added %s") % f for f in added])
     edittext.extend([_("HG: changed %s") % f for f in modified])
--- a/mercurial/commands.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/commands.py	Sun May 10 14:45:13 2015 -0500
@@ -979,8 +979,8 @@
                     if mark not in marks:
                         raise util.Abort(_("bookmark '%s' does not exist") %
                                          mark)
-                    if mark == repo._bookmarkcurrent:
-                        bookmarks.unsetcurrent(repo)
+                    if mark == repo._activebookmark:
+                        bookmarks.deactivate(repo)
                     del marks[mark]
                 marks.write()
 
@@ -994,8 +994,8 @@
                     raise util.Abort(_("bookmark '%s' does not exist") % rename)
                 checkconflict(repo, mark, cur, force)
                 marks[mark] = marks[rename]
-                if repo._bookmarkcurrent == rename and not inactive:
-                    bookmarks.setcurrent(repo, mark)
+                if repo._activebookmark == rename and not inactive:
+                    bookmarks.activate(repo, mark)
                 del marks[rename]
                 marks.write()
 
@@ -1005,8 +1005,8 @@
                     mark = checkformat(mark)
                     if newact is None:
                         newact = mark
-                    if inactive and mark == repo._bookmarkcurrent:
-                        bookmarks.unsetcurrent(repo)
+                    if inactive and mark == repo._activebookmark:
+                        bookmarks.deactivate(repo)
                         return
                     tgt = cur
                     if rev:
@@ -1014,18 +1014,18 @@
                     checkconflict(repo, mark, cur, force, tgt)
                     marks[mark] = tgt
                 if not inactive and cur == marks[newact] and not rev:
-                    bookmarks.setcurrent(repo, newact)
-                elif cur != tgt and newact == repo._bookmarkcurrent:
-                    bookmarks.unsetcurrent(repo)
+                    bookmarks.activate(repo, newact)
+                elif cur != tgt and newact == repo._activebookmark:
+                    bookmarks.deactivate(repo)
                 marks.write()
 
             elif inactive:
                 if len(marks) == 0:
                     ui.status(_("no bookmarks set\n"))
-                elif not repo._bookmarkcurrent:
+                elif not repo._activebookmark:
                     ui.status(_("no active bookmark\n"))
                 else:
-                    bookmarks.unsetcurrent(repo)
+                    bookmarks.deactivate(repo)
         finally:
             wlock.release()
     else: # show bookmarks
@@ -1035,7 +1035,7 @@
         if len(marks) == 0 and not fm:
             ui.status(_("no bookmarks set\n"))
         for bmark, n in sorted(marks.iteritems()):
-            current = repo._bookmarkcurrent
+            current = repo._activebookmark
             if bmark == current:
                 prefix, label = '*', 'bookmarks.current'
             else:
@@ -1506,7 +1506,7 @@
                                match,
                                extra=extra)
 
-        current = repo._bookmarkcurrent
+        current = repo._activebookmark
         marks = old.bookmarks()
         node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
         if node == old.node():
@@ -1519,7 +1519,7 @@
             for bm in marks:
                 newmarks[bm] = node
                 if bm == current:
-                    bookmarks.setcurrent(repo, bm)
+                    bookmarks.activate(repo, bm)
             newmarks.write()
     else:
         def commitfunc(ui, repo, message, match, opts):
@@ -4702,9 +4702,9 @@
     if node:
         node = scmutil.revsingle(repo, node).node()
 
-    if not node and repo._bookmarkcurrent:
-        bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
-        curhead = repo[repo._bookmarkcurrent].node()
+    if not node and repo._activebookmark:
+        bmheads = repo.bookmarkheads(repo._activebookmark)
+        curhead = repo[repo._activebookmark].node()
         if len(bmheads) == 2:
             if curhead == bmheads[0]:
                 node = bmheads[1]
@@ -4719,7 +4719,7 @@
                 "please merge with an explicit rev or bookmark"),
                 hint=_("run 'hg heads' to see all heads"))
 
-    if not node and not repo._bookmarkcurrent:
+    if not node and not repo._activebookmark:
         branch = repo[None].branch()
         bheads = repo.branchheads(branch)
         nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
@@ -5049,7 +5049,7 @@
             return 0
         if not ret and not checkout:
             if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
-                ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
+                ui.status(_("updating bookmark %s\n") % repo._activebookmark)
         return ret
     if modheads > 1:
         currentbranchheads = len(repo.branchheads())
@@ -5914,7 +5914,7 @@
         ui.status(m, label='log.branch')
 
     if marks:
-        current = repo._bookmarkcurrent
+        current = repo._activebookmark
         # i18n: column positioning for "hg summary"
         ui.write(_('bookmarks:'), label='log.bookmark')
         if current is not None:
@@ -6405,15 +6405,15 @@
 
     if not ret and movemarkfrom:
         if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
-            ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
+            ui.status(_("updating bookmark %s\n") % repo._activebookmark)
     elif brev in repo._bookmarks:
-        bookmarks.setcurrent(repo, brev)
+        bookmarks.activate(repo, brev)
         ui.status(_("(activating bookmark %s)\n") % brev)
     elif brev:
-        if repo._bookmarkcurrent:
+        if repo._activebookmark:
             ui.status(_("(leaving bookmark %s)\n") %
-                      repo._bookmarkcurrent)
-        bookmarks.unsetcurrent(repo)
+                      repo._activebookmark)
+        bookmarks.deactivate(repo)
 
     return ret
 
--- a/mercurial/context.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/context.py	Sun May 10 14:45:13 2015 -0500
@@ -459,7 +459,7 @@
                 pass
         except (error.FilteredIndexError, error.FilteredLookupError,
                 error.FilteredRepoLookupError):
-            if repo.filtername == 'visible':
+            if repo.filtername.startswith('visible'):
                 msg = _("hidden revision '%s'") % changeid
                 hint = _('use --hidden to access hidden revisions')
                 raise error.FilteredRepoLookupError(msg, hint=hint)
--- a/mercurial/crecord.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/crecord.py	Sun May 10 14:45:13 2015 -0500
@@ -20,7 +20,8 @@
 
 # os.name is one of: 'posix', 'nt', 'dos', 'os2', 'mac', or 'ce'
 if os.name == 'posix':
-    import curses, fcntl, termios
+    import curses
+    import fcntl, termios
 else:
     # I have no idea if wcurses works with crecord...
     try:
--- a/mercurial/filemerge.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/filemerge.py	Sun May 10 14:45:13 2015 -0500
@@ -354,7 +354,6 @@
 
     ui = repo.ui
     template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
-    template = templater.parsestring(template, quoted=False)
     tmpl = templater.templater(None, cache={'conflictmarker': template})
 
     pad = max(len(l) for l in labels)
--- a/mercurial/hg.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/hg.py	Sun May 10 14:45:13 2015 -0500
@@ -497,7 +497,7 @@
                 destrepo.ui.status(status)
                 _update(destrepo, uprev)
                 if update in destrepo._bookmarks:
-                    bookmarks.setcurrent(destrepo, update)
+                    bookmarks.activate(destrepo, update)
     finally:
         release(srclock, destlock)
         if cleandir is not None:
--- a/mercurial/localrepo.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/localrepo.py	Sun May 10 14:45:13 2015 -0500
@@ -192,11 +192,11 @@
 
 class localrepository(object):
 
-    supportedformats = set(('revlogv1', 'generaldelta', 'manifestv2'))
+    supportedformats = set(('revlogv1', 'generaldelta', 'treemanifest',
+                            'manifestv2'))
     _basesupported = supportedformats | set(('store', 'fncache', 'shared',
                                              'dotencode'))
-    openerreqs = set(('revlogv1', 'generaldelta', 'manifestv2'))
-    requirements = ['revlogv1']
+    openerreqs = set(('revlogv1', 'generaldelta', 'treemanifest', 'manifestv2'))
     filtername = None
 
     # a list of (ui, featureset) functions.
@@ -204,9 +204,10 @@
     featuresetupfuncs = set()
 
     def _baserequirements(self, create):
-        return self.requirements[:]
+        return ['revlogv1']
 
     def __init__(self, baseui, path=None, create=False):
+        self.requirements = set()
         self.wvfs = scmutil.vfs(path, expandpath=True, realpath=True)
         self.wopener = self.wvfs
         self.root = self.wvfs.base
@@ -243,14 +244,14 @@
                 if not self.wvfs.exists():
                     self.wvfs.makedirs()
                 self.vfs.makedir(notindexed=True)
-                requirements = self._baserequirements(create)
+                self.requirements.update(self._baserequirements(create))
                 if self.ui.configbool('format', 'usestore', True):
                     self.vfs.mkdir("store")
-                    requirements.append("store")
+                    self.requirements.add("store")
                     if self.ui.configbool('format', 'usefncache', True):
-                        requirements.append("fncache")
+                        self.requirements.add("fncache")
                         if self.ui.configbool('format', 'dotencode', True):
-                            requirements.append('dotencode')
+                            self.requirements.add('dotencode')
                     # create an invalid changelog
                     self.vfs.append(
                         "00changelog.i",
@@ -258,21 +259,22 @@
                         ' dummy changelog to prevent using the old repo layout'
                     )
                 if self.ui.configbool('format', 'generaldelta', False):
-                    requirements.append("generaldelta")
+                    self.requirements.add("generaldelta")
+                if self.ui.configbool('experimental', 'treemanifest', False):
+                    self.requirements.add("treemanifest")
                 if self.ui.configbool('experimental', 'manifestv2', False):
-                    requirements.append("manifestv2")
-                requirements = set(requirements)
+                    self.requirements.add("manifestv2")
             else:
                 raise error.RepoError(_("repository %s not found") % path)
         elif create:
             raise error.RepoError(_("repository %s already exists") % path)
         else:
             try:
-                requirements = scmutil.readrequires(self.vfs, self.supported)
+                self.requirements = scmutil.readrequires(
+                        self.vfs, self.supported)
             except IOError, inst:
                 if inst.errno != errno.ENOENT:
                     raise
-                requirements = set()
 
         self.sharedpath = self.path
         try:
@@ -287,13 +289,14 @@
             if inst.errno != errno.ENOENT:
                 raise
 
-        self.store = store.store(requirements, self.sharedpath, scmutil.vfs)
+        self.store = store.store(
+                self.requirements, self.sharedpath, scmutil.vfs)
         self.spath = self.store.path
         self.svfs = self.store.vfs
         self.sopener = self.svfs
         self.sjoin = self.store.join
         self.vfs.createmode = self.store.createmode
-        self._applyrequirements(requirements)
+        self._applyopenerreqs()
         if create:
             self._writerequirements()
 
@@ -336,9 +339,8 @@
             caps.add('bundle2=' + urllib.quote(capsblob))
         return caps
 
-    def _applyrequirements(self, requirements):
-        self.requirements = requirements
-        self.svfs.options = dict((r, 1) for r in requirements
+    def _applyopenerreqs(self):
+        self.svfs.options = dict((r, 1) for r in self.requirements
                                            if r in self.openerreqs)
         chunkcachesize = self.ui.configint('format', 'chunkcachesize')
         if chunkcachesize is not None:
@@ -349,15 +351,9 @@
         manifestcachesize = self.ui.configint('format', 'manifestcachesize')
         if manifestcachesize is not None:
             self.svfs.options['manifestcachesize'] = manifestcachesize
-        usetreemanifest = self.ui.configbool('experimental', 'treemanifest')
-        if usetreemanifest is not None:
-            self.svfs.options['usetreemanifest'] = usetreemanifest
 
     def _writerequirements(self):
-        reqfile = self.vfs("requires", "w")
-        for r in sorted(self.requirements):
-            reqfile.write("%s\n" % r)
-        reqfile.close()
+        scmutil.writerequires(self.vfs, self.requirements)
 
     def _checknested(self, path):
         """Determine if path is a legal nested repository."""
@@ -419,8 +415,8 @@
         return bookmarks.bmstore(self)
 
     @repofilecache('bookmarks.current')
-    def _bookmarkcurrent(self):
-        return bookmarks.readcurrent(self)
+    def _activebookmark(self):
+        return bookmarks.readactive(self)
 
     def bookmarkheads(self, bookmark):
         name = bookmark.split('@', 1)[0]
@@ -1754,7 +1750,7 @@
         """
         return util.hooks()
 
-    def stream_in(self, remote, requirements):
+    def stream_in(self, remote, remotereqs):
         lock = self.lock()
         try:
             # Save remote branchmap. We will use it later
@@ -1827,10 +1823,11 @@
                             util.bytecount(total_bytes / elapsed)))
 
             # new requirements = old non-format requirements +
-            #                    new format-related
+            #                    new format-related remote requirements
             # requirements from the streamed-in repository
-            requirements.update(set(self.requirements) - self.supportedformats)
-            self._applyrequirements(requirements)
+            self.requirements = remotereqs | (
+                    self.requirements - self.supportedformats)
+            self._applyopenerreqs()
             self._writerequirements()
 
             if rbranchmap:
--- a/mercurial/manifest.c	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/manifest.c	Sun May 10 14:45:13 2015 -0500
@@ -235,7 +235,7 @@
 	PyObject *ret = NULL, *path = NULL, *hash = NULL, *flags = NULL;
 	l = lmiter_nextline((lmIter *)o);
 	if (!l) {
-		goto bail;
+		goto done;
 	}
 	pl = pathlen(l);
 	path = PyString_FromStringAndSize(l->start, pl);
@@ -244,10 +244,10 @@
 	flags = PyString_FromStringAndSize(l->start + consumed,
 									   l->len - consumed - 1);
 	if (!path || !hash || !flags) {
-		goto bail;
+		goto done;
 	}
 	ret = PyTuple_Pack(3, path, hash, flags);
- bail:
+done:
 	Py_XDECREF(path);
 	Py_XDECREF(hash);
 	Py_XDECREF(flags);
@@ -672,7 +672,7 @@
 	copy->pydata = self->pydata;
 	Py_INCREF(copy->pydata);
 	return copy;
- nomem:
+nomem:
 	PyErr_NoMemory();
 	Py_XDECREF(copy);
 	return NULL;
@@ -724,7 +724,7 @@
 	}
 	copy->livelines = copy->numlines;
 	return copy;
- nomem:
+nomem:
 	PyErr_NoMemory();
 	Py_XDECREF(copy);
 	return NULL;
@@ -845,7 +845,7 @@
 	}
 	Py_DECREF(emptyTup);
 	return ret;
- nomem:
+nomem:
 	PyErr_NoMemory();
 	Py_XDECREF(ret);
 	Py_XDECREF(emptyTup);
--- a/mercurial/manifest.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/manifest.py	Sun May 10 14:45:13 2015 -0500
@@ -760,7 +760,7 @@
         opts = getattr(opener, 'options', None)
         if opts is not None:
             cachesize = opts.get('manifestcachesize', cachesize)
-            usetreemanifest = opts.get('usetreemanifest', usetreemanifest)
+            usetreemanifest = opts.get('treemanifest', usetreemanifest)
             usemanifestv2 = opts.get('manifestv2', usemanifestv2)
         self._mancache = util.lrucachedict(cachesize)
         revlog.revlog.__init__(self, opener, "00manifest.i")
@@ -793,7 +793,13 @@
         return self._newmanifest(d)
 
     def readfast(self, node):
-        '''use the faster of readdelta or read'''
+        '''use the faster of readdelta or read
+
+        This will return a manifest which is either only the files
+        added/modified relative to p1, or all files in the
+        manifest. Which one is returned depends on the codepath used
+        to retrieve the data.
+        '''
         r = self.rev(node)
         deltaparent = self.deltaparent(r)
         if deltaparent != revlog.nullrev and deltaparent in self.parentrevs(r):
--- a/mercurial/obsolete.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/obsolete.py	Sun May 10 14:45:13 2015 -0500
@@ -1110,13 +1110,17 @@
 @cachefor('unstable')
 def _computeunstableset(repo):
     """the set of non obsolete revisions with obsolete parents"""
-    # revset is not efficient enough here
-    # we do (obsolete()::) - obsolete() by hand
-    obs = getrevs(repo, 'obsolete')
-    if not obs:
-        return set()
-    cl = repo.changelog
-    return set(r for r in cl.descendants(obs) if r not in obs)
+    revs = [(ctx.rev(), ctx) for ctx in
+            repo.set('(not public()) and (not obsolete())')]
+    revs.sort(key=lambda x:x[0])
+    unstable = set()
+    for rev, ctx in revs:
+        # A rev is unstable if one of its parent is obsolete or unstable
+        # this works since we traverse following growing rev order
+        if util.any((x.obsolete() or (x.rev() in unstable))
+                for x in ctx.parents()):
+            unstable.add(rev)
+    return unstable
 
 @cachefor('suspended')
 def _computesuspendedset(repo):
@@ -1139,19 +1143,18 @@
     public = phases.public
     cl = repo.changelog
     torev = cl.nodemap.get
-    obs = getrevs(repo, 'obsolete')
-    for rev in repo:
+    for ctx in repo.set('(not public()) and (not obsolete())'):
+        rev = ctx.rev()
         # We only evaluate mutable, non-obsolete revision
-        if (public < phase(repo, rev)) and (rev not in obs):
-            node = cl.node(rev)
-            # (future) A cache of precursors may worth if split is very common
-            for pnode in allprecursors(repo.obsstore, [node],
-                                       ignoreflags=bumpedfix):
-                prev = torev(pnode) # unfiltered! but so is phasecache
-                if (prev is not None) and (phase(repo, prev) <= public):
-                    # we have a public precursors
-                    bumped.add(rev)
-                    break # Next draft!
+        node = ctx.node()
+        # (future) A cache of precursors may worth if split is very common
+        for pnode in allprecursors(repo.obsstore, [node],
+                                   ignoreflags=bumpedfix):
+            prev = torev(pnode) # unfiltered! but so is phasecache
+            if (prev is not None) and (phase(repo, prev) <= public):
+                # we have a public precursors
+                bumped.add(rev)
+                break # Next draft!
     return bumped
 
 @cachefor('divergent')
--- a/mercurial/revset.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/revset.py	Sun May 10 14:45:13 2015 -0500
@@ -25,23 +25,25 @@
     cl = repo.changelog
 
     def iterate():
-        revqueue, revsnode = None, None
+        revs.sort(reverse=True)
+        irevs = iter(revs)
         h = []
-
-        revs.sort(reverse=True)
-        revqueue = util.deque(revs)
-        if revqueue:
-            revsnode = revqueue.popleft()
-            heapq.heappush(h, -revsnode)
+        try:
+            inputrev = irevs.next()
+            heapq.heappush(h, -inputrev)
+        except StopIteration:
+            return
 
         seen = set()
         while h:
             current = -heapq.heappop(h)
+            if current == inputrev:
+                try:
+                    inputrev = irevs.next()
+                    heapq.heappush(h, -inputrev)
+                except StopIteration:
+                    pass
             if current not in seen:
-                if revsnode and current == revsnode:
-                    if revqueue:
-                        revsnode = revqueue.popleft()
-                        heapq.heappush(h, -revsnode)
                 seen.add(current)
                 yield current
                 for parent in cl.parentrevs(current)[:cut]:
@@ -334,11 +336,6 @@
         return baseset([x])
     return baseset()
 
-def symbolset(repo, subset, x):
-    if x in symbols:
-        raise error.ParseError(_("can't use %s here") % x)
-    return stringset(repo, subset, x)
-
 def rangeset(repo, subset, x, y):
     m = getset(repo, fullreposet(repo), x)
     n = getset(repo, fullreposet(repo), y)
@@ -1684,7 +1681,7 @@
     Changesets in set with no parent changeset in set.
     """
     s = getset(repo, fullreposet(repo), x)
-    subset = baseset([r for r in s if r in subset])
+    subset = subset & s# baseset([r for r in s if r in subset])
     cs = _children(repo, subset, s)
     return subset - cs
 
@@ -2088,7 +2085,7 @@
     "range": rangeset,
     "dagrange": dagrange,
     "string": stringset,
-    "symbol": symbolset,
+    "symbol": stringset,
     "and": andset,
     "or": orset,
     "not": notset,
@@ -3142,7 +3139,12 @@
                 self.__contains__ = self._desccontains
 
     def __nonzero__(self):
-        for r in self:
+        # Do not use 'for r in self' because it will enforce the iteration
+        # order (default ascending), possibly unrolling a whole descending
+        # iterator.
+        if self._genlist:
+            return True
+        for r in self._consumegen():
             return True
         return False
 
--- a/mercurial/scmutil.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/scmutil.py	Sun May 10 14:45:13 2015 -0500
@@ -1011,6 +1011,12 @@
                    " for more information"))
     return requirements
 
+def writerequires(opener, requirements):
+    reqfile = opener("requires", "w")
+    for r in sorted(requirements):
+        reqfile.write("%s\n" % r)
+    reqfile.close()
+
 class filecachesubentry(object):
     def __init__(self, path, stat):
         self.path = path
--- a/mercurial/subrepo.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/subrepo.py	Sun May 10 14:45:13 2015 -0500
@@ -1711,7 +1711,7 @@
         modified, added, removed = [], [], []
         self._gitupdatestat()
         if rev2:
-            command = ['diff-tree', rev1, rev2]
+            command = ['diff-tree', '-r', rev1, rev2]
         else:
             command = ['diff-index', rev1]
         out = self._gitcommand(command)
--- a/mercurial/templatekw.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/templatekw.py	Sun May 10 14:45:13 2015 -0500
@@ -210,7 +210,7 @@
     """
     repo = args['ctx']._repo
     bookmarks = args['ctx'].bookmarks()
-    current = repo._bookmarkcurrent
+    current = repo._activebookmark
     makemap = lambda v: {'bookmark': v, 'current': current}
     f = _showlist('bookmark', bookmarks, **args)
     return _hybrid(f, bookmarks, makemap, lambda x: x['bookmark'])
@@ -226,8 +226,8 @@
     associated with the changeset"""
     import bookmarks as bookmarks # to avoid circular import issues
     repo = args['repo']
-    if bookmarks.iscurrent(repo):
-        current = repo._bookmarkcurrent
+    if bookmarks.isactivewdirparent(repo):
+        current = repo._activebookmark
         if current in args['ctx'].bookmarks():
             return current
     return ''
--- a/mercurial/templater.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/templater.py	Sun May 10 14:45:13 2015 -0500
@@ -618,14 +618,25 @@
                 for j in _flatten(i):
                     yield j
 
-def parsestring(s, quoted=True):
-    '''unwrap quotes if quoted is True'''
-    if quoted:
-        if len(s) < 2 or s[0] != s[-1]:
-            raise SyntaxError(_('unmatched quotes'))
-        return s[1:-1]
-
-    return s
+def unquotestring(s):
+    '''unwrap quotes'''
+    if len(s) < 2 or s[0] != s[-1]:
+        raise SyntaxError(_('unmatched quotes'))
+    # de-backslash-ify only <\">. it is invalid syntax in non-string part of
+    # template, but we are likely to escape <"> in quoted string and it was
+    # accepted before, thanks to issue4290. <\\"> is unmodified because it
+    # is ambiguous and it was processed as such before 2.8.1.
+    #
+    #  template  result
+    #  --------- ------------------------
+    #  {\"\"}    parse error
+    #  "{""}"    {""} -> <>
+    #  "{\"\"}"  {""} -> <>
+    #  {"\""}    {"\""} -> <">
+    #  '{"\""}'  {"\""} -> <">
+    #  "{"\""}"  parse error (don't care)
+    q = s[0]
+    return s[1:-1].replace('\\\\' + q, '\\\\\\' + q).replace('\\' + q, q)
 
 class engine(object):
     '''template expansion engine.
@@ -717,7 +728,7 @@
                 raise SyntaxError(_('%s: missing value') % conf.source('', key))
             if val[0] in "'\"":
                 try:
-                    self.cache[key] = parsestring(val)
+                    self.cache[key] = unquotestring(val)
                 except SyntaxError, inst:
                     raise SyntaxError('%s: %s' %
                                       (conf.source('', key), inst.args[0]))
--- a/mercurial/templates/map-cmdline.phases	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/templates/map-cmdline.phases	Sun May 10 14:45:13 2015 -0500
@@ -1,73 +1,3 @@
-# Base templates. Due to name clashes with existing keywords, we have
-# to replace some keywords with 'lkeyword', for 'labelled keyword'
+%include map-cmdline.default
 changeset = '{cset}{branches}{bookmarks}{tags}{lphase}{parents}{user}{ldate}{summary}\n'
-changeset_quiet = '{lnode}'
 changeset_verbose = '{cset}{branches}{bookmarks}{tags}{lphase}{parents}{user}{ldate}{lfiles}{lfile_copies_switch}{description}\n'
-changeset_debug = '{fullcset}{branches}{bookmarks}{tags}{lphase}{parents}{manifest}{user}{ldate}{lfile_mods}{lfile_adds}{lfile_dels}{lfile_copies_switch}{extras}{description}\n'
-
-# File templates
-lfiles = '{if(files,
-               label("ui.note log.files",
-                     "files:       {files}\n"))}'
-
-lfile_mods = '{if(file_mods,
-                  label("ui.debug log.files",
-                        "files:       {file_mods}\n"))}'
-
-lfile_adds = '{if(file_adds,
-                  label("ui.debug log.files",
-                        "files+:      {file_adds}\n"))}'
-
-lfile_dels = '{if(file_dels,
-                  label("ui.debug log.files",
-                        "files-:      {file_dels}\n"))}'
-
-lfile_copies_switch = '{if(file_copies_switch,
-                           label("ui.note log.copies",
-                                 "copies:     {file_copies_switch
-                                               % ' {name} ({source})'}\n"))}'
-
-# General templates
-cset = '{label("log.changeset changeset.{phase}",
-               "changeset:   {rev}:{node|short}")}\n'
-
-lphase = '{label("log.phase",
-                 "phase:       {phase}")}\n'
-
-fullcset = '{label("log.changeset changeset.{phase}",
-                   "changeset:   {rev}:{node}")}\n'
-
-parent = '{label("log.parent changeset.{phase}",
-                  "parent:      {rev}:{node|formatnode}")}\n'
-
-lnode = '{label("log.node",
-                "{rev}:{node|short}")}\n'
-
-manifest = '{label("ui.debug log.manifest",
-                   "manifest:    {rev}:{node}")}\n'
-
-branch = '{label("log.branch",
-                 "branch:      {branch}")}\n'
-
-tag = '{label("log.tag",
-              "tag:         {tag}")}\n'
-
-bookmark = '{label("log.bookmark",
-                   "bookmark:    {bookmark}")}\n'
-
-user = '{label("log.user",
-               "user:        {author}")}\n'
-
-summary = '{if(desc|strip, "{label('log.summary',
-                                   'summary:     {desc|firstline}')}\n")}'
-
-ldate = '{label("log.date",
-                "date:        {date|date}")}\n'
-
-extra = '{label("ui.debug log.extra",
-                "extra:       {key}={value|stringescape}")}\n'
-
-description = '{if(desc|strip, "{label('ui.note log.description',
-                                       'description:')}
-                                {label('ui.note log.description',
-                                       '{desc|strip}')}\n\n")}'
--- a/mercurial/windows.py	Fri May 08 11:32:24 2015 -0700
+++ b/mercurial/windows.py	Sun May 10 14:45:13 2015 -0500
@@ -162,6 +162,18 @@
 _quotere = None
 _needsshellquote = None
 def shellquote(s):
+    r"""
+    >>> shellquote(r'C:\Users\xyz')
+    '"C:\\Users\\xyz"'
+    >>> shellquote(r'C:\Users\xyz/mixed')
+    '"C:\\Users\\xyz/mixed"'
+    >>> # Would be safe not to quote too, since it is all double backslashes
+    >>> shellquote(r'C:\\Users\\xyz')
+    '"C:\\\\Users\\\\xyz"'
+    >>> # But this must be quoted
+    >>> shellquote(r'C:\\Users\\xyz/abc')
+    '"C:\\\\Users\\\\xyz/abc"'
+    """
     global _quotere
     if _quotere is None:
         _quotere = re.compile(r'(\\*)("|\\$)')
--- a/setup.py	Fri May 08 11:32:24 2015 -0700
+++ b/setup.py	Sun May 10 14:45:13 2015 -0500
@@ -408,11 +408,12 @@
                 # Persist executable bit (apply it to group and other if user
                 # has it)
                 if st[stat.ST_MODE] & stat.S_IXUSR:
-                    setmode = 0755
+                    setmode = int('0755', 8)
                 else:
-                    setmode = 0644
-                os.chmod(dst, (stat.S_IMODE(st[stat.ST_MODE]) & ~0777) |
-                         setmode)
+                    setmode = int('0644', 8)
+                m = stat.S_IMODE(st[stat.ST_MODE])
+                m = (m & ~int('0777', 8)) | setmode
+                os.chmod(dst, m)
         file_util.copy_file = copyfileandsetmode
         try:
             install_lib.run(self)
--- a/tests/run-tests.py	Fri May 08 11:32:24 2015 -0700
+++ b/tests/run-tests.py	Sun May 10 14:45:13 2015 -0500
@@ -49,6 +49,7 @@
 import shutil
 import subprocess
 import signal
+import socket
 import sys
 import tempfile
 import time
@@ -78,6 +79,18 @@
 
 wifexited = getattr(os, "WIFEXITED", lambda x: False)
 
+def checkportisavailable(port):
+    """return true if a port seems free to bind on localhost"""
+    try:
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        s.bind(('localhost', port))
+        s.close()
+        return True
+    except socket.error, exc:
+        if not exc.errno == errno.EADDRINUSE:
+            raise
+        return False
+
 closefds = os.name == 'posix'
 def Popen4(cmd, wd, timeout, env=None):
     processlock.acquire()
@@ -442,6 +455,11 @@
         else:
             self._refout = []
 
+    # needed to get base class __repr__ running
+    @property
+    def _testMethodName(self):
+        return self.name
+
     def __str__(self):
         return self.name
 
@@ -620,7 +638,7 @@
                 f.write(line)
             f.close()
 
-        vlog("# Ret was:", self._ret)
+        vlog("# Ret was:", self._ret, '(%s)' % self.name)
 
     def _run(self, env):
         # This should be implemented in child classes to run tests.
@@ -1290,8 +1308,11 @@
 
         starttime = test.started
         endtime = test.stopped
-        self.times.append((test.name, endtime[2] - starttime[2],
-                    endtime[3] - starttime[3], endtime[4] - starttime[4]))
+        self.times.append((test.name,
+                           endtime[2] - starttime[2], # user space CPU time
+                           endtime[3] - starttime[3], # sys  space CPU time
+                           endtime[4] - starttime[4], # real time
+                           ))
 
         if interrupted:
             iolock.acquire()
@@ -1476,8 +1497,7 @@
         if self._runner.options.xunit:
             xuf = open(self._runner.options.xunit, 'wb')
             try:
-                timesd = dict(
-                    (test, real) for test, cuser, csys, real in result.times)
+                timesd = dict((t[0], t[3]) for t in result.times)
                 doc = minidom.Document()
                 s = doc.createElement('testsuite')
                 s.setAttribute('name', 'run-tests')
@@ -1513,30 +1533,21 @@
             fp = open(jsonpath, 'w')
             try:
                 timesd = {}
-                for test, cuser, csys, real in result.times:
-                    timesd[test] = (real, cuser, csys)
+                for tdata in result.times:
+                    test = tdata[0]
+                    timesd[test] = tdata[1:]
 
                 outcome = {}
-                for tc in result.successes:
-                    testresult = {'result': 'success',
-                                  'time': ('%0.3f' % timesd[tc.name][0]),
-                                  'cuser': ('%0.3f' % timesd[tc.name][1]),
-                                  'csys': ('%0.3f' % timesd[tc.name][2])}
-                    outcome[tc.name] = testresult
-
-                for tc, err in sorted(result.faildata.iteritems()):
-                    testresult = {'result': 'failure',
-                                  'time': ('%0.3f' % timesd[tc][0]),
-                                  'cuser': ('%0.3f' % timesd[tc][1]),
-                                  'csys': ('%0.3f' % timesd[tc][2])}
-                    outcome[tc] = testresult
-
-                for tc, reason in result.skipped:
-                    testresult = {'result': 'skip',
-                                  'time': ('%0.3f' % timesd[tc.name][0]),
-                                  'cuser': ('%0.3f' % timesd[tc.name][1]),
-                                  'csys': ('%0.3f' % timesd[tc.name][2])}
-                    outcome[tc.name] = testresult
+                groups = [('success', ((tc, None) for tc in result.successes)),
+                          ('failure', result.failures),
+                          ('skip', result.skipped)]
+                for res, testcases in groups:
+                    for tc, __ in testcases:
+                        testresult = {'result': res,
+                                      'time': ('%0.3f' % timesd[tc.name][2]),
+                                      'cuser': ('%0.3f' % timesd[tc.name][0]),
+                                      'csys': ('%0.3f' % timesd[tc.name][1])}
+                        outcome[tc.name] = testresult
 
                 jsonout = json.dumps(outcome, sort_keys=True, indent=4)
                 fp.writelines(("testreport =", jsonout))
@@ -1565,7 +1576,9 @@
         cols = '%7.3f %7.3f %7.3f   %s'
         self.stream.writeln('%-7s %-7s %-7s   %s' % ('cuser', 'csys', 'real',
                     'Test'))
-        for test, cuser, csys, real in times:
+        for tdata in times:
+            test = tdata[0]
+            cuser, csys, real = tdata[1:4]
             self.stream.writeln(cols % (cuser, csys, real, test))
 
 class TestRunner(object):
@@ -1603,6 +1616,8 @@
         self._coveragefile = None
         self._createdfiles = []
         self._hgpath = None
+        self._portoffset = 0
+        self._ports = {}
 
     def run(self, args, parser=None):
         """Run the test suite."""
@@ -1807,6 +1822,24 @@
         if warned:
             return 80
 
+    def _getport(self, count):
+        port = self._ports.get(count) # do we have a cached entry?
+        if port is None:
+            port = self.options.port + self._portoffset
+            portneeded = 3
+            # above 100 tries we just give up and let test reports failure
+            for tries in xrange(100):
+                allfree = True
+                for idx in xrange(portneeded):
+                    if not checkportisavailable(port + idx):
+                        allfree = False
+                        break
+                self._portoffset += portneeded
+                if allfree:
+                    break
+            self._ports[count] = port
+        return port
+
     def _gettest(self, test, count):
         """Obtain a Test by looking at its filename.
 
@@ -1828,7 +1861,7 @@
                     keeptmpdir=self.options.keep_tmpdir,
                     debug=self.options.debug,
                     timeout=self.options.timeout,
-                    startport=self.options.port + count * 3,
+                    startport=self._getport(count),
                     extraconfigopts=self.options.extra_config_opt,
                     py3kwarnings=self.options.py3k_warnings,
                     shell=self.options.shell)
--- a/tests/test-command-template.t	Fri May 08 11:32:24 2015 -0700
+++ b/tests/test-command-template.t	Sun May 10 14:45:13 2015 -0500
@@ -95,7 +95,7 @@
   8
 
 Add a commit with empty description, to ensure that the templates
-following below omit it properly.
+below will omit the description line.
 
   $ echo c >> c
   $ hg add c
@@ -108,32 +108,52 @@
   $ hg log --style default > style.out
   $ cmp log.out style.out || diff -u log.out style.out
   $ hg log -T phases > phases.out
-  $ diff -u log.out phases.out | grep "phase:"
+  $ diff -U 0 log.out phases.out | grep -v '^---\|^+++'
+  @@ -2,0 +3 @@
   +phase:       draft
+  @@ -6,0 +8 @@
   +phase:       draft
+  @@ -11,0 +14 @@
   +phase:       draft
+  @@ -17,0 +21 @@
   +phase:       draft
+  @@ -24,0 +29 @@
   +phase:       draft
+  @@ -31,0 +37 @@
   +phase:       draft
+  @@ -36,0 +43 @@
   +phase:       draft
+  @@ -41,0 +49 @@
   +phase:       draft
+  @@ -46,0 +55 @@
   +phase:       draft
+  @@ -51,0 +61 @@
   +phase:       draft
 
   $ hg log -v > log.out
   $ hg log -v --style default > style.out
   $ cmp log.out style.out || diff -u log.out style.out
   $ hg log -v -T phases > phases.out
-  $ diff -u log.out phases.out | grep phase:
+  $ diff -U 0 log.out phases.out | grep -v '^---\|^+++'
+  @@ -2,0 +3 @@
   +phase:       draft
+  @@ -7,0 +9 @@
   +phase:       draft
+  @@ -15,0 +18 @@
   +phase:       draft
+  @@ -24,0 +28 @@
   +phase:       draft
+  @@ -33,0 +38 @@
   +phase:       draft
+  @@ -43,0 +49 @@
   +phase:       draft
+  @@ -50,0 +57 @@
   +phase:       draft
+  @@ -58,0 +66 @@
   +phase:       draft
+  @@ -66,0 +75 @@
   +phase:       draft
+  @@ -77,0 +87 @@
   +phase:       draft
 
   $ hg log -q > log.out
@@ -160,32 +180,52 @@
   $ hg --color=debug log --style default > style.out
   $ cmp log.out style.out || diff -u log.out style.out
   $ hg --color=debug log -T phases > phases.out
-  $ diff -u log.out phases.out | grep phase:
+  $ diff -U 0 log.out phases.out | grep -v '^---\|^+++'
+  @@ -2,0 +3 @@
   +[log.phase|phase:       draft]
+  @@ -6,0 +8 @@
   +[log.phase|phase:       draft]
+  @@ -11,0 +14 @@
   +[log.phase|phase:       draft]
+  @@ -17,0 +21 @@
   +[log.phase|phase:       draft]
+  @@ -24,0 +29 @@
   +[log.phase|phase:       draft]
+  @@ -31,0 +37 @@
   +[log.phase|phase:       draft]
+  @@ -36,0 +43 @@
   +[log.phase|phase:       draft]
+  @@ -41,0 +49 @@
   +[log.phase|phase:       draft]
+  @@ -46,0 +55 @@
   +[log.phase|phase:       draft]
+  @@ -51,0 +61 @@
   +[log.phase|phase:       draft]
 
   $ hg --color=debug -v log > log.out
   $ hg --color=debug -v log --style default > style.out
   $ cmp log.out style.out || diff -u log.out style.out
   $ hg --color=debug -v log -T phases > phases.out
-  $ diff -u log.out phases.out | grep phase:
+  $ diff -U 0 log.out phases.out | grep -v '^---\|^+++'
+  @@ -2,0 +3 @@
   +[log.phase|phase:       draft]
+  @@ -7,0 +9 @@
   +[log.phase|phase:       draft]
+  @@ -15,0 +18 @@
   +[log.phase|phase:       draft]
+  @@ -24,0 +28 @@
   +[log.phase|phase:       draft]
+  @@ -33,0 +38 @@
   +[log.phase|phase:       draft]
+  @@ -43,0 +49 @@
   +[log.phase|phase:       draft]
+  @@ -50,0 +57 @@
   +[log.phase|phase:       draft]
+  @@ -58,0 +66 @@
   +[log.phase|phase:       draft]
+  @@ -66,0 +75 @@
   +[log.phase|phase:       draft]
+  @@ -77,0 +87 @@
   +[log.phase|phase:       draft]
 
   $ hg --color=debug -q log > log.out
@@ -1953,6 +1993,15 @@
   abort: template filter 'upper' is not compatible with keyword 'date'
   [255]
 
+Add a commit that does all possible modifications at once
+
+  $ echo modify >> third
+  $ touch b
+  $ hg add b
+  $ hg mv fourth fifth
+  $ hg rm a
+  $ hg ci -m "Modify, add, remove, rename"
+
 Error on syntax:
 
   $ echo 'x = "f' >> t
@@ -2273,6 +2322,25 @@
   <>\n<]>
   <>\n<
 
+Test exception in quoted template. single backslash before quotation mark is
+stripped before parsing:
+
+  $ cat <<'EOF' > escquotetmpl
+  > changeset = "\" \\" \\\" \\\\" {files % \"{file}\"}\n"
+  > EOF
+  $ cd latesttag
+  $ hg log -r 2 --style ../escquotetmpl
+  " \" \" \\" head1
+
+  $ hg log -r 2 -T esc --config templates.esc='{\"invalid\"}\n'
+  hg: parse error at 1: syntax error
+  [255]
+  $ hg log -r 2 -T esc --config templates.esc='"{\"valid\"}\n"'
+  valid
+  $ hg log -r 2 -T esc --config templates.esc="'"'{\'"'"'valid\'"'"'}\n'"'"
+  valid
+  $ cd ..
+
 Test leading backslashes:
 
   $ cd latesttag
@@ -2547,7 +2615,9 @@
 Test splitlines
 
   $ hg log -Gv -R a --template "{splitlines(desc) % 'foo {line}\n'}"
-  @  foo future
+  @  foo Modify, add, remove, rename
+  |
+  o  foo future
   |
   o  foo third
   |
@@ -2581,6 +2651,8 @@
   o
   |
   o
+  |
+  o
   
   o
   |\
@@ -2606,7 +2678,9 @@
 Test word function (including index out of bounds graceful failure)
 
   $ hg log -Gv -R a --template "{word('1', desc)}"
-  @
+  @  add,
+  |
+  o
   |
   o
   |
@@ -2630,7 +2704,9 @@
 Test word third parameter used as splitter
 
   $ hg log -Gv -R a --template "{word('0', desc, 'o')}"
-  @  future
+  @  M
+  |
+  o  future
   |
   o  third
   |
--- a/tests/test-manifestv2.t	Fri May 08 11:32:24 2015 -0700
+++ b/tests/test-manifestv2.t	Sun May 10 14:45:13 2015 -0500
@@ -1,4 +1,69 @@
-Check that entry is added to .hg/requires
+Create repo with old manifest
+
+  $ hg init existing
+  $ cd existing
+  $ echo footext > foo
+  $ hg add foo
+  $ hg commit -m initial
+
+We're using v1, so no manifestv2 entry is in requires yet.
+
+  $ grep manifestv2 .hg/requires
+  [1]
+
+Let's clone this with manifestv2 enabled to switch to the new format for
+future commits.
+
+  $ cd ..
+  $ hg clone --pull existing new --config experimental.manifestv2=1
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  $ cd new
+
+Check that entry was added to .hg/requires.
+
+  $ grep manifestv2 .hg/requires
+  manifestv2
+
+Make a new commit.
+
+  $ echo newfootext > foo
+  $ hg commit -m new
+
+Check that the manifest actually switched to v2.
+
+  $ hg debugdata -m 0
+  foo\x0021e958b1dca695a60ee2e9cf151753204ee0f9e9 (esc)
+
+  $ hg debugdata -m 1
+  \x00 (esc)
+  \x00foo\x00 (esc)
+  I\xab\x7f\xb8(\x83\xcas\x15\x9d\xc2\xd3\xd3:5\x08\xbad5_ (esc)
+
+Check that manifestv2 is used if the requirement is present, even if it's
+disabled in the config.
+
+  $ echo newerfootext > foo
+  $ hg --config experimental.manifestv2=False commit -m newer
+
+  $ hg debugdata -m 2
+  \x00 (esc)
+  \x00foo\x00 (esc)
+  \xa6\xb1\xfb\xef]\x91\xa1\x19`\xf3.#\x90S\xf8\x06 \xe2\x19\x00 (esc)
+
+Check that we can still read v1 manifests.
+
+  $ hg files -r 0
+  foo
+
+  $ cd ..
+
+Check that entry is added to .hg/requires on repo creation
 
   $ hg --config experimental.manifestv2=True init repo
   $ cd repo
--- a/tests/test-module-imports.t	Fri May 08 11:32:24 2015 -0700
+++ b/tests/test-module-imports.t	Sun May 10 14:45:13 2015 -0500
@@ -21,9 +21,6 @@
 these may expose other cycles.
 
   $ hg locate 'mercurial/**.py' | sed 's-\\-/-g' | xargs python "$import_checker"
-  mercurial/crecord.py mixed imports
-     stdlib:    fcntl, termios
-     relative:  curses
   mercurial/dispatch.py mixed imports
      stdlib:    commands
      relative:  error, extensions, fancyopts, hg, hook, util
--- a/tests/test-revset.t	Fri May 08 11:32:24 2015 -0700
+++ b/tests/test-revset.t	Sun May 10 14:45:13 2015 -0500
@@ -1,5 +1,27 @@
   $ HGENCODING=utf-8
   $ export HGENCODING
+  $ cat > testrevset.py << EOF
+  > import mercurial.revset
+  > 
+  > baseset = mercurial.revset.baseset
+  > 
+  > def r3232(repo, subset, x):
+  >     """"simple revset that return [3,2,3,2]
+  > 
+  >     revisions duplicated on purpose.
+  >     """
+  >     if 3 not in subset:
+  >        if 2 in subset:
+  >            return baseset([2,2])
+  >        return baseset()
+  >     return baseset([3,3,2,2])
+  > 
+  > mercurial.revset.symbols['r3232'] = r3232
+  > EOF
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > testrevset=$TESTTMP/testrevset.py
+  > EOF
 
   $ try() {
   >   hg debugrevspec --debug "$@"
@@ -281,7 +303,7 @@
   hg: parse error: date requires a string
   [255]
   $ log 'date'
-  hg: parse error: can't use date here
+  abort: unknown revision 'date'!
   [255]
   $ log 'date('
   hg: parse error at 5: not a prefix: end
@@ -289,11 +311,40 @@
   $ log 'date(tip)'
   abort: invalid date: 'tip'
   [255]
-  $ log '"date"'
+  $ log '0:date'
+  abort: unknown revision 'date'!
+  [255]
+  $ log '::"date"'
   abort: unknown revision 'date'!
   [255]
+  $ hg book date -r 4
+  $ log '0:date'
+  0
+  1
+  2
+  3
+  4
+  $ log '::date'
+  0
+  1
+  2
+  4
+  $ log '::"date"'
+  0
+  1
+  2
+  4
   $ log 'date(2005) and 1::'
   4
+  $ hg book -d date
+
+Test that symbols only get parsed as functions if there's an opening
+parenthesis.
+
+  $ hg book only -r 9
+  $ log 'only(only)'   # Outer "only" is a function, inner "only" is the bookmark
+  8
+  9
 
 ancestor can accept 0 or more arguments
 
@@ -311,6 +362,9 @@
   0
   $ log 'ancestor(1,2,3,4,5)'
   1
+
+test ancestors
+
   $ log 'ancestors(5)'
   0
   1
@@ -318,6 +372,12 @@
   5
   $ log 'ancestor(ancestors(5))'
   0
+  $ log '::r3232()'
+  0
+  1
+  2
+  3
+
   $ log 'author(bob)'
   2
   $ log 'author("re:bob|test")'
--- a/tests/test-run-tests.t	Fri May 08 11:32:24 2015 -0700
+++ b/tests/test-run-tests.t	Sun May 10 14:45:13 2015 -0500
@@ -497,6 +497,46 @@
       }
   } (no-eol)
 
+Test that failed test accepted through interactive are properly reported:
+
+  $ cp test-failure.t backup
+  $ echo y | $TESTDIR/run-tests.py --with-hg=`which hg` --json -i
+  
+  --- $TESTTMP/test-failure.t
+  +++ $TESTTMP/test-failure.t.err
+  @@ -1,4 +1,4 @@
+     $ echo babar
+  -  rataxes
+  +  babar
+   This is a noop statement so that
+   this test is still more bytes than success.
+  Accept this change? [n] ..s
+  Skipped test-skip.t: skipped
+  # Ran 2 tests, 1 skipped, 0 warned, 0 failed.
+
+  $ cat report.json
+  testreport ={
+      "test-failure.t": [\{] (re)
+          "csys": "\s*[\d\.]{4,5}", ? (re)
+          "cuser": "\s*[\d\.]{4,5}", ? (re)
+          "result": "success", ? (re)
+          "time": "\s*[\d\.]{4,5}" (re)
+      }, ? (re)
+      "test-skip.t": {
+          "csys": "\s*[\d\.]{4,5}", ? (re)
+          "cuser": "\s*[\d\.]{4,5}", ? (re)
+          "result": "skip", ? (re)
+          "time": "\s*[\d\.]{4,5}" (re)
+      }, ? (re)
+      "test-success.t": [\{] (re)
+          "csys": "\s*[\d\.]{4,5}", ? (re)
+          "cuser": "\s*[\d\.]{4,5}", ? (re)
+          "result": "success", ? (re)
+          "time": "\s*[\d\.]{4,5}" (re)
+      }
+  } (no-eol)
+  $ mv backup test-failure.t
+
 #endif
 
 backslash on end of line with glob matching is handled properly
--- a/tests/test-subrepo-deep-nested-change.t	Fri May 08 11:32:24 2015 -0700
+++ b/tests/test-subrepo-deep-nested-change.t	Sun May 10 14:45:13 2015 -0500
@@ -309,17 +309,17 @@
 
 Exclude normal files from main and sub-sub repo
 
-  $ hg --config extensions.largefiles= archive -S -X '**.txt' ../archive_lf.tgz
+  $ hg --config extensions.largefiles= archive -S -X '**.txt' -p '.' ../archive_lf.tgz
   $ tar -tzf ../archive_lf.tgz | sort
-  archive_lf/.hgsub
-  archive_lf/.hgsubstate
-  archive_lf/large.bin
-  archive_lf/main
-  archive_lf/sub1/.hgsub
-  archive_lf/sub1/.hgsubstate
-  archive_lf/sub1/sub1
-  archive_lf/sub1/sub2/large.bin
-  archive_lf/sub1/sub2/sub2
+  .hgsub
+  .hgsubstate
+  large.bin
+  main
+  sub1/.hgsub
+  sub1/.hgsubstate
+  sub1/sub1
+  sub1/sub2/large.bin
+  sub1/sub2/sub2
 
 Include normal files from within a largefiles subrepo
 
--- a/tests/test-subrepo-git.t	Fri May 08 11:32:24 2015 -0700
+++ b/tests/test-subrepo-git.t	Sun May 10 14:45:13 2015 -0500
@@ -325,13 +325,13 @@
   ../archive_x/s
   ../archive_x/s/g
 
-  $ hg -R ../tc archive -S ../archive.tgz 2>/dev/null
-  $ tar -tzf ../archive.tgz | sort
-  archive/.hg_archival.txt
-  archive/.hgsub
-  archive/.hgsubstate
-  archive/a
-  archive/s/g
+  $ hg -R ../tc archive -S ../archive.tgz --prefix '.' 2>/dev/null
+  $ tar -tzf ../archive.tgz | sort | grep -v pax_global_header
+  .hg_archival.txt
+  .hgsub
+  .hgsubstate
+  a
+  s/g
 
 create nested repo
 
@@ -1105,5 +1105,21 @@
   ? s/c.c
   ? s/cpp.cpp
   ? s/foobar.orig
+  $ hg revert --all -q
+
+make sure we show changed files, rather than changed subtrees
+  $ mkdir s/foo
+  $ touch s/foo/bwuh
+  $ hg add s/foo/bwuh
+  $ hg commit -S -m "add bwuh"
+  committing subrepository s
+  $ hg status -S --change .
+  M .hgsubstate
+  A s/foo/bwuh
+  ? s/barfoo
+  ? s/c.c
+  ? s/cpp.cpp
+  ? s/foobar.orig
+  ? s/snake.python.orig
 
   $ cd ..
--- a/tests/test-subrepo-recursion.t	Fri May 08 11:32:24 2015 -0700
+++ b/tests/test-subrepo-recursion.t	Sun May 10 14:45:13 2015 -0500
@@ -312,7 +312,7 @@
 
 Test archiving to zip file (unzip output is unstable):
 
-  $ hg archive --subrepos ../archive.zip
+  $ hg archive --subrepos --prefix '.' ../archive.zip
   \r (no-eol) (esc)
   archiving [                                           ] 0/3\r (no-eol) (esc)
   archiving [                                           ] 0/3\r (no-eol) (esc)
@@ -340,6 +340,23 @@
   archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
                                                               \r (no-eol) (esc)
 
+(unzip date formating is unstable, we do not care about it and glob it out)
+
+  $ unzip -l ../archive.zip
+  Archive:  ../archive.zip
+    Length      Date    Time    Name
+  ---------  ---------- -----   ----
+        172  ?????????? 00:00   .hg_archival.txt (glob)
+         10  ?????????? 00:00   .hgsub (glob)
+         45  ?????????? 00:00   .hgsubstate (glob)
+          3  ?????????? 00:00   x.txt (glob)
+         10  ?????????? 00:00   foo/.hgsub (glob)
+         45  ?????????? 00:00   foo/.hgsubstate (glob)
+          9  ?????????? 00:00   foo/y.txt (glob)
+          9  ?????????? 00:00   foo/bar/z.txt (glob)
+  ---------                     -------
+        303                     8 files
+
 Test archiving a revision that references a subrepo that is not yet
 cloned:
 
@@ -363,7 +380,7 @@
 
   $ cd ../empty
 #if hardlink
-  $ hg archive --subrepos -r tip ../archive.tar.gz
+  $ hg archive --subrepos -r tip --prefix './' ../archive.tar.gz
   \r (no-eol) (esc)
   archiving [                                           ] 0/3\r (no-eol) (esc)
   archiving [                                           ] 0/3\r (no-eol) (esc)
@@ -413,7 +430,7 @@
 #else
 Note there's a slight output glitch on non-hardlink systems: the last
 "linking" progress topic never gets closed, leading to slight output corruption on that platform.
-  $ hg archive --subrepos -r tip ../archive.tar.gz
+  $ hg archive --subrepos -r tip --prefix './' ../archive.tar.gz
   \r (no-eol) (esc)
   archiving [                                           ] 0/3\r (no-eol) (esc)
   archiving [                                           ] 0/3\r (no-eol) (esc)
@@ -437,14 +454,14 @@
 Archive + subrepos uses '/' for all component separators
 
   $ tar -tzf ../archive.tar.gz | sort
-  archive/.hg_archival.txt
-  archive/.hgsub
-  archive/.hgsubstate
-  archive/foo/.hgsub
-  archive/foo/.hgsubstate
-  archive/foo/bar/z.txt
-  archive/foo/y.txt
-  archive/x.txt
+  .hg_archival.txt
+  .hgsub
+  .hgsubstate
+  foo/.hgsub
+  foo/.hgsubstate
+  foo/bar/z.txt
+  foo/y.txt
+  x.txt
 
 The newly cloned subrepos contain no working copy: